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.
- package/LICENSE +21 -0
- package/README.md +197 -0
- package/bin/install.js +193 -0
- package/bin/uninstall.js +42 -0
- package/config/AGENTS.md +247 -0
- package/config/CLAUDE.md +207 -0
- package/config/settings.example.json +27 -0
- package/output-styles/abyss-cultivator.md +399 -0
- package/package.json +41 -0
- package/skills/SKILL.md +115 -0
- package/skills/ai/SKILL.md +29 -0
- package/skills/ai/agent-dev.md +242 -0
- package/skills/ai/llm-security.md +288 -0
- package/skills/architecture/SKILL.md +41 -0
- package/skills/architecture/api-design.md +225 -0
- package/skills/architecture/caching.md +299 -0
- package/skills/architecture/cloud-native.md +285 -0
- package/skills/architecture/compliance.md +299 -0
- package/skills/architecture/data-security.md +184 -0
- package/skills/architecture/message-queue.md +329 -0
- package/skills/architecture/security-arch.md +210 -0
- package/skills/development/SKILL.md +43 -0
- package/skills/development/cpp.md +246 -0
- package/skills/development/go.md +323 -0
- package/skills/development/java.md +277 -0
- package/skills/development/python.md +288 -0
- package/skills/development/rust.md +313 -0
- package/skills/development/shell.md +313 -0
- package/skills/development/typescript.md +277 -0
- package/skills/devops/SKILL.md +36 -0
- package/skills/devops/cost-optimization.md +272 -0
- package/skills/devops/database.md +217 -0
- package/skills/devops/devsecops.md +198 -0
- package/skills/devops/git-workflow.md +181 -0
- package/skills/devops/observability.md +280 -0
- package/skills/devops/performance.md +273 -0
- package/skills/devops/testing.md +186 -0
- package/skills/gen-docs/SKILL.md +114 -0
- package/skills/gen-docs/scripts/doc_generator.py +491 -0
- package/skills/multi-agent/SKILL.md +268 -0
- package/skills/run_skill.py +88 -0
- package/skills/security/SKILL.md +51 -0
- package/skills/security/blue-team.md +379 -0
- package/skills/security/code-audit.md +265 -0
- package/skills/security/pentest.md +226 -0
- package/skills/security/red-team.md +321 -0
- package/skills/security/threat-intel.md +322 -0
- package/skills/security/vuln-research.md +369 -0
- package/skills/tests/README.md +225 -0
- package/skills/tests/SUMMARY.md +362 -0
- package/skills/tests/__init__.py +3 -0
- package/skills/tests/test_change_analyzer.py +558 -0
- package/skills/tests/test_doc_generator.py +538 -0
- package/skills/tests/test_module_scanner.py +376 -0
- package/skills/tests/test_quality_checker.py +516 -0
- package/skills/tests/test_security_scanner.py +426 -0
- package/skills/verify-change/SKILL.md +138 -0
- package/skills/verify-change/scripts/change_analyzer.py +529 -0
- package/skills/verify-module/SKILL.md +125 -0
- package/skills/verify-module/scripts/module_scanner.py +321 -0
- package/skills/verify-quality/SKILL.md +158 -0
- package/skills/verify-quality/scripts/quality_checker.py +481 -0
- package/skills/verify-security/SKILL.md +141 -0
- package/skills/verify-security/scripts/security_scanner.py +368 -0
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
gen-docs 单元测试
|
|
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 / "gen-docs" / "scripts"))
|
|
14
|
+
|
|
15
|
+
from doc_generator import (
|
|
16
|
+
ModuleInfo, detect_language, analyze_python_module, analyze_module,
|
|
17
|
+
generate_readme, generate_design, generate_docs
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestDocGenerator(unittest.TestCase):
|
|
22
|
+
"""文档生成器测试"""
|
|
23
|
+
|
|
24
|
+
def setUp(self):
|
|
25
|
+
"""测试前准备"""
|
|
26
|
+
self.temp_dir = tempfile.TemporaryDirectory()
|
|
27
|
+
self.temp_path = Path(self.temp_dir.name)
|
|
28
|
+
|
|
29
|
+
def tearDown(self):
|
|
30
|
+
"""测试后清理"""
|
|
31
|
+
self.temp_dir.cleanup()
|
|
32
|
+
|
|
33
|
+
def test_detect_language_python(self):
|
|
34
|
+
"""测试 Python 语言检测"""
|
|
35
|
+
(self.temp_path / "main.py").write_text("print('hello')")
|
|
36
|
+
(self.temp_path / "utils.py").write_text("def util(): pass")
|
|
37
|
+
|
|
38
|
+
language = detect_language(self.temp_path)
|
|
39
|
+
|
|
40
|
+
self.assertEqual(language, "Python")
|
|
41
|
+
|
|
42
|
+
def test_detect_language_go(self):
|
|
43
|
+
"""测试 Go 语言检测"""
|
|
44
|
+
(self.temp_path / "main.go").write_text("package main")
|
|
45
|
+
(self.temp_path / "utils.go").write_text("package main")
|
|
46
|
+
|
|
47
|
+
language = detect_language(self.temp_path)
|
|
48
|
+
|
|
49
|
+
self.assertEqual(language, "Go")
|
|
50
|
+
|
|
51
|
+
def test_detect_language_rust(self):
|
|
52
|
+
"""测试 Rust 语言检测"""
|
|
53
|
+
(self.temp_path / "main.rs").write_text("fn main() {}")
|
|
54
|
+
(self.temp_path / "lib.rs").write_text("pub fn util() {}")
|
|
55
|
+
|
|
56
|
+
language = detect_language(self.temp_path)
|
|
57
|
+
|
|
58
|
+
self.assertEqual(language, "Rust")
|
|
59
|
+
|
|
60
|
+
def test_detect_language_typescript(self):
|
|
61
|
+
"""测试 TypeScript 语言检测"""
|
|
62
|
+
(self.temp_path / "main.ts").write_text("console.log('hello')")
|
|
63
|
+
(self.temp_path / "utils.ts").write_text("export function util() {}")
|
|
64
|
+
|
|
65
|
+
language = detect_language(self.temp_path)
|
|
66
|
+
|
|
67
|
+
self.assertEqual(language, "TypeScript")
|
|
68
|
+
|
|
69
|
+
def test_detect_language_javascript(self):
|
|
70
|
+
"""测试 JavaScript 语言检测"""
|
|
71
|
+
(self.temp_path / "main.js").write_text("console.log('hello')")
|
|
72
|
+
|
|
73
|
+
language = detect_language(self.temp_path)
|
|
74
|
+
|
|
75
|
+
self.assertEqual(language, "JavaScript")
|
|
76
|
+
|
|
77
|
+
def test_detect_language_java(self):
|
|
78
|
+
"""测试 Java 语言检测"""
|
|
79
|
+
(self.temp_path / "Main.java").write_text("public class Main {}")
|
|
80
|
+
|
|
81
|
+
language = detect_language(self.temp_path)
|
|
82
|
+
|
|
83
|
+
self.assertEqual(language, "Java")
|
|
84
|
+
|
|
85
|
+
def test_detect_language_empty_directory(self):
|
|
86
|
+
"""测试空目录语言检测"""
|
|
87
|
+
language = detect_language(self.temp_path)
|
|
88
|
+
|
|
89
|
+
self.assertEqual(language, "Unknown")
|
|
90
|
+
|
|
91
|
+
def test_analyze_python_module_basic(self):
|
|
92
|
+
"""测试基本 Python 模块分析"""
|
|
93
|
+
(self.temp_path / "main.py").write_text('''
|
|
94
|
+
"""Module docstring"""
|
|
95
|
+
|
|
96
|
+
def hello():
|
|
97
|
+
"""Say hello"""
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
class MyClass:
|
|
101
|
+
"""A test class"""
|
|
102
|
+
pass
|
|
103
|
+
''')
|
|
104
|
+
|
|
105
|
+
info = analyze_python_module(self.temp_path)
|
|
106
|
+
|
|
107
|
+
self.assertEqual(info.name, self.temp_path.name)
|
|
108
|
+
self.assertEqual(info.language, "Python")
|
|
109
|
+
self.assertGreater(len(info.files), 0)
|
|
110
|
+
self.assertEqual(len(info.functions), 1)
|
|
111
|
+
self.assertEqual(len(info.classes), 1)
|
|
112
|
+
|
|
113
|
+
def test_analyze_python_module_with_dependencies(self):
|
|
114
|
+
"""测试 Python 模块依赖检测"""
|
|
115
|
+
(self.temp_path / "main.py").write_text("import requests")
|
|
116
|
+
(self.temp_path / "requirements.txt").write_text('''
|
|
117
|
+
requests==2.28.0
|
|
118
|
+
numpy>=1.20.0
|
|
119
|
+
pandas
|
|
120
|
+
''')
|
|
121
|
+
|
|
122
|
+
info = analyze_python_module(self.temp_path)
|
|
123
|
+
|
|
124
|
+
self.assertGreater(len(info.dependencies), 0)
|
|
125
|
+
self.assertIn("requests", info.dependencies)
|
|
126
|
+
|
|
127
|
+
def test_analyze_python_module_entry_points(self):
|
|
128
|
+
"""测试 Python 模块入口点检测"""
|
|
129
|
+
(self.temp_path / "main.py").write_text("if __name__ == '__main__': pass")
|
|
130
|
+
(self.temp_path / "__main__.py").write_text("print('hello')")
|
|
131
|
+
|
|
132
|
+
info = analyze_python_module(self.temp_path)
|
|
133
|
+
|
|
134
|
+
self.assertGreater(len(info.entry_points), 0)
|
|
135
|
+
|
|
136
|
+
def test_analyze_python_module_ignores_tests(self):
|
|
137
|
+
"""测试忽略测试文件"""
|
|
138
|
+
(self.temp_path / "main.py").write_text('''
|
|
139
|
+
def hello():
|
|
140
|
+
pass
|
|
141
|
+
''')
|
|
142
|
+
(self.temp_path / "test_main.py").write_text('''
|
|
143
|
+
def test_hello():
|
|
144
|
+
pass
|
|
145
|
+
''')
|
|
146
|
+
|
|
147
|
+
info = analyze_python_module(self.temp_path)
|
|
148
|
+
|
|
149
|
+
# 应该只有 main.py 中的函数
|
|
150
|
+
self.assertEqual(len(info.functions), 1)
|
|
151
|
+
|
|
152
|
+
def test_analyze_python_module_with_pyproject(self):
|
|
153
|
+
"""测试 pyproject.toml 依赖检测"""
|
|
154
|
+
(self.temp_path / "main.py").write_text("x = 1")
|
|
155
|
+
(self.temp_path / "pyproject.toml").write_text('''
|
|
156
|
+
[project]
|
|
157
|
+
dependencies = [
|
|
158
|
+
"requests",
|
|
159
|
+
"numpy"
|
|
160
|
+
]
|
|
161
|
+
''')
|
|
162
|
+
|
|
163
|
+
info = analyze_python_module(self.temp_path)
|
|
164
|
+
|
|
165
|
+
# pyproject.toml 应该被识别
|
|
166
|
+
self.assertIsInstance(info, ModuleInfo)
|
|
167
|
+
|
|
168
|
+
def test_analyze_module_python(self):
|
|
169
|
+
"""测试通用模块分析 - Python"""
|
|
170
|
+
(self.temp_path / "main.py").write_text("x = 1")
|
|
171
|
+
|
|
172
|
+
info = analyze_module(self.temp_path)
|
|
173
|
+
|
|
174
|
+
self.assertEqual(info.language, "Python")
|
|
175
|
+
|
|
176
|
+
def test_analyze_module_go(self):
|
|
177
|
+
"""测试通用模块分析 - Go"""
|
|
178
|
+
(self.temp_path / "main.go").write_text("package main")
|
|
179
|
+
|
|
180
|
+
info = analyze_module(self.temp_path)
|
|
181
|
+
|
|
182
|
+
self.assertEqual(info.language, "Go")
|
|
183
|
+
|
|
184
|
+
def test_analyze_module_mixed_languages(self):
|
|
185
|
+
"""测试混合语言模块"""
|
|
186
|
+
(self.temp_path / "main.py").write_text("x = 1")
|
|
187
|
+
(self.temp_path / "main.go").write_text("package main")
|
|
188
|
+
(self.temp_path / "main.rs").write_text("fn main() {}")
|
|
189
|
+
|
|
190
|
+
info = analyze_module(self.temp_path)
|
|
191
|
+
|
|
192
|
+
# 应该检测到主要语言
|
|
193
|
+
self.assertIn(info.language, ["Python", "Go", "Rust"])
|
|
194
|
+
|
|
195
|
+
def test_generate_readme_basic(self):
|
|
196
|
+
"""测试基本 README 生成"""
|
|
197
|
+
info = ModuleInfo(
|
|
198
|
+
name="TestModule",
|
|
199
|
+
path=str(self.temp_path),
|
|
200
|
+
description="A test module",
|
|
201
|
+
language="Python"
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
readme = generate_readme(info)
|
|
205
|
+
|
|
206
|
+
self.assertIn("# TestModule", readme)
|
|
207
|
+
self.assertIn("A test module", readme)
|
|
208
|
+
self.assertIn("## 概述", readme)
|
|
209
|
+
self.assertIn("## 使用方法", readme)
|
|
210
|
+
|
|
211
|
+
def test_generate_readme_with_dependencies(self):
|
|
212
|
+
"""测试包含依赖的 README 生成"""
|
|
213
|
+
info = ModuleInfo(
|
|
214
|
+
name="TestModule",
|
|
215
|
+
path=str(self.temp_path),
|
|
216
|
+
language="Python",
|
|
217
|
+
dependencies=["requests", "numpy", "pandas"]
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
readme = generate_readme(info)
|
|
221
|
+
|
|
222
|
+
self.assertIn("## 依赖", readme)
|
|
223
|
+
self.assertIn("requests", readme)
|
|
224
|
+
|
|
225
|
+
def test_generate_readme_with_api(self):
|
|
226
|
+
"""测试包含 API 的 README 生成"""
|
|
227
|
+
info = ModuleInfo(
|
|
228
|
+
name="TestModule",
|
|
229
|
+
path=str(self.temp_path),
|
|
230
|
+
language="Python",
|
|
231
|
+
classes=[{"name": "MyClass", "doc": "A test class"}],
|
|
232
|
+
functions=[{"name": "my_func", "doc": "A test function"}]
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
readme = generate_readme(info)
|
|
236
|
+
|
|
237
|
+
self.assertIn("## API 概览", readme)
|
|
238
|
+
self.assertIn("MyClass", readme)
|
|
239
|
+
self.assertIn("my_func", readme)
|
|
240
|
+
|
|
241
|
+
def test_generate_readme_with_files(self):
|
|
242
|
+
"""测试包含文件列表的 README 生成"""
|
|
243
|
+
info = ModuleInfo(
|
|
244
|
+
name="TestModule",
|
|
245
|
+
path=str(self.temp_path),
|
|
246
|
+
language="Python",
|
|
247
|
+
files=["main.py", "utils.py", "config.py"]
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
readme = generate_readme(info)
|
|
251
|
+
|
|
252
|
+
self.assertIn("## 目录结构", readme)
|
|
253
|
+
self.assertIn("main.py", readme)
|
|
254
|
+
|
|
255
|
+
def test_generate_design_basic(self):
|
|
256
|
+
"""测试基本 DESIGN 生成"""
|
|
257
|
+
info = ModuleInfo(
|
|
258
|
+
name="TestModule",
|
|
259
|
+
path=str(self.temp_path),
|
|
260
|
+
language="Python"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
design = generate_design(info)
|
|
264
|
+
|
|
265
|
+
self.assertIn("# TestModule 设计文档", design)
|
|
266
|
+
self.assertIn("## 设计概述", design)
|
|
267
|
+
self.assertIn("## 架构设计", design)
|
|
268
|
+
self.assertIn("## 设计决策", design)
|
|
269
|
+
self.assertIn("## 权衡取舍", design)
|
|
270
|
+
self.assertIn("## 安全考量", design)
|
|
271
|
+
self.assertIn("## 变更历史", design)
|
|
272
|
+
|
|
273
|
+
def test_generate_design_with_components(self):
|
|
274
|
+
"""测试包含组件的 DESIGN 生成"""
|
|
275
|
+
info = ModuleInfo(
|
|
276
|
+
name="TestModule",
|
|
277
|
+
path=str(self.temp_path),
|
|
278
|
+
language="Python",
|
|
279
|
+
classes=[
|
|
280
|
+
{"name": "Parser", "doc": "Parse input"},
|
|
281
|
+
{"name": "Processor", "doc": "Process data"}
|
|
282
|
+
]
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
design = generate_design(info)
|
|
286
|
+
|
|
287
|
+
self.assertIn("### 核心组件", design)
|
|
288
|
+
self.assertIn("Parser", design)
|
|
289
|
+
self.assertIn("Processor", design)
|
|
290
|
+
|
|
291
|
+
def test_generate_design_with_dependencies(self):
|
|
292
|
+
"""测试包含依赖的 DESIGN 生成"""
|
|
293
|
+
info = ModuleInfo(
|
|
294
|
+
name="TestModule",
|
|
295
|
+
path=str(self.temp_path),
|
|
296
|
+
language="Python",
|
|
297
|
+
dependencies=["requests", "numpy"]
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
design = generate_design(info)
|
|
301
|
+
|
|
302
|
+
self.assertIn("### 技术选型", design)
|
|
303
|
+
self.assertIn("requests", design)
|
|
304
|
+
|
|
305
|
+
def test_generate_docs_nonexistent_path(self):
|
|
306
|
+
"""测试不存在的路径"""
|
|
307
|
+
nonexistent = self.temp_path / "nonexistent"
|
|
308
|
+
|
|
309
|
+
result = generate_docs(str(nonexistent))
|
|
310
|
+
|
|
311
|
+
self.assertEqual(result["status"], "error")
|
|
312
|
+
self.assertTrue(any("不存在" in msg for msg in result["messages"]))
|
|
313
|
+
|
|
314
|
+
def test_generate_docs_creates_files(self):
|
|
315
|
+
"""测试文档文件创建"""
|
|
316
|
+
(self.temp_path / "main.py").write_text("x = 1")
|
|
317
|
+
|
|
318
|
+
result = generate_docs(str(self.temp_path), force=True)
|
|
319
|
+
|
|
320
|
+
self.assertEqual(result["status"], "success")
|
|
321
|
+
self.assertTrue((self.temp_path / "README.md").exists())
|
|
322
|
+
self.assertTrue((self.temp_path / "DESIGN.md").exists())
|
|
323
|
+
|
|
324
|
+
def test_generate_docs_respects_existing_files(self):
|
|
325
|
+
"""测试尊重已存在的文件"""
|
|
326
|
+
(self.temp_path / "main.py").write_text("x = 1")
|
|
327
|
+
(self.temp_path / "README.md").write_text("# Existing README")
|
|
328
|
+
|
|
329
|
+
result = generate_docs(str(self.temp_path), force=False)
|
|
330
|
+
|
|
331
|
+
# 不应该覆盖
|
|
332
|
+
content = (self.temp_path / "README.md").read_text()
|
|
333
|
+
self.assertEqual(content, "# Existing README")
|
|
334
|
+
|
|
335
|
+
def test_generate_docs_force_overwrite(self):
|
|
336
|
+
"""测试强制覆盖"""
|
|
337
|
+
(self.temp_path / "main.py").write_text("x = 1")
|
|
338
|
+
(self.temp_path / "README.md").write_text("# Old README")
|
|
339
|
+
|
|
340
|
+
result = generate_docs(str(self.temp_path), force=True)
|
|
341
|
+
|
|
342
|
+
# 应该被覆盖
|
|
343
|
+
content = (self.temp_path / "README.md").read_text()
|
|
344
|
+
self.assertNotEqual(content, "# Old README")
|
|
345
|
+
|
|
346
|
+
def test_module_info_dataclass(self):
|
|
347
|
+
"""测试 ModuleInfo 数据类"""
|
|
348
|
+
info = ModuleInfo(
|
|
349
|
+
name="TestModule",
|
|
350
|
+
path="/test/path",
|
|
351
|
+
description="Test description",
|
|
352
|
+
language="Python",
|
|
353
|
+
files=["main.py"],
|
|
354
|
+
dependencies=["requests"]
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
self.assertEqual(info.name, "TestModule")
|
|
358
|
+
self.assertEqual(info.language, "Python")
|
|
359
|
+
self.assertEqual(len(info.files), 1)
|
|
360
|
+
self.assertEqual(len(info.dependencies), 1)
|
|
361
|
+
|
|
362
|
+
def test_generate_readme_structure(self):
|
|
363
|
+
"""测试 README 结构完整性"""
|
|
364
|
+
info = ModuleInfo(
|
|
365
|
+
name="TestModule",
|
|
366
|
+
path=str(self.temp_path),
|
|
367
|
+
language="Python"
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
readme = generate_readme(info)
|
|
371
|
+
|
|
372
|
+
# 检查必要的章节
|
|
373
|
+
sections = [
|
|
374
|
+
"# TestModule",
|
|
375
|
+
"## 概述",
|
|
376
|
+
"## 特性",
|
|
377
|
+
"## 使用方法",
|
|
378
|
+
"## 目录结构",
|
|
379
|
+
"## 相关文档"
|
|
380
|
+
]
|
|
381
|
+
|
|
382
|
+
for section in sections:
|
|
383
|
+
self.assertIn(section, readme)
|
|
384
|
+
|
|
385
|
+
def test_generate_design_structure(self):
|
|
386
|
+
"""测试 DESIGN 结构完整性"""
|
|
387
|
+
info = ModuleInfo(
|
|
388
|
+
name="TestModule",
|
|
389
|
+
path=str(self.temp_path),
|
|
390
|
+
language="Python"
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
design = generate_design(info)
|
|
394
|
+
|
|
395
|
+
# 检查必要的章节
|
|
396
|
+
sections = [
|
|
397
|
+
"# TestModule 设计文档",
|
|
398
|
+
"## 设计概述",
|
|
399
|
+
"## 架构设计",
|
|
400
|
+
"## 设计决策",
|
|
401
|
+
"## 权衡取舍",
|
|
402
|
+
"## 安全考量",
|
|
403
|
+
"## 变更历史"
|
|
404
|
+
]
|
|
405
|
+
|
|
406
|
+
for section in sections:
|
|
407
|
+
self.assertIn(section, design)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
class TestDocGeneratorEdgeCases(unittest.TestCase):
|
|
411
|
+
"""文档生成器边界条件测试"""
|
|
412
|
+
|
|
413
|
+
def setUp(self):
|
|
414
|
+
"""测试前准备"""
|
|
415
|
+
self.temp_dir = tempfile.TemporaryDirectory()
|
|
416
|
+
self.temp_path = Path(self.temp_dir.name)
|
|
417
|
+
|
|
418
|
+
def tearDown(self):
|
|
419
|
+
"""测试后清理"""
|
|
420
|
+
self.temp_dir.cleanup()
|
|
421
|
+
|
|
422
|
+
def test_analyze_module_deeply_nested(self):
|
|
423
|
+
"""测试深层嵌套模块"""
|
|
424
|
+
deep_path = self.temp_path / "a" / "b" / "c"
|
|
425
|
+
deep_path.mkdir(parents=True)
|
|
426
|
+
(deep_path / "main.py").write_text("x = 1")
|
|
427
|
+
|
|
428
|
+
info = analyze_module(deep_path)
|
|
429
|
+
|
|
430
|
+
self.assertIsInstance(info, ModuleInfo)
|
|
431
|
+
|
|
432
|
+
def test_analyze_module_with_special_characters(self):
|
|
433
|
+
"""测试包含特殊字符的模块"""
|
|
434
|
+
(self.temp_path / "文件.py").write_text("x = 1")
|
|
435
|
+
|
|
436
|
+
info = analyze_module(self.temp_path)
|
|
437
|
+
|
|
438
|
+
self.assertIsInstance(info, ModuleInfo)
|
|
439
|
+
|
|
440
|
+
def test_generate_readme_empty_module(self):
|
|
441
|
+
"""测试空模块的 README 生成"""
|
|
442
|
+
info = ModuleInfo(
|
|
443
|
+
name="EmptyModule",
|
|
444
|
+
path=str(self.temp_path),
|
|
445
|
+
language="Unknown"
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
readme = generate_readme(info)
|
|
449
|
+
|
|
450
|
+
self.assertIn("# EmptyModule", readme)
|
|
451
|
+
# 检查是否包含占位符或说明
|
|
452
|
+
self.assertTrue(any(keyword in readme for keyword in ["请", "TODO", "示例", "特性"]))
|
|
453
|
+
|
|
454
|
+
def test_generate_design_empty_module(self):
|
|
455
|
+
"""测试空模块的 DESIGN 生成"""
|
|
456
|
+
info = ModuleInfo(
|
|
457
|
+
name="EmptyModule",
|
|
458
|
+
path=str(self.temp_path),
|
|
459
|
+
language="Unknown"
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
design = generate_design(info)
|
|
463
|
+
|
|
464
|
+
self.assertIn("# EmptyModule 设计文档", design)
|
|
465
|
+
# 检查是否包含占位符或说明
|
|
466
|
+
self.assertTrue(any(keyword in design for keyword in ["请", "TODO", "设计", "决策"]))
|
|
467
|
+
|
|
468
|
+
def test_analyze_python_module_with_syntax_error(self):
|
|
469
|
+
"""测试包含语法错误的 Python 模块"""
|
|
470
|
+
(self.temp_path / "bad.py").write_text("def broken(\n")
|
|
471
|
+
(self.temp_path / "good.py").write_text("def hello(): pass")
|
|
472
|
+
|
|
473
|
+
info = analyze_python_module(self.temp_path)
|
|
474
|
+
|
|
475
|
+
# 应该优雅地处理语法错误
|
|
476
|
+
self.assertIsInstance(info, ModuleInfo)
|
|
477
|
+
|
|
478
|
+
def test_analyze_python_module_large_file(self):
|
|
479
|
+
"""测试包含大文件的 Python 模块"""
|
|
480
|
+
lines = []
|
|
481
|
+
for i in range(1000):
|
|
482
|
+
lines.append(f"def func{i}(): pass")
|
|
483
|
+
(self.temp_path / "large.py").write_text("\n".join(lines))
|
|
484
|
+
|
|
485
|
+
info = analyze_python_module(self.temp_path)
|
|
486
|
+
|
|
487
|
+
self.assertGreater(len(info.functions), 0)
|
|
488
|
+
|
|
489
|
+
def test_generate_docs_with_many_files(self):
|
|
490
|
+
"""测试包含多个文件的模块"""
|
|
491
|
+
for i in range(50):
|
|
492
|
+
(self.temp_path / f"file{i}.py").write_text(f"x{i} = {i}")
|
|
493
|
+
|
|
494
|
+
result = generate_docs(str(self.temp_path), force=True)
|
|
495
|
+
|
|
496
|
+
self.assertEqual(result["status"], "success")
|
|
497
|
+
|
|
498
|
+
def test_detect_language_mixed_extensions(self):
|
|
499
|
+
"""测试混合扩展名检测"""
|
|
500
|
+
(self.temp_path / "main.py").write_text("x = 1")
|
|
501
|
+
(self.temp_path / "main.txt").write_text("text")
|
|
502
|
+
(self.temp_path / "main.md").write_text("# Markdown")
|
|
503
|
+
|
|
504
|
+
language = detect_language(self.temp_path)
|
|
505
|
+
|
|
506
|
+
self.assertEqual(language, "Python")
|
|
507
|
+
|
|
508
|
+
def test_generate_readme_with_long_description(self):
|
|
509
|
+
"""测试长描述的 README 生成"""
|
|
510
|
+
long_desc = "This is a very long description. " * 100
|
|
511
|
+
info = ModuleInfo(
|
|
512
|
+
name="TestModule",
|
|
513
|
+
path=str(self.temp_path),
|
|
514
|
+
description=long_desc,
|
|
515
|
+
language="Python"
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
readme = generate_readme(info)
|
|
519
|
+
|
|
520
|
+
self.assertIn(long_desc[:50], readme)
|
|
521
|
+
|
|
522
|
+
def test_generate_design_with_many_dependencies(self):
|
|
523
|
+
"""测试包含多个依赖的 DESIGN 生成"""
|
|
524
|
+
deps = [f"package{i}" for i in range(20)]
|
|
525
|
+
info = ModuleInfo(
|
|
526
|
+
name="TestModule",
|
|
527
|
+
path=str(self.temp_path),
|
|
528
|
+
language="Python",
|
|
529
|
+
dependencies=deps
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
design = generate_design(info)
|
|
533
|
+
|
|
534
|
+
self.assertIn("package0", design)
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
if __name__ == '__main__':
|
|
538
|
+
unittest.main()
|