@zhin.js/core 1.0.16 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/REFACTORING_COMPLETE.md +178 -0
- package/REFACTORING_STATUS.md +263 -0
- package/lib/adapter.d.ts +44 -19
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +81 -50
- package/lib/adapter.js.map +1 -1
- package/lib/bot.d.ts +7 -12
- package/lib/bot.d.ts.map +1 -1
- package/lib/built/adapter-process.d.ts +36 -0
- package/lib/built/adapter-process.d.ts.map +1 -0
- package/lib/built/adapter-process.js +77 -0
- package/lib/built/adapter-process.js.map +1 -0
- package/lib/built/command.d.ts +46 -0
- package/lib/built/command.d.ts.map +1 -0
- package/lib/built/command.js +54 -0
- package/lib/built/command.js.map +1 -0
- package/lib/built/component.d.ts +42 -0
- package/lib/built/component.d.ts.map +1 -0
- package/lib/built/component.js +66 -0
- package/lib/built/component.js.map +1 -0
- package/lib/built/config.d.ts +31 -0
- package/lib/built/config.d.ts.map +1 -0
- package/lib/built/config.js +141 -0
- package/lib/built/config.js.map +1 -0
- package/lib/built/cron.d.ts +53 -0
- package/lib/built/cron.d.ts.map +1 -0
- package/lib/built/cron.js +79 -0
- package/lib/built/cron.js.map +1 -0
- package/lib/built/database.d.ts +17 -0
- package/lib/built/database.d.ts.map +1 -0
- package/lib/built/database.js +28 -0
- package/lib/built/database.js.map +1 -0
- package/lib/{permissions.d.ts → built/permission.d.ts} +5 -10
- package/lib/built/permission.d.ts.map +1 -0
- package/lib/{permissions.js → built/permission.js} +11 -10
- package/lib/built/permission.js.map +1 -0
- package/lib/command.d.ts +18 -7
- package/lib/command.d.ts.map +1 -1
- package/lib/command.js +36 -15
- package/lib/command.js.map +1 -1
- package/lib/component.d.ts +1 -1
- package/lib/component.d.ts.map +1 -1
- package/lib/component.js.map +1 -1
- package/lib/cron.d.ts +4 -12
- package/lib/cron.d.ts.map +1 -1
- package/lib/cron.js +33 -64
- package/lib/cron.js.map +1 -1
- package/lib/index.d.ts +11 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +14 -4
- package/lib/index.js.map +1 -1
- package/lib/jsx-runtime.d.ts +2 -2
- package/lib/jsx.d.ts +2 -3
- package/lib/jsx.d.ts.map +1 -1
- package/lib/jsx.js.map +1 -1
- package/lib/message.d.ts +4 -7
- package/lib/message.d.ts.map +1 -1
- package/lib/message.js.map +1 -1
- package/lib/plugin.d.ts +164 -51
- package/lib/plugin.d.ts.map +1 -1
- package/lib/plugin.js +520 -137
- package/lib/plugin.js.map +1 -1
- package/lib/prompt.d.ts +1 -1
- package/lib/prompt.d.ts.map +1 -1
- package/lib/prompt.js +2 -1
- package/lib/prompt.js.map +1 -1
- package/lib/types.d.ts +33 -33
- package/lib/types.d.ts.map +1 -1
- package/lib/utils.d.ts +16 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +166 -66
- package/lib/utils.js.map +1 -1
- package/package.json +17 -11
- package/src/adapter.ts +131 -80
- package/src/bot.ts +8 -13
- package/src/built/adapter-process.ts +77 -0
- package/src/built/command.ts +102 -0
- package/src/built/component.ts +111 -0
- package/src/built/config.ts +126 -0
- package/src/built/cron.ts +140 -0
- package/src/built/database.ts +38 -0
- package/src/{permissions.ts → built/permission.ts} +9 -12
- package/src/command.ts +48 -20
- package/src/component.ts +2 -3
- package/src/cron.ts +35 -70
- package/src/index.ts +15 -5
- package/src/jsx.ts +2 -3
- package/src/message.ts +3 -4
- package/src/plugin.ts +671 -184
- package/src/prompt.ts +4 -3
- package/src/types.ts +41 -35
- package/src/utils.ts +418 -296
- package/test/minimal-bot.ts +31 -0
- package/test/stress-test.ts +123 -0
- package/tests/command.test.ts +124 -44
- package/ASYNC-JSX-SUPPORT.md +0 -173
- package/lib/app.d.ts +0 -191
- package/lib/app.d.ts.map +0 -1
- package/lib/app.js +0 -604
- package/lib/app.js.map +0 -1
- package/lib/config.d.ts +0 -54
- package/lib/config.d.ts.map +0 -1
- package/lib/config.js +0 -308
- package/lib/config.js.map +0 -1
- package/lib/log-transport.d.ts +0 -37
- package/lib/log-transport.d.ts.map +0 -1
- package/lib/log-transport.js +0 -136
- package/lib/log-transport.js.map +0 -1
- package/lib/permissions.d.ts.map +0 -1
- package/lib/permissions.js.map +0 -1
- package/src/app.ts +0 -772
- package/src/config.ts +0 -397
- package/src/log-transport.ts +0 -163
- package/tests/app.test.ts +0 -265
- package/tests/permissions.test.ts +0 -358
- package/tests/plugin.test.ts +0 -234
- package/tests/prompt.test.ts +0 -223
package/tests/app.test.ts
DELETED
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
2
|
-
import { App, createApp } from '../src/app'
|
|
3
|
-
import { LogLevel } from '@zhin.js/logger'
|
|
4
|
-
import path from 'path'
|
|
5
|
-
import fs from 'fs'
|
|
6
|
-
|
|
7
|
-
describe('App核心功能测试', () => {
|
|
8
|
-
let app: App
|
|
9
|
-
let testDir: string
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
testDir = path.join(process.cwd(), 'test-app')
|
|
13
|
-
if (!fs.existsSync(testDir)) {
|
|
14
|
-
fs.mkdirSync(testDir, { recursive: true })
|
|
15
|
-
}
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
afterEach(async () => {
|
|
19
|
-
if (app) {
|
|
20
|
-
await app.stop()
|
|
21
|
-
}
|
|
22
|
-
if (fs.existsSync(testDir)) {
|
|
23
|
-
fs.rmSync(testDir, { recursive: true, force: true })
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe('App实例化', () => {
|
|
28
|
-
it('应该使用默认配置创建App', () => {
|
|
29
|
-
app = new App()
|
|
30
|
-
expect(app).toBeInstanceOf(App)
|
|
31
|
-
expect(app.getConfig()).toEqual(App.defaultConfig)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('应该使用自定义配置创建App', () => {
|
|
35
|
-
const config = {
|
|
36
|
-
log_level: LogLevel.DEBUG,
|
|
37
|
-
plugin_dirs: ['./custom-plugins'],
|
|
38
|
-
plugins: ['test-plugin'],
|
|
39
|
-
bots: [{ name: 'test-bot', context: 'process' }],
|
|
40
|
-
debug: true
|
|
41
|
-
}
|
|
42
|
-
app = new App(config)
|
|
43
|
-
expect(app.getConfig()).toMatchObject(config)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it('应该通过createApp工厂函数创建App', async () => {
|
|
47
|
-
app = await createApp()
|
|
48
|
-
expect(app).toBeInstanceOf(App)
|
|
49
|
-
expect(app.getConfig()).toBeDefined()
|
|
50
|
-
expect(app.getConfig().log_level).toBeDefined()
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
describe('配置管理', () => {
|
|
55
|
-
beforeEach(() => {
|
|
56
|
-
app = new App({
|
|
57
|
-
log_level: LogLevel.INFO,
|
|
58
|
-
plugin_dirs: [],
|
|
59
|
-
plugins: [],
|
|
60
|
-
bots: [],
|
|
61
|
-
debug: false
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('应该正确获取配置', () => {
|
|
66
|
-
const config = app.getConfig()
|
|
67
|
-
expect(config.log_level).toBe(LogLevel.INFO)
|
|
68
|
-
// debug 在实际运行中可能是 true,接受实际值
|
|
69
|
-
expect(typeof config.debug).toBe('boolean')
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('应该正确获取嵌套配置', () => {
|
|
73
|
-
const logLevel = app.getConfig('log_level' as any)
|
|
74
|
-
expect(logLevel).toBe(LogLevel.INFO)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('应该正确设置配置', () => {
|
|
78
|
-
app.setConfig('debug', true)
|
|
79
|
-
expect(app.getConfig('debug' as any)).toBe(true)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
it('应该正确设置插件配置', () => {
|
|
83
|
-
app.setConfig('test-plugin', { enabled: true })
|
|
84
|
-
expect(app.getConfig('test-plugin' as any)).toEqual({ enabled: true })
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
describe('生命周期管理', () => {
|
|
89
|
-
beforeEach(() => {
|
|
90
|
-
app = new App({
|
|
91
|
-
log_level: LogLevel.INFO,
|
|
92
|
-
plugin_dirs: [],
|
|
93
|
-
plugins: [],
|
|
94
|
-
bots: [],
|
|
95
|
-
debug: false
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('应该正确启动和停止App', async () => {
|
|
100
|
-
await expect(app.start()).resolves.not.toThrow()
|
|
101
|
-
await expect(app.stop()).resolves.not.toThrow()
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('应该在启动时初始化插件', async () => {
|
|
105
|
-
// 测试app启动过程
|
|
106
|
-
expect(typeof app.start).toBe('function')
|
|
107
|
-
|
|
108
|
-
// 由于插件初始化涉及复杂的依赖加载,这里主要测试方法存在
|
|
109
|
-
expect(app.dependencyList).toBeDefined()
|
|
110
|
-
})
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
describe('Schema管理', () => {
|
|
114
|
-
beforeEach(() => {
|
|
115
|
-
app = new App({
|
|
116
|
-
log_level: LogLevel.INFO,
|
|
117
|
-
plugin_dirs: [],
|
|
118
|
-
plugins: [],
|
|
119
|
-
bots: [],
|
|
120
|
-
debug: false
|
|
121
|
-
})
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('应该有默认的App Schema', () => {
|
|
125
|
-
expect(app.schema).toBeDefined()
|
|
126
|
-
expect(app.schema.toJSON()).toBeDefined()
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
it('应该能够更改插件Schema', () => {
|
|
130
|
-
const mockSchema = { type: 'object', properties: {} }
|
|
131
|
-
|
|
132
|
-
// 测试changeSchema方法存在
|
|
133
|
-
expect(typeof app.changeSchema).toBe('function')
|
|
134
|
-
|
|
135
|
-
// 由于Schema系统复杂,这里主要测试接口存在
|
|
136
|
-
expect(app.schema).toBeDefined()
|
|
137
|
-
})
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
describe('上下文管理', () => {
|
|
141
|
-
beforeEach(() => {
|
|
142
|
-
app = new App({
|
|
143
|
-
log_level: LogLevel.INFO,
|
|
144
|
-
plugin_dirs: [],
|
|
145
|
-
plugins: [],
|
|
146
|
-
bots: [],
|
|
147
|
-
debug: false
|
|
148
|
-
})
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('应该能够获取注册的上下文', () => {
|
|
152
|
-
// 测试getContext方法存在
|
|
153
|
-
expect(typeof app.getContext).toBe('function')
|
|
154
|
-
|
|
155
|
-
// 测试错误处理
|
|
156
|
-
expect(() => app.getContext('nonexistent')).toThrow()
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
it('应该在获取不存在的上下文时抛出错误', () => {
|
|
160
|
-
expect(() => app.getContext('non-existent')).toThrow()
|
|
161
|
-
})
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
describe('中间件系统', () => {
|
|
165
|
-
beforeEach(() => {
|
|
166
|
-
app = new App({
|
|
167
|
-
log_level: LogLevel.INFO,
|
|
168
|
-
plugin_dirs: [],
|
|
169
|
-
plugins: [],
|
|
170
|
-
bots: [],
|
|
171
|
-
debug: false
|
|
172
|
-
})
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
it('应该能够添加中间件', () => {
|
|
176
|
-
const middleware = vi.fn(async (message, next) => await next())
|
|
177
|
-
app.middleware(middleware)
|
|
178
|
-
|
|
179
|
-
expect(app.middlewares).toContain(middleware)
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
it('应该按顺序执行中间件', async () => {
|
|
183
|
-
const order: number[] = []
|
|
184
|
-
|
|
185
|
-
app.middleware(async (message, next) => {
|
|
186
|
-
order.push(1)
|
|
187
|
-
await next()
|
|
188
|
-
order.push(4)
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
app.middleware(async (message, next) => {
|
|
192
|
-
order.push(2)
|
|
193
|
-
await next()
|
|
194
|
-
order.push(3)
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
// 创建模拟消息进行测试
|
|
198
|
-
// 注意:这里需要根据实际的消息处理逻辑调整
|
|
199
|
-
const mockMessage = { content: 'test' } as any
|
|
200
|
-
|
|
201
|
-
// 直接测试中间件执行
|
|
202
|
-
if (app.middlewares.length > 0) {
|
|
203
|
-
let index = 0
|
|
204
|
-
const runMiddleware = async () => {
|
|
205
|
-
if (index < app.middlewares.length) {
|
|
206
|
-
const middleware = app.middlewares[index++]
|
|
207
|
-
await middleware(mockMessage, runMiddleware)
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
await runMiddleware()
|
|
211
|
-
|
|
212
|
-
expect(order).toEqual([1, 2, 3, 4])
|
|
213
|
-
}
|
|
214
|
-
})
|
|
215
|
-
})
|
|
216
|
-
|
|
217
|
-
describe('错误处理', () => {
|
|
218
|
-
beforeEach(() => {
|
|
219
|
-
app = new App({
|
|
220
|
-
log_level: LogLevel.INFO,
|
|
221
|
-
plugin_dirs: [],
|
|
222
|
-
plugins: [],
|
|
223
|
-
bots: [],
|
|
224
|
-
debug: false
|
|
225
|
-
})
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
it('应该正确处理启动错误', async () => {
|
|
229
|
-
// 创建一个会失败的配置
|
|
230
|
-
app = new App({
|
|
231
|
-
log_level: LogLevel.INFO,
|
|
232
|
-
plugin_dirs: ['/non/existent/path'],
|
|
233
|
-
plugins: [],
|
|
234
|
-
bots: [],
|
|
235
|
-
debug: false
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
// 启动应该不会抛出错误,但会记录警告
|
|
239
|
-
await expect(app.start()).resolves.not.toThrow()
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
it('应该正确处理中间件错误', async () => {
|
|
243
|
-
const errorMiddleware = vi.fn(async () => {
|
|
244
|
-
throw new Error('中间件错误')
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
app.middleware(errorMiddleware)
|
|
248
|
-
|
|
249
|
-
// 错误应该被捕获并处理
|
|
250
|
-
const mockMessage = { content: 'test' } as any
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
if (app.middlewares.length > 0) {
|
|
254
|
-
const middleware = app.middlewares[0]
|
|
255
|
-
await middleware(mockMessage, async () => {})
|
|
256
|
-
}
|
|
257
|
-
// 如果没有抛出错误,测试仍然通过,因为框架可能内部处理了错误
|
|
258
|
-
expect(true).toBe(true)
|
|
259
|
-
} catch (error: any) {
|
|
260
|
-
// 如果抛出了错误,验证错误信息
|
|
261
|
-
expect(error.message).toBe('中间件错误')
|
|
262
|
-
}
|
|
263
|
-
})
|
|
264
|
-
})
|
|
265
|
-
})
|
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
|
-
import { Permissions, PermissionItem, PermissionChecker } from '../src/permissions'
|
|
3
|
-
import { App } from '../src/app'
|
|
4
|
-
import { Message, MessageBase, MessageChannel } from '../src/message'
|
|
5
|
-
|
|
6
|
-
describe('权限系统测试', () => {
|
|
7
|
-
let app: App
|
|
8
|
-
let permissions: Permissions
|
|
9
|
-
let mockMessage: MessageBase
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
app = new App({
|
|
13
|
-
log_level: 1,
|
|
14
|
-
plugin_dirs: [],
|
|
15
|
-
plugins: [],
|
|
16
|
-
bots: [],
|
|
17
|
-
debug: false
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
permissions = new Permissions(app)
|
|
21
|
-
|
|
22
|
-
// 创建模拟消息
|
|
23
|
-
const mockChannel: MessageChannel = {
|
|
24
|
-
id: 'channel123',
|
|
25
|
-
type: 'group'
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
mockMessage = {
|
|
29
|
-
$id: 'msg123',
|
|
30
|
-
$adapter: 'test',
|
|
31
|
-
$bot: 'bot123',
|
|
32
|
-
$content: [],
|
|
33
|
-
$sender: {
|
|
34
|
-
id: 'user123',
|
|
35
|
-
name: 'testuser'
|
|
36
|
-
},
|
|
37
|
-
$reply: vi.fn().mockResolvedValue('reply123'),
|
|
38
|
-
$channel: mockChannel,
|
|
39
|
-
$timestamp: Date.now(),
|
|
40
|
-
$raw: 'test message'
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
describe('Permissions实例化', () => {
|
|
45
|
-
it('应该正确创建Permissions实例', () => {
|
|
46
|
-
expect(permissions).toBeInstanceOf(Permissions)
|
|
47
|
-
expect(permissions).toBeInstanceOf(Array)
|
|
48
|
-
expect(permissions.length).toBeGreaterThan(0) // 应该有预定义的权限
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('应该包含预定义的权限检查器', () => {
|
|
52
|
-
expect(permissions.length).toBeGreaterThan(4) // adapter, group, private, channel, user
|
|
53
|
-
})
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
describe('权限定义', () => {
|
|
57
|
-
it('应该支持字符串权限名', () => {
|
|
58
|
-
const permission = Permissions.define('test.permission', () => true)
|
|
59
|
-
|
|
60
|
-
expect(permission.name).toBe('test.permission')
|
|
61
|
-
expect(typeof permission.check).toBe('function')
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('应该支持正则表达式权限名', () => {
|
|
65
|
-
const permission = Permissions.define(/^admin\./, () => true)
|
|
66
|
-
|
|
67
|
-
expect(permission.name).toBeInstanceOf(RegExp)
|
|
68
|
-
expect(typeof permission.check).toBe('function')
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('应该支持同步权限检查器', () => {
|
|
72
|
-
const permission = Permissions.define('sync.permission', () => true)
|
|
73
|
-
|
|
74
|
-
expect(typeof permission.check).toBe('function')
|
|
75
|
-
expect(permission.name).toBe('sync.permission')
|
|
76
|
-
})
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
describe('权限添加和查找', () => {
|
|
80
|
-
it('应该能够添加新权限', () => {
|
|
81
|
-
const initialLength = permissions.length
|
|
82
|
-
const newPermission = Permissions.define('new.permission', () => true)
|
|
83
|
-
|
|
84
|
-
permissions.add(newPermission)
|
|
85
|
-
|
|
86
|
-
expect(permissions.length).toBe(initialLength + 1)
|
|
87
|
-
expect(permissions[permissions.length - 1]).toBe(newPermission)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('应该能够查找匹配的权限', () => {
|
|
91
|
-
const testPermission = Permissions.define('test.specific', () => true)
|
|
92
|
-
permissions.add(testPermission)
|
|
93
|
-
|
|
94
|
-
const found = permissions.get('test.specific')
|
|
95
|
-
|
|
96
|
-
expect(found).toBe(testPermission)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('应该能够通过正则表达式查找权限', () => {
|
|
100
|
-
const regexPermission = Permissions.define(/^admin\./, () => true)
|
|
101
|
-
permissions.add(regexPermission)
|
|
102
|
-
|
|
103
|
-
const found = permissions.get('admin.users')
|
|
104
|
-
|
|
105
|
-
expect(found).toBe(regexPermission)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('应该返回undefined当权限不存在时', () => {
|
|
109
|
-
const found = permissions.get('nonexistent.permission')
|
|
110
|
-
|
|
111
|
-
expect(found).toBeUndefined()
|
|
112
|
-
})
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
describe('预定义权限检查器', () => {
|
|
116
|
-
it('应该正确检查adapter权限', async () => {
|
|
117
|
-
// 测试匹配的适配器
|
|
118
|
-
mockMessage.$adapter = 'test-adapter'
|
|
119
|
-
const permission = permissions.get('adapter(test-adapter)')
|
|
120
|
-
|
|
121
|
-
expect(permission).toBeDefined()
|
|
122
|
-
if (permission) {
|
|
123
|
-
const result = await permission.check('adapter(test-adapter)', mockMessage as any)
|
|
124
|
-
expect(result).toBe(true)
|
|
125
|
-
}
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('应该拒绝不匹配的adapter权限', async () => {
|
|
129
|
-
mockMessage.$adapter = 'other-adapter'
|
|
130
|
-
const permission = permissions.get('adapter(test-adapter)')
|
|
131
|
-
|
|
132
|
-
expect(permission).toBeDefined()
|
|
133
|
-
if (permission) {
|
|
134
|
-
const result = await permission.check('adapter(test-adapter)', mockMessage as any)
|
|
135
|
-
expect(result).toBe(false)
|
|
136
|
-
}
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
describe('群组权限检查', () => {
|
|
140
|
-
beforeEach(() => {
|
|
141
|
-
mockMessage.$channel = { id: 'group123', type: 'group' }
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
it('应该匹配特定群组ID', async () => {
|
|
145
|
-
const permission = permissions.get('group(group123)')
|
|
146
|
-
|
|
147
|
-
expect(permission).toBeDefined()
|
|
148
|
-
if (permission) {
|
|
149
|
-
const result = await permission.check('group(group123)', mockMessage as any)
|
|
150
|
-
expect(result).toBe(true)
|
|
151
|
-
}
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
it('应该匹配通配符群组', async () => {
|
|
155
|
-
const permission = permissions.get('group(*)')
|
|
156
|
-
|
|
157
|
-
expect(permission).toBeDefined()
|
|
158
|
-
if (permission) {
|
|
159
|
-
const result = await permission.check('group(*)', mockMessage as any)
|
|
160
|
-
expect(result).toBe(true)
|
|
161
|
-
}
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
it('应该拒绝非群组消息', async () => {
|
|
165
|
-
mockMessage.$channel.type = 'private'
|
|
166
|
-
const permission = permissions.get('group(group123)')
|
|
167
|
-
|
|
168
|
-
expect(permission).toBeDefined()
|
|
169
|
-
if (permission) {
|
|
170
|
-
const result = await permission.check('group(group123)', mockMessage as any)
|
|
171
|
-
expect(result).toBe(false)
|
|
172
|
-
}
|
|
173
|
-
})
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
describe('私聊权限检查', () => {
|
|
177
|
-
beforeEach(() => {
|
|
178
|
-
mockMessage.$channel = { id: 'private123', type: 'private' }
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
it('应该匹配特定私聊ID', async () => {
|
|
182
|
-
const permission = permissions.get('private(private123)')
|
|
183
|
-
|
|
184
|
-
expect(permission).toBeDefined()
|
|
185
|
-
if (permission) {
|
|
186
|
-
const result = await permission.check('private(private123)', mockMessage as any)
|
|
187
|
-
expect(result).toBe(true)
|
|
188
|
-
}
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
it('应该匹配通配符私聊', async () => {
|
|
192
|
-
const permission = permissions.get('private(*)')
|
|
193
|
-
|
|
194
|
-
expect(permission).toBeDefined()
|
|
195
|
-
if (permission) {
|
|
196
|
-
const result = await permission.check('private(*)', mockMessage as any)
|
|
197
|
-
expect(result).toBe(true)
|
|
198
|
-
}
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
it('应该拒绝非私聊消息', async () => {
|
|
202
|
-
mockMessage.$channel.type = 'group'
|
|
203
|
-
const permission = permissions.get('private(private123)')
|
|
204
|
-
|
|
205
|
-
expect(permission).toBeDefined()
|
|
206
|
-
if (permission) {
|
|
207
|
-
const result = await permission.check('private(private123)', mockMessage as any)
|
|
208
|
-
expect(result).toBe(false)
|
|
209
|
-
}
|
|
210
|
-
})
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
describe('频道权限检查', () => {
|
|
214
|
-
beforeEach(() => {
|
|
215
|
-
mockMessage.$channel = { id: 'channel123', type: 'channel' }
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
it('应该匹配特定频道ID', async () => {
|
|
219
|
-
const permission = permissions.get('channel(channel123)')
|
|
220
|
-
|
|
221
|
-
expect(permission).toBeDefined()
|
|
222
|
-
if (permission) {
|
|
223
|
-
const result = await permission.check('channel(channel123)', mockMessage as any)
|
|
224
|
-
expect(result).toBe(true)
|
|
225
|
-
}
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
it('应该匹配通配符频道', async () => {
|
|
229
|
-
const permission = permissions.get('channel(*)')
|
|
230
|
-
|
|
231
|
-
expect(permission).toBeDefined()
|
|
232
|
-
if (permission) {
|
|
233
|
-
const result = await permission.check('channel(*)', mockMessage as any)
|
|
234
|
-
expect(result).toBe(true)
|
|
235
|
-
}
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
it('应该拒绝非频道消息', async () => {
|
|
239
|
-
mockMessage.$channel.type = 'group'
|
|
240
|
-
const permission = permissions.get('channel(channel123)')
|
|
241
|
-
|
|
242
|
-
expect(permission).toBeDefined()
|
|
243
|
-
if (permission) {
|
|
244
|
-
const result = await permission.check('channel(channel123)', mockMessage as any)
|
|
245
|
-
expect(result).toBe(false)
|
|
246
|
-
}
|
|
247
|
-
})
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
describe('用户权限检查(有bug的实现)', () => {
|
|
251
|
-
it('应该检查用户ID权限', async () => {
|
|
252
|
-
mockMessage.$sender.id = 'user123'
|
|
253
|
-
const permission = permissions.get('user(user123)')
|
|
254
|
-
|
|
255
|
-
expect(permission).toBeDefined()
|
|
256
|
-
// 注意:原代码中user权限检查有bug,使用了错误的正则表达式
|
|
257
|
-
if (permission) {
|
|
258
|
-
const result = await permission.check('user(user123)', mockMessage as any)
|
|
259
|
-
// 由于实现中的bug,这个测试可能会失败
|
|
260
|
-
// expect(result).toBe(true)
|
|
261
|
-
expect(typeof result).toBe('boolean')
|
|
262
|
-
}
|
|
263
|
-
})
|
|
264
|
-
})
|
|
265
|
-
})
|
|
266
|
-
|
|
267
|
-
describe('权限系统集成', () => {
|
|
268
|
-
it('应该从依赖列表中获取权限', () => {
|
|
269
|
-
// 这个测试验证get方法会从app.dependencyList中收集权限
|
|
270
|
-
const originalGet = permissions.get
|
|
271
|
-
const mockDependencyList = []
|
|
272
|
-
|
|
273
|
-
// 由于依赖于app.dependencyList,这里主要测试方法存在
|
|
274
|
-
expect(typeof permissions.get).toBe('function')
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
it('应该支持权限链式查找', () => {
|
|
278
|
-
const permission1 = Permissions.define(/^test1\./, () => true)
|
|
279
|
-
const permission2 = Permissions.define(/^test2\./, () => false)
|
|
280
|
-
|
|
281
|
-
permissions.add(permission1)
|
|
282
|
-
permissions.add(permission2)
|
|
283
|
-
|
|
284
|
-
const found1 = permissions.get('test1.action')
|
|
285
|
-
const found2 = permissions.get('test2.action')
|
|
286
|
-
const notFound = permissions.get('test3.action')
|
|
287
|
-
|
|
288
|
-
expect(found1).toBe(permission1)
|
|
289
|
-
expect(found2).toBe(permission2)
|
|
290
|
-
expect(notFound).toBeUndefined()
|
|
291
|
-
})
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
describe('权限检查场景', () => {
|
|
295
|
-
it('应该支持复杂权限规则', async () => {
|
|
296
|
-
const complexPermission = Permissions.define(/^admin\./, (name, message: any) => {
|
|
297
|
-
// 复杂权限逻辑:只有特定用户在特定群组中才有管理权限
|
|
298
|
-
if (message.$channel.type !== 'group') return false
|
|
299
|
-
if (message.$channel.id !== 'admin-group') return false
|
|
300
|
-
if (!['admin1', 'admin2'].includes(message.$sender.id)) return false
|
|
301
|
-
return true
|
|
302
|
-
})
|
|
303
|
-
|
|
304
|
-
permissions.add(complexPermission)
|
|
305
|
-
|
|
306
|
-
// 测试符合条件的情况
|
|
307
|
-
mockMessage.$channel = { id: 'admin-group', type: 'group' }
|
|
308
|
-
mockMessage.$sender.id = 'admin1'
|
|
309
|
-
|
|
310
|
-
const permission = permissions.get('admin.delete')
|
|
311
|
-
expect(permission).toBe(complexPermission)
|
|
312
|
-
|
|
313
|
-
if (permission) {
|
|
314
|
-
const result = await permission.check('admin.delete', mockMessage as any)
|
|
315
|
-
expect(result).toBe(true)
|
|
316
|
-
}
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
it('应该支持时间相关权限', async () => {
|
|
320
|
-
const timePermission = Permissions.define('time.restricted', (name, message) => {
|
|
321
|
-
const hour = new Date().getHours()
|
|
322
|
-
return hour >= 9 && hour <= 17 // 工作时间内才允许
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
permissions.add(timePermission)
|
|
326
|
-
|
|
327
|
-
const permission = permissions.get('time.restricted')
|
|
328
|
-
expect(permission).toBe(timePermission)
|
|
329
|
-
|
|
330
|
-
if (permission) {
|
|
331
|
-
const result = await permission.check('time.restricted', mockMessage as any)
|
|
332
|
-
expect(typeof result).toBe('boolean')
|
|
333
|
-
}
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
it('应该处理权限检查中的错误', async () => {
|
|
337
|
-
const errorPermission = Permissions.define('error.permission', () => {
|
|
338
|
-
throw new Error('Permission check failed')
|
|
339
|
-
})
|
|
340
|
-
|
|
341
|
-
permissions.add(errorPermission)
|
|
342
|
-
|
|
343
|
-
const permission = permissions.get('error.permission')
|
|
344
|
-
expect(permission).toBe(errorPermission)
|
|
345
|
-
|
|
346
|
-
if (permission) {
|
|
347
|
-
// 使用try-catch来测试错误处理而不是expect rejects
|
|
348
|
-
try {
|
|
349
|
-
await permission.check('error.permission', mockMessage as any)
|
|
350
|
-
// 如果没有抛出错误,测试失败
|
|
351
|
-
expect(true).toBe(false)
|
|
352
|
-
} catch (error: any) {
|
|
353
|
-
expect(error.message).toBe('Permission check failed')
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
})
|
|
357
|
-
})
|
|
358
|
-
})
|