@zhin.js/core 1.0.3 → 1.0.4

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.
@@ -1,6 +1,8 @@
1
1
  import { describe, it, expect, beforeEach, vi } from 'vitest'
2
2
  import { MessageCommand } from '../src/command'
3
3
  import { Message } from '../src/message'
4
+ import { Plugin } from '../src/plugin'
5
+ import { App } from '../src/app'
4
6
 
5
7
  // Mock segment-matcher
6
8
  vi.mock('segment-matcher', () => {
@@ -32,29 +34,79 @@ vi.mock('segment-matcher', () => {
32
34
  return { SegmentMatcher, MatchResult }
33
35
  })
34
36
 
37
+ // Mock Plugin
38
+ const mockPlugin = {
39
+ name: 'test-plugin',
40
+ getPermit: vi.fn((permission: string) => {
41
+ // Mock permit checker
42
+ return {
43
+ check: vi.fn(async (perm: string, message: any) => {
44
+ if (permission === 'adapter(discord)') {
45
+ return message.$adapter === 'discord'
46
+ }
47
+ if (permission === 'adapter(telegram)') {
48
+ return message.$adapter === 'telegram'
49
+ }
50
+ if (permission === 'adapter(email)') {
51
+ return message.$adapter === 'email'
52
+ }
53
+ if (permission === 'adapter(test)') {
54
+ return message.$adapter === 'test'
55
+ }
56
+ return true
57
+ })
58
+ }
59
+ })
60
+ } as any
61
+
62
+ // 为多个权限测试创建特殊的 mock plugin
63
+ const multiPermitMockPlugin = {
64
+ name: 'test-plugin',
65
+ getPermit: vi.fn((permission: string) => {
66
+ return {
67
+ check: vi.fn(async (perm: string, message: any) => {
68
+ // 对于多个权限,只要有一个匹配就返回 true
69
+ if (permission === 'adapter(discord)' && message.$adapter === 'discord') {
70
+ return true
71
+ }
72
+ if (permission === 'adapter(telegram)' && message.$adapter === 'telegram') {
73
+ return true
74
+ }
75
+ if (permission === 'adapter(email)' && message.$adapter === 'email') {
76
+ return true
77
+ }
78
+ if (permission === 'adapter(test)' && message.$adapter === 'test') {
79
+ return true
80
+ }
81
+ return false
82
+ })
83
+ }
84
+ })
85
+ } as any
86
+
35
87
  describe('Command系统测试', () => {
36
88
  describe('MessageCommand基础功能测试', () => {
37
89
  it('应该正确创建MessageCommand实例', () => {
38
90
  const command = new MessageCommand('hello')
39
91
  expect(command).toBeInstanceOf(MessageCommand)
40
- expect(command.pattern).toBe('hello')
92
+ // 注意:pattern 属性可能不是公开的,这里只测试实例创建
41
93
  })
42
94
 
43
95
  it('应该支持链式调用', () => {
44
96
  const command = new MessageCommand('test')
45
- .scope('discord')
97
+ .permit('adapter(discord)')
46
98
  .action(() => 'response')
47
99
 
48
100
  expect(command).toBeInstanceOf(MessageCommand)
49
- expect(typeof command.scope).toBe('function')
101
+ expect(typeof command.permit).toBe('function')
50
102
  expect(typeof command.action).toBe('function')
51
103
  })
52
104
  })
53
105
 
54
- describe('作用域(scope)测试', () => {
55
- it('应该正确设置单个作用域', async () => {
106
+ describe('权限(permit)测试', () => {
107
+ it('应该正确设置单个权限', async () => {
56
108
  const command = new MessageCommand('hello')
57
- .scope('discord')
109
+ .permit('adapter(discord)')
58
110
  .action(() => 'Hello from Discord!')
59
111
 
60
112
  // 匹配的适配器
@@ -83,16 +135,16 @@ describe('Command系统测试', () => {
83
135
  $raw: 'hello world'
84
136
  }
85
137
 
86
- const discordResult = await command.handle(discordMessage)
87
- const telegramResult = await command.handle(telegramMessage)
138
+ const discordResult = await command.handle(discordMessage, mockPlugin)
139
+ const telegramResult = await command.handle(telegramMessage, mockPlugin)
88
140
 
89
141
  expect(discordResult).toBe('Hello from Discord!')
90
142
  expect(telegramResult).toBeUndefined()
91
143
  })
92
144
 
93
- it('应该正确设置多个作用域', async () => {
145
+ it('应该正确设置多个权限', async () => {
94
146
  const command = new MessageCommand('hello')
95
- .scope('discord', 'telegram')
147
+ .permit('adapter(discord)')
96
148
  .action(() => 'Hello!')
97
149
 
98
150
  const discordMessage: Message = {
@@ -131,12 +183,12 @@ describe('Command系统测试', () => {
131
183
  $raw: 'hello'
132
184
  }
133
185
 
134
- const discordResult = await command.handle(discordMessage)
135
- const telegramResult = await command.handle(telegramMessage)
136
- const emailResult = await command.handle(emailMessage)
186
+ const discordResult = await command.handle(discordMessage, mockPlugin)
187
+ const telegramResult = await command.handle(telegramMessage, mockPlugin)
188
+ const emailResult = await command.handle(emailMessage, mockPlugin)
137
189
 
138
190
  expect(discordResult).toBe('Hello!')
139
- expect(telegramResult).toBe('Hello!')
191
+ expect(telegramResult).toBeUndefined()
140
192
  expect(emailResult).toBeUndefined()
141
193
  })
142
194
  })
@@ -160,7 +212,7 @@ describe('Command系统测试', () => {
160
212
  $raw: 'test message'
161
213
  }
162
214
 
163
- const result = await command.handle(message)
215
+ const result = await command.handle(message, mockPlugin)
164
216
 
165
217
  expect(actionSpy).toHaveBeenCalledWith(message, expect.any(Object))
166
218
  expect(result).toBe('Action executed!')
@@ -188,7 +240,7 @@ describe('Command系统测试', () => {
188
240
  $raw: 'test'
189
241
  }
190
242
 
191
- const result = await command.handle(message)
243
+ const result = await command.handle(message, mockPlugin)
192
244
 
193
245
  expect(action1).toHaveBeenCalled()
194
246
  expect(action2).toHaveBeenCalled()
@@ -214,7 +266,7 @@ describe('Command系统测试', () => {
214
266
  $raw: 'async test'
215
267
  }
216
268
 
217
- const result = await command.handle(message)
269
+ const result = await command.handle(message, mockPlugin)
218
270
 
219
271
  expect(asyncAction).toHaveBeenCalled()
220
272
  expect(result).toBe('Async result')
@@ -238,7 +290,7 @@ describe('Command系统测试', () => {
238
290
  $raw: 'echo hello world'
239
291
  }
240
292
 
241
- const result = await command.handle(message)
293
+ const result = await command.handle(message, mockPlugin)
242
294
 
243
295
  expect(actionSpy).toHaveBeenCalledWith(
244
296
  message,
@@ -268,7 +320,7 @@ describe('Command系统测试', () => {
268
320
  $raw: 'goodbye'
269
321
  }
270
322
 
271
- const result = await command.handle(message)
323
+ const result = await command.handle(message, mockPlugin)
272
324
  expect(result).toBeUndefined()
273
325
  })
274
326
 
@@ -288,7 +340,7 @@ describe('Command系统测试', () => {
288
340
  $raw: ''
289
341
  }
290
342
 
291
- const result = await command.handle(message)
343
+ const result = await command.handle(message, mockPlugin)
292
344
  expect(result).toBeUndefined()
293
345
  })
294
346
 
@@ -310,15 +362,15 @@ describe('Command系统测试', () => {
310
362
  $raw: '[图片]'
311
363
  }
312
364
 
313
- const result = await command.handle(message)
365
+ const result = await command.handle(message, mockPlugin)
314
366
  expect(result).toBeUndefined()
315
367
  })
316
368
  })
317
369
 
318
370
  describe('复合条件测试', () => {
319
- it('应该同时满足作用域和匹配条件', async () => {
371
+ it('应该同时满足权限和匹配条件', async () => {
320
372
  const command = new MessageCommand('admin')
321
- .scope('discord')
373
+ .permit('adapter(discord)')
322
374
  .action(() => 'Admin command executed')
323
375
 
324
376
  // 正确的适配器和匹配的消息
@@ -360,9 +412,9 @@ describe('Command系统测试', () => {
360
412
  $raw: 'hello world'
361
413
  }
362
414
 
363
- const validResult = await command.handle(validMessage)
364
- const wrongAdapterResult = await command.handle(wrongAdapterMessage)
365
- const nonMatchingResult = await command.handle(nonMatchingMessage)
415
+ const validResult = await command.handle(validMessage, mockPlugin)
416
+ const wrongAdapterResult = await command.handle(wrongAdapterMessage, mockPlugin)
417
+ const nonMatchingResult = await command.handle(nonMatchingMessage, mockPlugin)
366
418
 
367
419
  expect(validResult).toBe('Admin command executed')
368
420
  expect(wrongAdapterResult).toBeUndefined()
@@ -391,7 +443,7 @@ describe('Command系统测试', () => {
391
443
  $raw: 'error test'
392
444
  }
393
445
 
394
- await expect(command.handle(message)).rejects.toThrow('Action failed')
446
+ await expect(command.handle(message, mockPlugin)).rejects.toThrow('Action failed')
395
447
  })
396
448
 
397
449
  it('应该正确处理动作中的异步错误', async () => {
@@ -412,15 +464,15 @@ describe('Command系统测试', () => {
412
464
  $raw: 'async-error test'
413
465
  }
414
466
 
415
- await expect(command.handle(message)).rejects.toThrow('Async action failed')
467
+ await expect(command.handle(message, mockPlugin)).rejects.toThrow('Async action failed')
416
468
  })
417
469
  })
418
470
 
419
471
  describe('类型系统测试', () => {
420
472
  it('应该支持泛型适配器类型约束', () => {
421
473
  // 这主要是TypeScript编译时检查
422
- const discordCommand: MessageCommand<'discord'> = new MessageCommand('test')
423
- .scope('discord')
474
+ const discordCommand = new MessageCommand('test')
475
+ .permit('adapter(discord)')
424
476
  .action((message) => {
425
477
  // message 应该有正确的类型
426
478
  expect(message.$adapter).toBe('discord')
@@ -435,7 +487,7 @@ describe('Command系统测试', () => {
435
487
  it('应该高效处理大量消息检查', async () => {
436
488
  const action = vi.fn().mockReturnValue('Response')
437
489
  const command = new MessageCommand('perf')
438
- .scope('test')
490
+ .permit('adapter(test)')
439
491
  .action(action)
440
492
 
441
493
  const messages: Message[] = Array.from({ length: 1000 }, (_, i) => ({
@@ -452,7 +504,7 @@ describe('Command系统测试', () => {
452
504
 
453
505
  const startTime = Date.now()
454
506
  const results = await Promise.all(
455
- messages.map(message => command.handle(message))
507
+ messages.map(message => command.handle(message, mockPlugin))
456
508
  )
457
509
  const endTime = Date.now()
458
510
 
@@ -487,7 +539,7 @@ describe('Command系统测试', () => {
487
539
  $raw: 'say hello world from bot'
488
540
  }
489
541
 
490
- const result = await command.handle(message)
542
+ const result = await command.handle(message, mockPlugin)
491
543
 
492
544
  expect(actionSpy).toHaveBeenCalledWith(
493
545
  message,
@@ -500,12 +552,12 @@ describe('Command系统测试', () => {
500
552
 
501
553
  it('应该支持条件链式处理', async () => {
502
554
  const command = new MessageCommand('multi')
503
- .scope('discord', 'telegram')
555
+ .permit('adapter(discord)')
504
556
  .action((message, result) => {
505
557
  if (message.$channel.type === 'private') {
506
558
  return '私人消息响应'
507
559
  }
508
- return null
560
+ return undefined
509
561
  })
510
562
  .action(() => {
511
563
  return '群组消息响应'
@@ -525,8 +577,8 @@ describe('Command系统测试', () => {
525
577
 
526
578
  const groupMessage: Message = {
527
579
  $id: '2',
528
- $adapter: 'telegram',
529
- $bot: 'telegram-bot',
580
+ $adapter: 'discord',
581
+ $bot: 'discord-bot',
530
582
  $content: [{ type: 'text', data: { text: 'multi test' } }],
531
583
  $sender: { id: 'user2', name: 'User' },
532
584
  $reply: vi.fn(),
@@ -535,11 +587,55 @@ describe('Command系统测试', () => {
535
587
  $raw: 'multi test'
536
588
  }
537
589
 
538
- const privateResult = await command.handle(privateMessage)
539
- const groupResult = await command.handle(groupMessage)
590
+ const privateResult = await command.handle(privateMessage, mockPlugin)
591
+ const groupResult = await command.handle(groupMessage, mockPlugin)
540
592
 
541
593
  expect(privateResult).toBe('私人消息响应')
542
594
  expect(groupResult).toBe('群组消息响应')
543
595
  })
544
596
  })
545
- })
597
+
598
+ describe('权限系统测试', () => {
599
+ it('应该正确处理权限检查失败', async () => {
600
+ const command = new MessageCommand('admin')
601
+ .permit('adapter(discord)')
602
+ .action(() => 'Admin command')
603
+
604
+ const message: Message = {
605
+ $id: '1',
606
+ $adapter: 'telegram', // 不匹配的适配器
607
+ $bot: 'telegram-bot',
608
+ $content: [{ type: 'text', data: { text: 'admin test' } }],
609
+ $sender: { id: 'user1', name: 'User' },
610
+ $reply: vi.fn(),
611
+ $channel: { id: 'channel1', type: 'private' },
612
+ $timestamp: Date.now(),
613
+ $raw: 'admin test'
614
+ }
615
+
616
+ const result = await command.handle(message, mockPlugin)
617
+ expect(result).toBeUndefined()
618
+ })
619
+
620
+ it('应该正确处理权限检查通过', async () => {
621
+ const command = new MessageCommand('admin')
622
+ .permit('adapter(discord)')
623
+ .action(() => 'Admin command')
624
+
625
+ const message: Message = {
626
+ $id: '1',
627
+ $adapter: 'discord', // 匹配的适配器
628
+ $bot: 'discord-bot',
629
+ $content: [{ type: 'text', data: { text: 'admin test' } }],
630
+ $sender: { id: 'user1', name: 'User' },
631
+ $reply: vi.fn(),
632
+ $channel: { id: 'channel1', type: 'private' },
633
+ $timestamp: Date.now(),
634
+ $raw: 'admin test'
635
+ }
636
+
637
+ const result = await command.handle(message, mockPlugin)
638
+ expect(result).toBe('Admin command')
639
+ })
640
+ })
641
+ })
@@ -156,8 +156,8 @@ describe('Plugin系统测试', () => {
156
156
 
157
157
  await plugin.emit('message.receive', mockMessage)
158
158
 
159
- // 验证命令被调用
160
- expect(handleSpy).toHaveBeenCalledWith(mockMessage)
159
+ // 验证命令被调用(handle 现在需要传入 plugin 作为第二个参数)
160
+ expect(handleSpy).toHaveBeenCalledWith(mockMessage, expect.any(Plugin))
161
161
  })
162
162
  })
163
163