code-abyss 1.5.1

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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +197 -0
  3. package/bin/install.js +193 -0
  4. package/bin/uninstall.js +42 -0
  5. package/config/AGENTS.md +247 -0
  6. package/config/CLAUDE.md +207 -0
  7. package/config/settings.example.json +27 -0
  8. package/output-styles/abyss-cultivator.md +399 -0
  9. package/package.json +41 -0
  10. package/skills/SKILL.md +115 -0
  11. package/skills/ai/SKILL.md +29 -0
  12. package/skills/ai/agent-dev.md +242 -0
  13. package/skills/ai/llm-security.md +288 -0
  14. package/skills/architecture/SKILL.md +41 -0
  15. package/skills/architecture/api-design.md +225 -0
  16. package/skills/architecture/caching.md +299 -0
  17. package/skills/architecture/cloud-native.md +285 -0
  18. package/skills/architecture/compliance.md +299 -0
  19. package/skills/architecture/data-security.md +184 -0
  20. package/skills/architecture/message-queue.md +329 -0
  21. package/skills/architecture/security-arch.md +210 -0
  22. package/skills/development/SKILL.md +43 -0
  23. package/skills/development/cpp.md +246 -0
  24. package/skills/development/go.md +323 -0
  25. package/skills/development/java.md +277 -0
  26. package/skills/development/python.md +288 -0
  27. package/skills/development/rust.md +313 -0
  28. package/skills/development/shell.md +313 -0
  29. package/skills/development/typescript.md +277 -0
  30. package/skills/devops/SKILL.md +36 -0
  31. package/skills/devops/cost-optimization.md +272 -0
  32. package/skills/devops/database.md +217 -0
  33. package/skills/devops/devsecops.md +198 -0
  34. package/skills/devops/git-workflow.md +181 -0
  35. package/skills/devops/observability.md +280 -0
  36. package/skills/devops/performance.md +273 -0
  37. package/skills/devops/testing.md +186 -0
  38. package/skills/gen-docs/SKILL.md +114 -0
  39. package/skills/gen-docs/scripts/doc_generator.py +491 -0
  40. package/skills/multi-agent/SKILL.md +268 -0
  41. package/skills/run_skill.py +88 -0
  42. package/skills/security/SKILL.md +51 -0
  43. package/skills/security/blue-team.md +379 -0
  44. package/skills/security/code-audit.md +265 -0
  45. package/skills/security/pentest.md +226 -0
  46. package/skills/security/red-team.md +321 -0
  47. package/skills/security/threat-intel.md +322 -0
  48. package/skills/security/vuln-research.md +369 -0
  49. package/skills/tests/README.md +225 -0
  50. package/skills/tests/SUMMARY.md +362 -0
  51. package/skills/tests/__init__.py +3 -0
  52. package/skills/tests/test_change_analyzer.py +558 -0
  53. package/skills/tests/test_doc_generator.py +538 -0
  54. package/skills/tests/test_module_scanner.py +376 -0
  55. package/skills/tests/test_quality_checker.py +516 -0
  56. package/skills/tests/test_security_scanner.py +426 -0
  57. package/skills/verify-change/SKILL.md +138 -0
  58. package/skills/verify-change/scripts/change_analyzer.py +529 -0
  59. package/skills/verify-module/SKILL.md +125 -0
  60. package/skills/verify-module/scripts/module_scanner.py +321 -0
  61. package/skills/verify-quality/SKILL.md +158 -0
  62. package/skills/verify-quality/scripts/quality_checker.py +481 -0
  63. package/skills/verify-security/SKILL.md +141 -0
  64. package/skills/verify-security/scripts/security_scanner.py +368 -0
