@xiaozhi-client/cli 1.9.4-beta.10

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.
Files changed (55) hide show
  1. package/README.md +98 -0
  2. package/package.json +31 -0
  3. package/project.json +75 -0
  4. package/src/Constants.ts +105 -0
  5. package/src/Container.ts +212 -0
  6. package/src/Types.ts +79 -0
  7. package/src/commands/CommandHandlerFactory.ts +98 -0
  8. package/src/commands/ConfigCommandHandler.ts +279 -0
  9. package/src/commands/EndpointCommandHandler.ts +158 -0
  10. package/src/commands/McpCommandHandler.ts +778 -0
  11. package/src/commands/ProjectCommandHandler.ts +254 -0
  12. package/src/commands/ServiceCommandHandler.ts +182 -0
  13. package/src/commands/__tests__/CommandHandlerFactory.test.ts +323 -0
  14. package/src/commands/__tests__/CommandRegistry.test.ts +287 -0
  15. package/src/commands/__tests__/ConfigCommandHandler.test.ts +844 -0
  16. package/src/commands/__tests__/EndpointCommandHandler.test.ts +426 -0
  17. package/src/commands/__tests__/McpCommandHandler.test.ts +753 -0
  18. package/src/commands/__tests__/ProjectCommandHandler.test.ts +230 -0
  19. package/src/commands/__tests__/ServiceCommands.integration.test.ts +408 -0
  20. package/src/commands/index.ts +351 -0
  21. package/src/errors/ErrorHandlers.ts +141 -0
  22. package/src/errors/ErrorMessages.ts +121 -0
  23. package/src/errors/__tests__/index.test.ts +186 -0
  24. package/src/errors/index.ts +163 -0
  25. package/src/global.d.ts +19 -0
  26. package/src/index.ts +53 -0
  27. package/src/interfaces/Command.ts +128 -0
  28. package/src/interfaces/CommandTypes.ts +95 -0
  29. package/src/interfaces/Config.ts +25 -0
  30. package/src/interfaces/Service.ts +99 -0
  31. package/src/services/DaemonManager.ts +318 -0
  32. package/src/services/ProcessManager.ts +235 -0
  33. package/src/services/ServiceManager.ts +319 -0
  34. package/src/services/TemplateManager.ts +382 -0
  35. package/src/services/__tests__/DaemonManager.test.ts +378 -0
  36. package/src/services/__tests__/DaemonMode.integration.test.ts +321 -0
  37. package/src/services/__tests__/ProcessManager.test.ts +296 -0
  38. package/src/services/__tests__/ServiceManager.test.ts +774 -0
  39. package/src/services/__tests__/TemplateManager.test.ts +337 -0
  40. package/src/types/backend.d.ts +48 -0
  41. package/src/utils/FileUtils.ts +320 -0
  42. package/src/utils/FormatUtils.ts +198 -0
  43. package/src/utils/PathUtils.ts +255 -0
  44. package/src/utils/PlatformUtils.ts +217 -0
  45. package/src/utils/Validation.ts +274 -0
  46. package/src/utils/VersionUtils.ts +141 -0
  47. package/src/utils/__tests__/FileUtils.test.ts +728 -0
  48. package/src/utils/__tests__/FormatUtils.test.ts +243 -0
  49. package/src/utils/__tests__/PathUtils.test.ts +1165 -0
  50. package/src/utils/__tests__/PlatformUtils.test.ts +723 -0
  51. package/src/utils/__tests__/Validation.test.ts +560 -0
  52. package/src/utils/__tests__/VersionUtils.test.ts +410 -0
  53. package/tsconfig.json +32 -0
  54. package/tsup.config.ts +100 -0
  55. package/vitest.config.ts +97 -0