@@ -0,0 +1,516 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ verify-quality 单元测试
4
+ 测试代码质量检查器功能
5
+ """
6
+
7
+ import unittest
8
+ import tempfile
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ # 添加 skills 目录到 Python 路径
13
+ sys.path.insert(0, str(Path(__file__).parent.parent / "verify-quality" / "scripts"))
14
+
15
+ from quality_checker import (
16
+ Severity, Issue, FileMetrics, QualityResult, PythonAnalyzer,
17
+ analyze_python_file, analyze_generic_file, scan_directory,
18
+ format_report
19
+ )
20
+
21
+
22
+ class TestQualityChecker(unittest.TestCase):
23
+ """代码质量检查器测试"""
24
+
25
+ def setUp(self):
26
+ """测试前准备"""
27
+ self.temp_dir = tempfile.TemporaryDirectory()
28
+ self.temp_path = Path(self.temp_dir.name)
29
+
30
+ def tearDown(self):
31
+ """测试后清理"""
32
+ self.temp_dir.cleanup()
33
+
34
+ def test_analyze_python_file_basic(self):
35
+ """测试基本 Python 文件分析"""
36
+ test_file = self.temp_path / "test.py"
37
+ test_file.write_text('''
38
+ def hello():
39
+ """Say hello"""
40
+ print("hello")
41
+
42
+ class MyClass:
43
+ """A test class"""
44
+ pass
45
+ ''')
46
+
47
+ metrics, issues = analyze_python_file(test_file)
48
+
49
+ self.assertEqual(metrics.path, str(test_file))
50
+ self.assertGreater(metrics.lines, 0)
51
+ self.assertGreater(metrics.code_lines, 0)
52
+ self.assertEqual(metrics.functions, 1)
53
+ self.assertEqual(metrics.classes, 1)
54
+
55
+ def test_analyze_python_file_with_syntax_error(self):
56
+ """测试语法错误检测"""
57
+ test_file = self.temp_path / "bad.py"
58
+ test_file.write_text('def broken(\n')
59
+
60
+ metrics, issues = analyze_python_file(test_file)
61
+
62
+ self.assertTrue(any(i.severity == Severity.ERROR for i in issues))
63
+ self.assertTrue(any("语法错误" in i.message for i in issues))
64
+
65
+ def test_analyze_python_file_long_function(self):
66
+ """测试长函数检测"""
67
+ test_file = self.temp_path / "long.py"
68
+ lines = ['def long_function():']
69
+ for i in range(60):
70
+ lines.append(f' x{i} = {i}')
71
+ test_file.write_text('\n'.join(lines))
72
+
73
+ metrics, issues = analyze_python_file(test_file)
74
+
75
+ self.assertTrue(any("过长" in i.message for i in issues))
76
+
77
+ def test_analyze_python_file_high_complexity(self):
78
+ """测试高复杂度检测"""
79
+ test_file = self.temp_path / "complex.py"
80
+ test_file.write_text('''
81
+ def complex_function(x):
82
+ if x > 0:
83
+ if x > 10:
84
+ if x > 20:
85
+ if x > 30:
86
+ if x > 40:
87
+ if x > 50:
88
+ if x > 60:
89
+ if x > 70:
90
+ if x > 80:
91
+ if x > 90:
92
+ return "very high"
93
+ return "low"
94
+ ''')
95
+
96
+ metrics, issues = analyze_python_file(test_file)
97
+
98
+ self.assertTrue(any("圈复杂度" in i.message for i in issues))
99
+
100
+ def test_analyze_python_file_too_many_parameters(self):
101
+ """测试参数过多检测"""
102
+ test_file = self.temp_path / "params.py"
103
+ test_file.write_text('def func(a, b, c, d, e, f, g):\n pass')
104
+
105
+ metrics, issues = analyze_python_file(test_file)
106
+
107
+ self.assertTrue(any("参数过多" in i.message for i in issues))
108
+
109
+ def test_analyze_python_file_bad_naming(self):
110
+ """测试命名规范检测"""
111
+ test_file = self.temp_path / "naming.py"
112
+ test_file.write_text('''
113
+ class myClass:
114
+ pass
115
+
116
+ def MyFunction():
117
+ pass
118
+ ''')
119
+
120
+ metrics, issues = analyze_python_file(test_file)
121
+
122
+ # 检查是否有命名相关的问题(类名或函数名)
123
+ naming_issues = [i for i in issues if "命名" in i.message or "PascalCase" in i.message or "snake_case" in i.message]
124
+ self.assertTrue(len(naming_issues) > 0)
125
+
126
+ def test_analyze_python_file_short_function_name(self):
127
+ """测试函数名过短检测"""
128
+ test_file = self.temp_path / "short.py"
129
+ test_file.write_text('def x():\n pass')
130
+
131
+ metrics, issues = analyze_python_file(test_file)
132
+
133
+ self.assertTrue(any("过短" in i.message for i in issues))
134
+
135
+ def test_analyze_python_file_long_lines(self):
136
+ """测试长行检测"""
137
+ test_file = self.temp_path / "longline.py"
138
+ long_line = 'x = "' + 'a' * 150 + '"'
139
+ test_file.write_text(long_line)
140
+
141
+ metrics, issues = analyze_python_file(test_file)
142
+
143
+ self.assertTrue(any("行过长" in i.message for i in issues))
144
+
145
+ def test_analyze_python_file_large_file(self):
146
+ """测试大文件检测"""
147
+ test_file = self.temp_path / "large.py"
148
+ lines = []
149
+ for i in range(600):
150
+ lines.append(f'x{i} = {i}')
151
+ test_file.write_text('\n'.join(lines))
152
+
153
+ metrics, issues = analyze_python_file(test_file)
154
+
155
+ self.assertTrue(any("文件过长" in i.message for i in issues))
156
+
157
+ def test_analyze_python_file_comments(self):
158
+ """测试注释行统计"""
159
+ test_file = self.temp_path / "comments.py"
160
+ test_file.write_text('''
161
+ # This is a comment
162
+ x = 1 # inline comment
163
+ """
164
+ Multi-line
165
+ comment
166
+ """
167
+ y = 2
168
+ ''')
169
+
170
+ metrics, issues = analyze_python_file(test_file)
171
+
172
+ self.assertGreater(metrics.comment_lines, 0)
173
+
174
+ def test_analyze_generic_file(self):
175
+ """测试通用文件分析"""
176
+ test_file = self.temp_path / "test.js"
177
+ test_file.write_text('''
178
+ // Comment
179
+ function hello() {
180
+ console.log("hello");
181
+ }
182
+ ''')
183
+
184
+ metrics, issues = analyze_generic_file(test_file)
185
+
186
+ self.assertEqual(metrics.path, str(test_file))
187
+ self.assertGreater(metrics.lines, 0)
188
+
189
+ def test_scan_directory_basic(self):
190
+ """测试目录扫描"""
191
+ (self.temp_path / "file1.py").write_text('x = 1')
192
+ (self.temp_path / "file2.py").write_text('y = 2')
193
+
194
+ result = scan_directory(str(self.temp_path))
195
+
196
+ self.assertEqual(result.files_scanned, 2)
197
+ self.assertGreater(result.total_lines, 0)
198
+
199
+ def test_scan_directory_empty(self):
200
+ """测试空目录扫描"""
201
+ result = scan_directory(str(self.temp_path))
202
+
203
+ self.assertEqual(result.files_scanned, 0)
204
+
205
+ def test_scan_directory_excludes(self):
206
+ """测试目录排除"""
207
+ (self.temp_path / "src").mkdir()
208
+ (self.temp_path / "src" / "main.py").write_text('x = 1')
209
+
210
+ (self.temp_path / "__pycache__").mkdir()
211
+ (self.temp_path / "__pycache__" / "cache.py").write_text('y = 2')
212
+
213
+ result = scan_directory(str(self.temp_path), exclude_dirs=['__pycache__'])
214
+
215
+ self.assertEqual(result.files_scanned, 1)
216
+
217
+ def test_scan_directory_multiple_languages(self):
218
+ """测试多语言扫描"""
219
+ (self.temp_path / "test.py").write_text('x = 1')
220
+ (self.temp_path / "test.js").write_text('var x = 1;')
221
+ (self.temp_path / "test.go").write_text('package main')
222
+
223
+ result = scan_directory(str(self.temp_path))
224
+
225
+ self.assertEqual(result.files_scanned, 3)
226
+
227
+ def test_quality_result_passed_property(self):
228
+ """测试 QualityResult.passed 属性"""
229
+ result = QualityResult(scan_path="/test")
230
+
231
+ # 没有错误时应该通过
232
+ self.assertTrue(result.passed)
233
+
234
+ # 添加警告
235
+ result.issues.append(Issue(
236
+ severity=Severity.WARNING,
237
+ category="test",
238
+ message="test warning",
239
+ file_path="test.py"
240
+ ))
241
+ self.assertTrue(result.passed)
242
+
243
+ # 添加错误
244
+ result.issues.append(Issue(
245
+ severity=Severity.ERROR,
246
+ category="test",
247
+ message="test error",
248
+ file_path="test.py"
249
+ ))
250
+ self.assertFalse(result.passed)
251
+
252
+ def test_quality_result_counts(self):
253
+ """测试问题计数"""
254
+ result = QualityResult(scan_path="/test")
255
+
256
+ result.issues.append(Issue(
257
+ severity=Severity.ERROR,
258
+ category="test",
259
+ message="error",
260
+ file_path="test.py"
261
+ ))
262
+ result.issues.append(Issue(
263
+ severity=Severity.WARNING,
264
+ category="test",
265
+ message="warning",
266
+ file_path="test.py"
267
+ ))
268
+
269
+ self.assertEqual(result.error_count, 1)
270
+ self.assertEqual(result.warning_count, 1)
271
+
272
+ def test_file_metrics_dataclass(self):
273
+ """测试 FileMetrics 数据类"""
274
+ metrics = FileMetrics(
275
+ path="/test/file.py",
276
+ lines=100,
277
+ code_lines=80,
278
+ comment_lines=10,
279
+ blank_lines=10,
280
+ functions=5,
281
+ classes=2
282
+ )
283
+
284
+ self.assertEqual(metrics.path, "/test/file.py")
285
+ self.assertEqual(metrics.lines, 100)
286
+ self.assertEqual(metrics.functions, 5)
287
+
288
+ def test_issue_dataclass(self):
289
+ """测试 Issue 数据类"""
290
+ issue = Issue(
291
+ severity=Severity.WARNING,
292
+ category="复杂度",
293
+ message="函数过长",
294
+ file_path="test.py",
295
+ line_number=10,
296
+ suggestion="拆分函数"
297
+ )
298
+
299
+ self.assertEqual(issue.severity, Severity.WARNING)
300
+ self.assertEqual(issue.category, "复杂度")
301
+ self.assertEqual(issue.line_number, 10)
302
+
303
+ def test_severity_enum(self):
304
+ """测试 Severity 枚举"""
305
+ self.assertEqual(Severity.ERROR.value, "error")
306
+ self.assertEqual(Severity.WARNING.value, "warning")
307
+ self.assertEqual(Severity.INFO.value, "info")
308
+
309
+ def test_format_report_basic(self):
310
+ """测试报告格式化"""
311
+ result = QualityResult(scan_path="/test", files_scanned=5, total_lines=500)
312
+
313
+ report = format_report(result)
314
+
315
+ self.assertIn("代码质量检查报告", report)
316
+ self.assertIn("/test", report)
317
+ self.assertIn("5", report)
318
+
319
+ def test_format_report_with_issues(self):
320
+ """测试包含问题的报告"""
321
+ result = QualityResult(scan_path="/test")
322
+ result.issues.append(Issue(
323
+ severity=Severity.WARNING,
324
+ category="复杂度",
325
+ message="函数过长",
326
+ file_path="test.py",
327
+ line_number=10,
328
+ suggestion="拆分函数"
329
+ ))
330
+
331
+ report = format_report(result, verbose=True)
332
+
333
+ self.assertIn("函数过长", report)
334
+ self.assertIn("test.py", report)
335
+
336
+ def test_python_analyzer_basic(self):
337
+ """测试 Python 分析器"""
338
+ source = '''
339
+ def hello():
340
+ """Say hello"""
341
+ print("hello")
342
+
343
+ class MyClass:
344
+ """A test class"""
345
+ pass
346
+ '''
347
+
348
+ analyzer = PythonAnalyzer("test.py", source)
349
+ issues, functions, classes, complexity = analyzer.analyze()
350
+
351
+ self.assertEqual(len(functions), 1)
352
+ self.assertEqual(len(classes), 1)
353
+
354
+ def test_python_analyzer_syntax_error(self):
355
+ """测试语法错误处理"""
356
+ source = 'def broken(\n'
357
+
358
+ analyzer = PythonAnalyzer("test.py", source)
359
+ issues, functions, classes, complexity = analyzer.analyze()
360
+
361
+ self.assertTrue(any(i.severity == Severity.ERROR for i in issues))
362
+
363
+ def test_python_analyzer_unittest_setup_teardown_naming(self):
364
+ """测试 unittest 生命周期函数不应命名告警"""
365
+ source = '''
366
+ class DemoTest:
367
+ def setUp(self):
368
+ pass
369
+
370
+ def tearDown(self):
371
+ pass
372
+ '''
373
+
374
+ analyzer = PythonAnalyzer("test.py", source)
375
+ issues, functions, classes, complexity = analyzer.analyze()
376
+
377
+ self.assertFalse(any("setUp" in i.message for i in issues))
378
+ self.assertFalse(any("tearDown" in i.message for i in issues))
379
+
380
+ def test_python_analyzer_ast_visitor_naming(self):
381
+ """测试 AST visitor 方法不应命名告警"""
382
+ source = '''
383
+ class MyVisitor:
384
+ def visit_FunctionDef(self, node):
385
+ return node
386
+ '''
387
+
388
+ analyzer = PythonAnalyzer("visitor.py", source)
389
+ issues, functions, classes, complexity = analyzer.analyze()
390
+
391
+ self.assertFalse(any("visit_FunctionDef" in i.message for i in issues))
392
+
393
+
394
+ class TestQualityCheckerEdgeCases(unittest.TestCase):
395
+ """代码质量检查器边界条件测试"""
396
+
397
+ def setUp(self):
398
+ """测试前准备"""
399
+ self.temp_dir = tempfile.TemporaryDirectory()
400
+ self.temp_path = Path(self.temp_dir.name)
401
+
402
+ def tearDown(self):
403
+ """测试后清理"""
404
+ self.temp_dir.cleanup()
405
+
406
+ def test_analyze_empty_file(self):
407
+ """测试空文件分析"""
408
+ test_file = self.temp_path / "empty.py"
409
+ test_file.write_text('')
410
+
411
+ metrics, issues = analyze_python_file(test_file)
412
+
413
+ self.assertEqual(metrics.lines, 1) # 空文件有一行
414
+
415
+ def test_analyze_file_with_only_comments(self):
416
+ """测试仅包含注释的文件"""
417
+ test_file = self.temp_path / "comments.py"
418
+ test_file.write_text('''
419
+ # Comment 1
420
+ # Comment 2
421
+ # Comment 3
422
+ ''')
423
+
424
+ metrics, issues = analyze_python_file(test_file)
425
+
426
+ self.assertEqual(metrics.code_lines, 0)
427
+ self.assertGreater(metrics.comment_lines, 0)
428
+
429
+ def test_analyze_file_with_special_characters(self):
430
+ """测试包含特殊字符的文件"""
431
+ test_file = self.temp_path / "special.py"
432
+ test_file.write_text('''
433
+ # 中文注释
434
+ def 函数():
435
+ """中文文档"""
436
+ pass
437
+ ''')
438
+
439
+ metrics, issues = analyze_python_file(test_file)
440
+
441
+ self.assertIsInstance(metrics, FileMetrics)
442
+
443
+ def test_scan_deeply_nested(self):
444
+ """测试深层嵌套目录"""
445
+ deep_path = self.temp_path / "a" / "b" / "c" / "d"
446
+ deep_path.mkdir(parents=True)
447
+ (deep_path / "test.py").write_text('x = 1')
448
+
449
+ result = scan_directory(str(self.temp_path))
450
+
451
+ self.assertEqual(result.files_scanned, 1)
452
+
453
+ def test_analyze_file_with_encoding_error(self):
454
+ """测试编码错误处理"""
455
+ test_file = self.temp_path / "binary.bin"
456
+ test_file.write_bytes(b'\x80\x81\x82\x83')
457
+
458
+ metrics, issues = analyze_generic_file(test_file)
459
+
460
+ # 应该优雅地处理
461
+ self.assertIsInstance(metrics, FileMetrics)
462
+
463
+ def test_analyze_very_long_function(self):
464
+ """测试超长函数"""
465
+ test_file = self.temp_path / "very_long.py"
466
+ lines = ['def very_long_function():']
467
+ for i in range(1000):
468
+ lines.append(f' x{i} = {i}')
469
+ test_file.write_text('\n'.join(lines))
470
+
471
+ metrics, issues = analyze_python_file(test_file)
472
+
473
+ self.assertTrue(any("过长" in i.message for i in issues))
474
+
475
+ def test_analyze_many_functions(self):
476
+ """测试包含多个函数的文件"""
477
+ test_file = self.temp_path / "many.py"
478
+ lines = []
479
+ for i in range(50):
480
+ lines.append(f'def func{i}():\n pass\n')
481
+ test_file.write_text('\n'.join(lines))
482
+
483
+ metrics, issues = analyze_python_file(test_file)
484
+
485
+ self.assertEqual(metrics.functions, 50)
486
+
487
+ def test_scan_mixed_file_types(self):
488
+ """测试混合文件类型"""
489
+ (self.temp_path / "test.py").write_text('x = 1')
490
+ (self.temp_path / "test.js").write_text('var x = 1;')
491
+ (self.temp_path / "test.txt").write_text('text')
492
+ (self.temp_path / "test.md").write_text('# Markdown')
493
+
494
+ result = scan_directory(str(self.temp_path))
495
+
496
+ # 只应该扫描代码文件
497
+ self.assertEqual(result.files_scanned, 2)
498
+
499
+ def test_format_report_verbose(self):
500
+ """测试详细报告"""
501
+ result = QualityResult(scan_path="/test", files_scanned=1)
502
+ result.file_metrics.append(FileMetrics(
503
+ path="/test/file.py",
504
+ lines=100,
505
+ code_lines=80,
506
+ functions=5,
507
+ max_complexity=8
508
+ ))
509
+
510
+ report = format_report(result, verbose=True)
511
+
512
+ self.assertIn("复杂度", report)
513
+
514
+
515
+ if __name__ == '__main__':
516
+ unittest.main()