@@ -0,0 +1,560 @@
1
+ /**
2
+ * 输入验证工具单元测试
3
+ */
4
+
5
+ import { describe, expect, it } from "vitest";
6
+ import { ValidationError } from "../../errors/index";
7
+ import { Validation } from "../Validation";
8
+
9
+ describe("Validation", () => {
10
+ describe("验证端口号", () => {
11
+ it("应接受有效的端口号", () => {
12
+ expect(() => Validation.validatePort(80)).not.toThrow();
13
+ expect(() => Validation.validatePort(8080)).not.toThrow();
14
+ expect(() => Validation.validatePort(65535)).not.toThrow();
15
+ });
16
+
17
+ it("应拒绝非整数端口号", () => {
18
+ expect(() => Validation.validatePort(80.5)).toThrow(ValidationError);
19
+ expect(() => Validation.validatePort(Number.NaN)).toThrow(
20
+ ValidationError
21
+ );
22
+ });
23
+
24
+ it("应拒绝小于1的端口号", () => {
25
+ expect(() => Validation.validatePort(0)).toThrow(ValidationError);
26
+ expect(() => Validation.validatePort(-1)).toThrow(ValidationError);
27
+ });
28
+
29
+ it("应拒绝大于65535的端口号", () => {
30
+ expect(() => Validation.validatePort(65536)).toThrow(ValidationError);
31
+ expect(() => Validation.validatePort(99999)).toThrow(ValidationError);
32
+ });
33
+
34
+ it("应抛出带有正确消息的验证错误", () => {
35
+ expect(() => Validation.validatePort(99999)).toThrow(
36
+ "端口号必须在 1-65535 范围内"
37
+ );
38
+ });
39
+ });
40
+
41
+ describe("验证配置格式", () => {
42
+ it("应接受有效的配置格式", () => {
43
+ expect(Validation.validateConfigFormat("json")).toBe("json");
44
+ expect(Validation.validateConfigFormat("json5")).toBe("json5");
45
+ expect(Validation.validateConfigFormat("jsonc")).toBe("jsonc");
46
+ });
47
+
48
+ it("应拒绝无效的配置格式", () => {
49
+ expect(() => Validation.validateConfigFormat("xml")).toThrow(
50
+ ValidationError
51
+ );
52
+ expect(() => Validation.validateConfigFormat("yaml")).toThrow(
53
+ ValidationError
54
+ );
55
+ expect(() => Validation.validateConfigFormat("")).toThrow(
56
+ ValidationError
57
+ );
58
+ });
59
+
60
+ it("应抛出带有正确消息的验证错误", () => {
61
+ expect(() => Validation.validateConfigFormat("invalid")).toThrow(
62
+ "无效的配置文件格式: invalid,支持的格式: json, json5, jsonc"
63
+ );
64
+ });
65
+ });
66
+
67
+ describe("验证必填字段", () => {
68
+ it("应接受非null、非undefined、非空值", () => {
69
+ expect(() => Validation.validateRequired("value", "field")).not.toThrow();
70
+ expect(() => Validation.validateRequired(0, "field")).not.toThrow();
71
+ expect(() => Validation.validateRequired(false, "field")).not.toThrow();
72
+ expect(() => Validation.validateRequired([], "field")).not.toThrow();
73
+ expect(() => Validation.validateRequired({}, "field")).not.toThrow();
74
+ });
75
+
76
+ it("应拒绝undefined值", () => {
77
+ expect(() => Validation.validateRequired(undefined, "field")).toThrow(
78
+ ValidationError
79
+ );
80
+ });
81
+
82
+ it("应拒绝null值", () => {
83
+ expect(() => Validation.validateRequired(null, "field")).toThrow(
84
+ ValidationError
85
+ );
86
+ });
87
+
88
+ it("应拒绝空字符串", () => {
89
+ expect(() => Validation.validateRequired("", "field")).toThrow(
90
+ ValidationError
91
+ );
92
+ });
93
+
94
+ it("应抛出带有正确字段名的验证错误", () => {
95
+ expect(() => Validation.validateRequired(undefined, "testField")).toThrow(
96
+ "验证失败: testField - 必填字段不能为空"
97
+ );
98
+ });
99
+ });
100
+
101
+ describe("验证字符串长度", () => {
102
+ it("应接受长度范围内的字符串", () => {
103
+ expect(() =>
104
+ Validation.validateStringLength("hello", "field", { min: 3, max: 10 })
105
+ ).not.toThrow();
106
+ expect(() =>
107
+ Validation.validateStringLength("hello", "field", { min: 5 })
108
+ ).not.toThrow();
109
+ expect(() =>
110
+ Validation.validateStringLength("hello", "field", { max: 10 })
111
+ ).not.toThrow();
112
+ expect(() =>
113
+ Validation.validateStringLength("hello", "field")
114
+ ).not.toThrow();
115
+ });
116
+
117
+ it("应拒绝短于最小长度的字符串", () => {
118
+ expect(() =>
119
+ Validation.validateStringLength("hi", "field", { min: 3 })
120
+ ).toThrow(ValidationError);
121
+ });
122
+
123
+ it("应拒绝长于最大长度的字符串", () => {
124
+ expect(() =>
125
+ Validation.validateStringLength("verylongstring", "field", { max: 5 })
126
+ ).toThrow(ValidationError);
127
+ });
128
+
129
+ it("应抛出带有正确消息的验证错误", () => {
130
+ expect(() =>
131
+ Validation.validateStringLength("hi", "field", { min: 3 })
132
+ ).toThrow("长度不能少于 3 个字符,当前长度: 2");
133
+ expect(() =>
134
+ Validation.validateStringLength("verylongstring", "field", { max: 5 })
135
+ ).toThrow("长度不能超过 5 个字符,当前长度: 14");
136
+ });
137
+ });
138
+
139
+ describe("验证URL", () => {
140
+ it("应接受有效的URL", () => {
141
+ expect(() => Validation.validateUrl("http://example.com")).not.toThrow();
142
+ expect(() => Validation.validateUrl("https://example.com")).not.toThrow();
143
+ expect(() =>
144
+ Validation.validateUrl("http://localhost:8080")
145
+ ).not.toThrow();
146
+ expect(() =>
147
+ Validation.validateUrl("https://example.com/path?query=value")
148
+ ).not.toThrow();
149
+ });
150
+
151
+ it("应拒绝无效的URL", () => {
152
+ expect(() => Validation.validateUrl("not-a-url")).toThrow(
153
+ ValidationError
154
+ );
155
+ expect(() => Validation.validateUrl("http://")).toThrow(ValidationError);
156
+ expect(() => Validation.validateUrl("")).toThrow(ValidationError);
157
+ });
158
+
159
+ it("应抛出带有正确字段名的验证错误", () => {
160
+ expect(() => Validation.validateUrl("invalid", "testField")).toThrow(
161
+ "无效的 URL 格式: invalid"
162
+ );
163
+ });
164
+ });
165
+
166
+ describe("验证WebSocket URL", () => {
167
+ it("应接受有效的WebSocket URL", () => {
168
+ expect(() =>
169
+ Validation.validateWebSocketUrl("ws://example.com")
170
+ ).not.toThrow();
171
+ expect(() =>
172
+ Validation.validateWebSocketUrl("wss://example.com")
173
+ ).not.toThrow();
174
+ expect(() =>
175
+ Validation.validateWebSocketUrl("ws://localhost:8080")
176
+ ).not.toThrow();
177
+ });
178
+
179
+ it("应拒绝非WebSocket URL", () => {
180
+ expect(() =>
181
+ Validation.validateWebSocketUrl("http://example.com")
182
+ ).toThrow(ValidationError);
183
+ expect(() =>
184
+ Validation.validateWebSocketUrl("https://example.com")
185
+ ).toThrow(ValidationError);
186
+ expect(() =>
187
+ Validation.validateWebSocketUrl("ftp://example.com")
188
+ ).toThrow(ValidationError);
189
+ });
190
+
191
+ it("应拒绝无效的WebSocket URL", () => {
192
+ expect(() => Validation.validateWebSocketUrl("ws://")).toThrow(
193
+ ValidationError
194
+ );
195
+ expect(() => Validation.validateWebSocketUrl("wss://")).toThrow(
196
+ ValidationError
197
+ );
198
+ });
199
+
200
+ it("应抛出带有正确协议消息的验证错误", () => {
201
+ expect(() =>
202
+ Validation.validateWebSocketUrl("http://example.com")
203
+ ).toThrow("WebSocket URL 必须使用 ws:// 或 wss:// 协议,当前协议: http:");
204
+ });
205
+ });
206
+
207
+ describe("验证HTTP URL", () => {
208
+ it("应接受有效的HTTP URL", () => {
209
+ expect(() =>
210
+ Validation.validateHttpUrl("http://example.com")
211
+ ).not.toThrow();
212
+ expect(() =>
213
+ Validation.validateHttpUrl("https://example.com")
214
+ ).not.toThrow();
215
+ expect(() =>
216
+ Validation.validateHttpUrl("http://localhost:8080")
217
+ ).not.toThrow();
218
+ });
219
+
220
+ it("应拒绝非HTTP URL", () => {
221
+ expect(() => Validation.validateHttpUrl("ws://example.com")).toThrow(
222
+ ValidationError
223
+ );
224
+ expect(() => Validation.validateHttpUrl("wss://example.com")).toThrow(
225
+ ValidationError
226
+ );
227
+ expect(() => Validation.validateHttpUrl("ftp://example.com")).toThrow(
228
+ ValidationError
229
+ );
230
+ });
231
+
232
+ it("应拒绝无效的HTTP URL", () => {
233
+ expect(() => Validation.validateHttpUrl("http://")).toThrow(
234
+ ValidationError
235
+ );
236
+ expect(() => Validation.validateHttpUrl("https://")).toThrow(
237
+ ValidationError
238
+ );
239
+ });
240
+
241
+ it("应抛出带有正确协议消息的验证错误", () => {
242
+ expect(() => Validation.validateHttpUrl("ws://example.com")).toThrow(
243
+ "HTTP URL 必须使用 http:// 或 https:// 协议,当前协议: ws:"
244
+ );
245
+ });
246
+ });
247
+
248
+ describe("验证项目名称", () => {
249
+ it("应接受有效的项目名称", () => {
250
+ expect(() => Validation.validateProjectName("my-project")).not.toThrow();
251
+ expect(() => Validation.validateProjectName("my_project")).not.toThrow();
252
+ expect(() => Validation.validateProjectName("myproject")).not.toThrow();
253
+ expect(() =>
254
+ Validation.validateProjectName("MyProject123")
255
+ ).not.toThrow();
256
+ });
257
+
258
+ it("应拒绝包含无效字符的项目名称", () => {
259
+ expect(() => Validation.validateProjectName("my<project")).toThrow(
260
+ ValidationError
261
+ );
262
+ expect(() => Validation.validateProjectName("my>project")).toThrow(
263
+ ValidationError
264
+ );
265
+ expect(() => Validation.validateProjectName('my:"project"')).toThrow(
266
+ ValidationError
267
+ );
268
+ expect(() => Validation.validateProjectName("my/project")).toThrow(
269
+ ValidationError
270
+ );
271
+ expect(() => Validation.validateProjectName("my\\project")).toThrow(
272
+ ValidationError
273
+ );
274
+ expect(() => Validation.validateProjectName("my|project")).toThrow(
275
+ ValidationError
276
+ );
277
+ expect(() => Validation.validateProjectName("my?project")).toThrow(
278
+ ValidationError
279
+ );
280
+ expect(() => Validation.validateProjectName("my*project")).toThrow(
281
+ ValidationError
282
+ );
283
+ });
284
+
285
+ it("应拒绝包含控制字符的项目名称", () => {
286
+ expect(() => Validation.validateProjectName("my\u0000project")).toThrow(
287
+ ValidationError
288
+ );
289
+ expect(() => Validation.validateProjectName("my\u0001project")).toThrow(
290
+ ValidationError
291
+ );
292
+ });
293
+
294
+ it("应拒绝以点开头的项目名称", () => {
295
+ expect(() => Validation.validateProjectName(".myproject")).toThrow(
296
+ ValidationError
297
+ );
298
+ });
299
+
300
+ it("应拒绝过短或过长的项目名称", () => {
301
+ expect(() => Validation.validateProjectName("")).toThrow(ValidationError);
302
+ const longName = "a".repeat(101);
303
+ expect(() => Validation.validateProjectName(longName)).toThrow(
304
+ ValidationError
305
+ );
306
+ });
307
+ });
308
+
309
+ describe("验证模板名称", () => {
310
+ it("应接受有效的模板名称", () => {
311
+ expect(() =>
312
+ Validation.validateTemplateName("hello-world")
313
+ ).not.toThrow();
314
+ expect(() =>
315
+ Validation.validateTemplateName("hello_world")
316
+ ).not.toThrow();
317
+ expect(() => Validation.validateTemplateName("HelloWorld")).not.toThrow();
318
+ expect(() => Validation.validateTemplateName("hello123")).not.toThrow();
319
+ expect(() => Validation.validateTemplateName("h")).not.toThrow();
320
+ });
321
+
322
+ it("应拒绝包含无效字符的模板名称", () => {
323
+ expect(() => Validation.validateTemplateName("hello.world")).toThrow(
324
+ ValidationError
325
+ );
326
+ expect(() => Validation.validateTemplateName("hello$world")).toThrow(
327
+ ValidationError
328
+ );
329
+ expect(() => Validation.validateTemplateName("hello world")).toThrow(
330
+ ValidationError
331
+ );
332
+ expect(() => Validation.validateTemplateName("hello@world")).toThrow(
333
+ ValidationError
334
+ );
335
+ });
336
+
337
+ it("应拒绝过短或过长的模板名称", () => {
338
+ expect(() => Validation.validateTemplateName("")).toThrow(
339
+ ValidationError
340
+ );
341
+ const longName = "a".repeat(51);
342
+ expect(() => Validation.validateTemplateName(longName)).toThrow(
343
+ ValidationError
344
+ );
345
+ });
346
+ });
347
+
348
+ describe("验证环境变量名", () => {
349
+ it("应接受有效的环境变量名", () => {
350
+ expect(() => Validation.validateEnvVarName("VAR_NAME")).not.toThrow();
351
+ expect(() => Validation.validateEnvVarName("VAR123")).not.toThrow();
352
+ expect(() => Validation.validateEnvVarName("_VAR_NAME")).not.toThrow();
353
+ expect(() => Validation.validateEnvVarName("VAR_")).not.toThrow();
354
+ expect(() => Validation.validateEnvVarName("V")).not.toThrow();
355
+ });
356
+
357
+ it("应拒绝包含无效字符的环境变量名", () => {
358
+ expect(() => Validation.validateEnvVarName("var_name")).toThrow(
359
+ ValidationError
360
+ );
361
+ expect(() => Validation.validateEnvVarName("VAR-NAME")).toThrow(
362
+ ValidationError
363
+ );
364
+ expect(() => Validation.validateEnvVarName("VAR.NAME")).toThrow(
365
+ ValidationError
366
+ );
367
+ expect(() => Validation.validateEnvVarName("VAR NAME")).toThrow(
368
+ ValidationError
369
+ );
370
+ });
371
+
372
+ it("应拒绝以数字开头的环境变量名", () => {
373
+ expect(() => Validation.validateEnvVarName("1VAR_NAME")).toThrow(
374
+ ValidationError
375
+ );
376
+ expect(() => Validation.validateEnvVarName("123VAR")).toThrow(
377
+ ValidationError
378
+ );
379
+ });
380
+
381
+ it("应拒绝空的环境变量名", () => {
382
+ expect(() => Validation.validateEnvVarName("")).toThrow(ValidationError);
383
+ });
384
+ });
385
+
386
+ describe("验证JSON", () => {
387
+ it("应接受有效的JSON", () => {
388
+ const validJson = '{"key": "value", "number": 42}';
389
+ const result = Validation.validateJson(validJson);
390
+ expect(result).toEqual({ key: "value", number: 42 });
391
+ });
392
+
393
+ it("应拒绝无效的JSON", () => {
394
+ expect(() => Validation.validateJson('{"key": "value"')).toThrow(
395
+ ValidationError
396
+ );
397
+ expect(() => Validation.validateJson("not json")).toThrow(
398
+ ValidationError
399
+ );
400
+ expect(() => Validation.validateJson("")).toThrow(ValidationError);
401
+ });
402
+
403
+ it("应抛出带有正确消息的验证错误", () => {
404
+ expect(() => Validation.validateJson('{"key": "value"')).toThrow(
405
+ ValidationError
406
+ );
407
+ expect(() => Validation.validateJson('{"key": "value"')).toThrow(
408
+ "无效的 JSON 格式"
409
+ );
410
+ });
411
+ });
412
+
413
+ describe("验证数字范围", () => {
414
+ it("应接受范围内的数字", () => {
415
+ expect(() =>
416
+ Validation.validateNumberRange(5, "field", { min: 0, max: 10 })
417
+ ).not.toThrow();
418
+ expect(() =>
419
+ Validation.validateNumberRange(5, "field", { min: 5 })
420
+ ).not.toThrow();
421
+ expect(() =>
422
+ Validation.validateNumberRange(5, "field", { max: 10 })
423
+ ).not.toThrow();
424
+ expect(() => Validation.validateNumberRange(5, "field")).not.toThrow();
425
+ });
426
+
427
+ it("应拒绝低于最小值的数字", () => {
428
+ expect(() =>
429
+ Validation.validateNumberRange(-1, "field", { min: 0 })
430
+ ).toThrow(ValidationError);
431
+ });
432
+
433
+ it("应拒绝高于最大值的数字", () => {
434
+ expect(() =>
435
+ Validation.validateNumberRange(11, "field", { max: 10 })
436
+ ).toThrow(ValidationError);
437
+ });
438
+
439
+ it("应抛出带有正确消息的验证错误", () => {
440
+ expect(() =>
441
+ Validation.validateNumberRange(-1, "field", { min: 0 })
442
+ ).toThrow("值不能小于 0,当前值: -1");
443
+ expect(() =>
444
+ Validation.validateNumberRange(11, "field", { max: 10 })
445
+ ).toThrow("值不能大于 10,当前值: 11");
446
+ });
447
+ });
448
+
449
+ describe("验证数组长度", () => {
450
+ it("应接受长度范围内的数组", () => {
451
+ expect(() =>
452
+ Validation.validateArrayLength([1, 2, 3], "field", { min: 1, max: 10 })
453
+ ).not.toThrow();
454
+ expect(() =>
455
+ Validation.validateArrayLength([1, 2, 3], "field", { min: 3 })
456
+ ).not.toThrow();
457
+ expect(() =>
458
+ Validation.validateArrayLength([1, 2, 3], "field", { max: 10 })
459
+ ).not.toThrow();
460
+ expect(() =>
461
+ Validation.validateArrayLength([1, 2, 3], "field")
462
+ ).not.toThrow();
463
+ });
464
+
465
+ it("应拒绝短于最小长度的数组", () => {
466
+ expect(() =>
467
+ Validation.validateArrayLength([1, 2], "field", { min: 3 })
468
+ ).toThrow(ValidationError);
469
+ });
470
+
471
+ it("应拒绝长于最大长度的数组", () => {
472
+ expect(() =>
473
+ Validation.validateArrayLength([1, 2, 3, 4], "field", { max: 3 })
474
+ ).toThrow(ValidationError);
475
+ });
476
+
477
+ it("应抛出带有正确消息的验证错误", () => {
478
+ expect(() =>
479
+ Validation.validateArrayLength([1, 2], "field", { min: 3 })
480
+ ).toThrow("数组长度不能少于 3,当前长度: 2");
481
+ expect(() =>
482
+ Validation.validateArrayLength([1, 2, 3, 4], "field", { max: 3 })
483
+ ).toThrow("数组长度不能超过 3,当前长度: 4");
484
+ });
485
+ });
486
+
487
+ describe("验证对象属性", () => {
488
+ it("应接受包含所有必需属性的对象", () => {
489
+ const obj = { name: "test", age: 25, city: "NYC" };
490
+ expect(() =>
491
+ Validation.validateObjectProperties(obj, ["name", "age"])
492
+ ).not.toThrow();
493
+ });
494
+
495
+ it("应拒绝缺少必需属性的对象", () => {
496
+ const obj = { name: "test" };
497
+ expect(() =>
498
+ Validation.validateObjectProperties(obj, ["name", "age"])
499
+ ).toThrow(ValidationError);
500
+ });
501
+
502
+ it("应抛出带有正确消息的验证错误", () => {
503
+ const obj = { name: "test" };
504
+ expect(() =>
505
+ Validation.validateObjectProperties(obj, ["name", "age"])
506
+ ).toThrow("缺少必需的属性: age");
507
+ });
508
+ });
509
+
510
+ describe("验证枚举值", () => {
511
+ it("应接受有效的枚举值", () => {
512
+ const validValues = ["option1", "option2", "option3"] as const;
513
+ expect(
514
+ Validation.validateEnum("option1", [...validValues] as const, "field")
515
+ ).toBe("option1");
516
+ expect(
517
+ Validation.validateEnum("option2", [...validValues] as const, "field")
518
+ ).toBe("option2");
519
+ });
520
+
521
+ it("应拒绝无效的枚举值", () => {
522
+ const validValues = ["option1", "option2", "option3"] as const;
523
+ expect(() =>
524
+ Validation.validateEnum("invalid", [...validValues] as const, "field")
525
+ ).toThrow(ValidationError);
526
+ });
527
+
528
+ it("应抛出带有正确消息的验证错误", () => {
529
+ const validValues = ["option1", "option2", "option3"] as const;
530
+ expect(() =>
531
+ Validation.validateEnum("invalid", [...validValues] as const, "field")
532
+ ).toThrow("无效的值: invalid,有效值: option1, option2, option3");
533
+ });
534
+ });
535
+
536
+ describe("验证正则表达式", () => {
537
+ it("应接受有效的正则表达式", () => {
538
+ const result1 = Validation.validateRegex("^test$", "regex");
539
+ expect(result1).toBeInstanceOf(RegExp);
540
+
541
+ const result2 = Validation.validateRegex("\\d+", "regex");
542
+ expect(result2).toBeInstanceOf(RegExp);
543
+ });
544
+
545
+ it("应拒绝无效的正则表达式", () => {
546
+ expect(() => Validation.validateRegex("[invalid", "regex")).toThrow(
547
+ ValidationError
548
+ );
549
+ expect(() => Validation.validateRegex("*invalid", "regex")).toThrow(
550
+ ValidationError
551
+ );
552
+ });
553
+
554
+ it("应抛出带有正确消息的验证错误", () => {
555
+ expect(() => Validation.validateRegex("[invalid", "regex")).toThrow(
556
+ "无效的正则表达式"
557
+ );
558
+ });
559
+ });
560
+ });