coverage-tool 1.0.0__py3-none-any.whl
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.
- coverage_tool/__init__.py +7 -0
- coverage_tool/analyzers/__init__.py +14 -0
- coverage_tool/analyzers/dependency.py +513 -0
- coverage_tool/converters/__init__.py +60 -0
- coverage_tool/converters/base.py +83 -0
- coverage_tool/converters/cunit_converter.py +47 -0
- coverage_tool/converters/factory.py +36 -0
- coverage_tool/converters/generic_converter.py +62 -0
- coverage_tool/converters/go_converter.py +178 -0
- coverage_tool/converters/gtest_converter.py +63 -0
- coverage_tool/core/__init__.py +18 -0
- coverage_tool/core/config.py +66 -0
- coverage_tool/core/reporter.py +270 -0
- coverage_tool/example.py +102 -0
- coverage_tool/handlers/__init__.py +13 -0
- coverage_tool/handlers/compilation.py +322 -0
- coverage_tool/handlers/env_checker.py +312 -0
- coverage_tool/main.py +559 -0
- coverage_tool/parsers/__init__.py +15 -0
- coverage_tool/parsers/junit.py +172 -0
- coverage_tool/runners/__init__.py +26 -0
- coverage_tool/runners/base.py +249 -0
- coverage_tool/runners/c_runner.py +66 -0
- coverage_tool/runners/cpp_runner.py +65 -0
- coverage_tool/runners/factory.py +41 -0
- coverage_tool/runners/go_runner.py +158 -0
- coverage_tool/runners/java_runner.py +54 -0
- coverage_tool/runners/python_runner.py +99 -0
- coverage_tool/test_removers/__init__.py +38 -0
- coverage_tool/test_removers/base.py +233 -0
- coverage_tool/test_removers/c_remover.py +210 -0
- coverage_tool/test_removers/cpp_remover.py +272 -0
- coverage_tool/test_removers/factory.py +45 -0
- coverage_tool/test_removers/go_remover.py +112 -0
- coverage_tool/test_removers/java_remover.py +216 -0
- coverage_tool/test_removers/python_remover.py +172 -0
- coverage_tool/utils/__init__.py +23 -0
- coverage_tool/utils/dependency_graph.py +52 -0
- coverage_tool/utils/file_backup.py +112 -0
- coverage_tool/utils/helpers.py +89 -0
- coverage_tool/utils/logger.py +54 -0
- coverage_tool/utils/progress.py +41 -0
- coverage_tool-1.0.0.dist-info/METADATA +484 -0
- coverage_tool-1.0.0.dist-info/RECORD +47 -0
- coverage_tool-1.0.0.dist-info/WHEEL +5 -0
- coverage_tool-1.0.0.dist-info/entry_points.txt +2 -0
- coverage_tool-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
日志记录器模块
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import List, Dict, Optional, Any
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Logger:
|
|
13
|
+
"""日志记录器"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, verbose: bool = True, log_file: Optional[str] = None):
|
|
16
|
+
self.verbose = verbose
|
|
17
|
+
self.log_file = log_file
|
|
18
|
+
self.logs: List[Dict[str, Any]] = []
|
|
19
|
+
|
|
20
|
+
def log(self, level: str, message: str, **kwargs):
|
|
21
|
+
"""记录日志"""
|
|
22
|
+
log_entry = {
|
|
23
|
+
'timestamp': datetime.now().isoformat(),
|
|
24
|
+
'level': level,
|
|
25
|
+
'message': message,
|
|
26
|
+
**kwargs
|
|
27
|
+
}
|
|
28
|
+
self.logs.append(log_entry)
|
|
29
|
+
|
|
30
|
+
if self.verbose:
|
|
31
|
+
print(f"[{level}] {message}")
|
|
32
|
+
|
|
33
|
+
if self.log_file:
|
|
34
|
+
with open(self.log_file, 'a', encoding='utf-8') as f:
|
|
35
|
+
f.write(json.dumps(log_entry, ensure_ascii=False) + '\n')
|
|
36
|
+
|
|
37
|
+
def info(self, message: str, **kwargs):
|
|
38
|
+
self.log('INFO', message, **kwargs)
|
|
39
|
+
|
|
40
|
+
def warning(self, message: str, **kwargs):
|
|
41
|
+
self.log('WARNING', message, **kwargs)
|
|
42
|
+
|
|
43
|
+
def error(self, message: str, **kwargs):
|
|
44
|
+
self.log('ERROR', message, **kwargs)
|
|
45
|
+
|
|
46
|
+
def debug(self, message: str, **kwargs):
|
|
47
|
+
if self.verbose:
|
|
48
|
+
self.log('DEBUG', message, **kwargs)
|
|
49
|
+
|
|
50
|
+
def get_logs(self, level: Optional[str] = None) -> List[Dict[str, Any]]:
|
|
51
|
+
"""获取日志记录"""
|
|
52
|
+
if level:
|
|
53
|
+
return [log for log in self.logs if log['level'] == level]
|
|
54
|
+
return self.logs.copy()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
进度追踪器模块
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ProgressTracker:
|
|
10
|
+
"""进度追踪器"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, total_steps: int, description: str = ""):
|
|
13
|
+
self.total_steps = total_steps
|
|
14
|
+
self.current_step = 0
|
|
15
|
+
self.description = description
|
|
16
|
+
self.start_time = datetime.now()
|
|
17
|
+
|
|
18
|
+
def update(self, step: int = 1, message: str = ""):
|
|
19
|
+
"""更新进度"""
|
|
20
|
+
self.current_step += step
|
|
21
|
+
percentage = (self.current_step / self.total_steps) * 100
|
|
22
|
+
|
|
23
|
+
elapsed = (datetime.now() - self.start_time).total_seconds()
|
|
24
|
+
if self.current_step > 0:
|
|
25
|
+
estimated_total = elapsed / self.current_step * self.total_steps
|
|
26
|
+
remaining = estimated_total - elapsed
|
|
27
|
+
else:
|
|
28
|
+
remaining = 0
|
|
29
|
+
|
|
30
|
+
progress_msg = f"[{self.current_step}/{self.total_steps}] {percentage:.1f}%"
|
|
31
|
+
if message:
|
|
32
|
+
progress_msg += f" - {message}"
|
|
33
|
+
if remaining > 0:
|
|
34
|
+
progress_msg += f" (预计剩余: {remaining:.0f}s)"
|
|
35
|
+
|
|
36
|
+
print(progress_msg)
|
|
37
|
+
|
|
38
|
+
def finish(self, message: str = "完成"):
|
|
39
|
+
"""完成追踪"""
|
|
40
|
+
elapsed = (datetime.now() - self.start_time).total_seconds()
|
|
41
|
+
print(f"✓ {message} (耗时: {elapsed:.2f}s)")
|
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coverage-tool
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Multi-language unit test coverage analysis tool
|
|
5
|
+
Author-email: Coverage Tool <coverage@tool.dev>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/anomalyco/coverage_tool
|
|
8
|
+
Project-URL: Issues, https://github.com/anomalyco/coverage_tool/issues
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: pyyaml>=6.0
|
|
22
|
+
|
|
23
|
+
# 多语言单测覆盖率统计工具
|
|
24
|
+
|
|
25
|
+
一个功能强大的多语言单测覆盖率统计工具,支持Python、Java、Go、C、C++等编程语言,自动执行测试、分析覆盖率、删除失败的测试用例,并生成详细的测试报告。
|
|
26
|
+
|
|
27
|
+
## 优化亮点
|
|
28
|
+
|
|
29
|
+
- **智能编译修复**: 采用渐进式删除策略,根据文件优先级和依赖关系智能删除问题文件
|
|
30
|
+
- **AST解析支持**: Python测试删除使用AST解析,更准确地识别和删除测试函数
|
|
31
|
+
- **统一覆盖率计算**: 所有语言使用统一的覆盖率提取器,结果更准确
|
|
32
|
+
- **完善的日志系统**: 详细的执行日志,便于问题排查
|
|
33
|
+
- **文件备份机制**: 删除前自动备份,支持恢复操作
|
|
34
|
+
|
|
35
|
+
## 功能特性
|
|
36
|
+
|
|
37
|
+
- **多语言支持**: 支持 Python、Java、Go、C、C++ 五种编程语言
|
|
38
|
+
- **自动测试执行**: 集成各语言的主流测试框架和覆盖率工具
|
|
39
|
+
- **智能环境检查**: 自动分析项目配置文件 (requirements.txt, pom.xml 等),检查编译和测试环境是否满足要求,并提供安装建议
|
|
40
|
+
- **智能错误恢复**: 编译失败时自动删除问题文件,直到编译通过
|
|
41
|
+
- **失败测试清理**: 自动删除测试失败的函数,确保所有单测都通过
|
|
42
|
+
- **多种报告格式**: 支持 Text、JSON、CSV、HTML 四种报告格式
|
|
43
|
+
- **JUnit XML 解析**: 统一解析各语言生成的 JUnit XML 测试报告
|
|
44
|
+
|
|
45
|
+
## 安装
|
|
46
|
+
|
|
47
|
+
### 方式一:直接使用
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# 克隆项目
|
|
51
|
+
git clone <repository-url>
|
|
52
|
+
cd coverage_tool
|
|
53
|
+
|
|
54
|
+
# 确保Python版本 >= 3.7
|
|
55
|
+
python3 --version
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 方式二:安装依赖(可选,仅用于开发测试)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install -r requirements.txt
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**注意**:工具本身仅依赖Python标准库,无需安装额外Python包。但根据你需要分析的项目语言,可能需要安装对应的编译和测试工具:
|
|
65
|
+
|
|
66
|
+
| 语言 | 必需依赖 |
|
|
67
|
+
|------|----------|
|
|
68
|
+
| Python | Python 3.7+, pytest, coverage.py |
|
|
69
|
+
| Java | JDK 8+, Maven |
|
|
70
|
+
| Go | Go SDK 1.16+ |
|
|
71
|
+
| C/C++ | GCC/G++, Make |
|
|
72
|
+
|
|
73
|
+
工具启动时会自动检查这些环境依赖。
|
|
74
|
+
|
|
75
|
+
## 使用方法
|
|
76
|
+
|
|
77
|
+
### 基本语法
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python main.py -l <language> -t <target_dir> [options]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 参数说明
|
|
84
|
+
|
|
85
|
+
| 参数 | 短参数 | 说明 | 默认值 |
|
|
86
|
+
|------|--------|------|--------|
|
|
87
|
+
| --language | -l | 编程语言 (python/java/go/c/cpp) | 必填 |
|
|
88
|
+
| --target | -t | 目标目录路径 | 必填 |
|
|
89
|
+
| --output | -o | 输出报告文件名 | coverage_report |
|
|
90
|
+
| --format | -f | 报告格式 (text/json/csv/html) | text |
|
|
91
|
+
| --no-delete | - | 编译失败时不删除文件 | False |
|
|
92
|
+
| --compile-timeout | - | 编译超时时间(秒) | 60 |
|
|
93
|
+
| --test-timeout | - | 测试超时时间(秒) | 300 |
|
|
94
|
+
|
|
95
|
+
### 使用示例
|
|
96
|
+
|
|
97
|
+
#### Python 项目
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# 基本使用
|
|
101
|
+
python main.py --language python --target ./src --output report
|
|
102
|
+
|
|
103
|
+
# 生成 JSON 格式报告
|
|
104
|
+
python main.py -l python -t ./project -f json
|
|
105
|
+
|
|
106
|
+
# 不自动删除编译失败的文件
|
|
107
|
+
python main.py -l python -t ./src --no-delete
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Java 项目
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# Maven 项目
|
|
114
|
+
python main.py --language java --target ./myproject
|
|
115
|
+
|
|
116
|
+
# 生成 HTML 格式报告
|
|
117
|
+
python main.py -l java -t ./project -f html
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### Go 项目
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Go 模块项目
|
|
124
|
+
python main.py --language go --target ./module
|
|
125
|
+
|
|
126
|
+
# 生成详细报告
|
|
127
|
+
python main.py -l go -t ./src -o go_coverage -f html
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### C/C++ 项目
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# C 项目
|
|
134
|
+
python main.py --language c --target ./c_project
|
|
135
|
+
|
|
136
|
+
# C++ 项目
|
|
137
|
+
python main.py --language cpp --target ./cpp_project -f json
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## 智能环境检查
|
|
141
|
+
|
|
142
|
+
工具会自动分析项目配置文件,检查编译和测试环境是否满足要求:
|
|
143
|
+
|
|
144
|
+
| 语言 | 检测的配置文件 |
|
|
145
|
+
|------|---------------|
|
|
146
|
+
| Python | `requirements.txt`, `setup.py`, `pyproject.toml` |
|
|
147
|
+
| Java | `pom.xml`, `build.gradle` |
|
|
148
|
+
| Go | `go.mod` |
|
|
149
|
+
| C/C++ | `Makefile`, `CMakeLists.txt` |
|
|
150
|
+
|
|
151
|
+
**示例输出:**
|
|
152
|
+
```
|
|
153
|
+
============================================================
|
|
154
|
+
环境检查报告: python
|
|
155
|
+
============================================================
|
|
156
|
+
|
|
157
|
+
📁 检测到的项目配置:
|
|
158
|
+
• 构建系统: pip
|
|
159
|
+
• 测试框架: pytest
|
|
160
|
+
|
|
161
|
+
✓ Python
|
|
162
|
+
版本: Python 3.12.8
|
|
163
|
+
|
|
164
|
+
✗ pytest
|
|
165
|
+
未安装
|
|
166
|
+
安装: pip install pytest
|
|
167
|
+
|
|
168
|
+
============================================================
|
|
169
|
+
✗ 存在缺失的关键依赖
|
|
170
|
+
缺失项: pytest
|
|
171
|
+
============================================================
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## 工作流程
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
1. 编译检查
|
|
178
|
+
↓
|
|
179
|
+
├── 编译成功 → 继续执行测试
|
|
180
|
+
└── 编译失败 → 自动删除问题文件 → 重试 (最多10次)
|
|
181
|
+
↓
|
|
182
|
+
无法恢复 → 报错退出
|
|
183
|
+
↓
|
|
184
|
+
2. 运行测试
|
|
185
|
+
↓
|
|
186
|
+
3. 解析 JUnit XML 报告
|
|
187
|
+
↓
|
|
188
|
+
4. 分析覆盖率
|
|
189
|
+
↓
|
|
190
|
+
5. 删除失败的测试函数
|
|
191
|
+
↓
|
|
192
|
+
6. 重新测试验证
|
|
193
|
+
↓
|
|
194
|
+
7. 生成最终报告
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## 报告示例
|
|
198
|
+
|
|
199
|
+
### Text 格式
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
================================================================================
|
|
203
|
+
单测覆盖率报告
|
|
204
|
+
项目: myproject
|
|
205
|
+
生成时间: 2024-01-15 10:30:00
|
|
206
|
+
================================================================================
|
|
207
|
+
|
|
208
|
+
语言: python
|
|
209
|
+
----------------------------------------
|
|
210
|
+
测试用例数: 100
|
|
211
|
+
通过: 95
|
|
212
|
+
失败: 3
|
|
213
|
+
错误: 2
|
|
214
|
+
跳过: 0
|
|
215
|
+
通过率: 95.00%
|
|
216
|
+
覆盖率: 85.50%
|
|
217
|
+
执行时间: 12.34s
|
|
218
|
+
测试文件数: 15
|
|
219
|
+
源文件数: 50
|
|
220
|
+
删除文件数: 2
|
|
221
|
+
|
|
222
|
+
================================================================================
|
|
223
|
+
总体统计
|
|
224
|
+
================================================================================
|
|
225
|
+
总执行时间: 12.34s
|
|
226
|
+
总体通过率: 95.00%
|
|
227
|
+
总体覆盖率: 85.50%
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### JSON 格式
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"project_name": "myproject",
|
|
235
|
+
"generated_at": "2024-01-15T10:30:00",
|
|
236
|
+
"total_duration": 12.34,
|
|
237
|
+
"overall_pass_rate": 95.0,
|
|
238
|
+
"overall_coverage": 85.5,
|
|
239
|
+
"stats": [
|
|
240
|
+
{
|
|
241
|
+
"language": "python",
|
|
242
|
+
"total_tests": 100,
|
|
243
|
+
"passed_tests": 95,
|
|
244
|
+
"failed_tests": 3,
|
|
245
|
+
"error_tests": 2,
|
|
246
|
+
"skipped_tests": 0,
|
|
247
|
+
"pass_rate": 95.0,
|
|
248
|
+
"coverage_rate": 85.5,
|
|
249
|
+
"duration": 12.34
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## 各语言测试框架
|
|
256
|
+
|
|
257
|
+
### Python
|
|
258
|
+
- **测试框架**: pytest
|
|
259
|
+
- **覆盖率工具**: coverage.py
|
|
260
|
+
- **命令**: `python -m pytest --junitxml=report.xml`
|
|
261
|
+
- **JUnit XML**: pytest 原生支持
|
|
262
|
+
|
|
263
|
+
### Java
|
|
264
|
+
- **测试框架**: JUnit + Maven Surefire
|
|
265
|
+
- **覆盖率工具**: JaCoCo
|
|
266
|
+
- **命令**: `mvn test`, `mvn jacoco:report`
|
|
267
|
+
- **JUnit XML**: Maven Surefire 原生支持
|
|
268
|
+
|
|
269
|
+
### Go
|
|
270
|
+
- **测试框架**: testing
|
|
271
|
+
- **覆盖率工具**: go test -cover
|
|
272
|
+
- **命令**: `go test -v -coverprofile=coverage.out -json`
|
|
273
|
+
- **JUnit XML**: 使用 `go-junit-report` 或内置转换器
|
|
274
|
+
|
|
275
|
+
### C/C++
|
|
276
|
+
- **测试框架**: Google Test / CUnit
|
|
277
|
+
- **覆盖率工具**: gcov / lcov
|
|
278
|
+
- **命令**: `make test GTEST_XML_OUTPUT=1`
|
|
279
|
+
- **JUnit XML**: Google Test 原生支持 (`--gtest_output=xml:path`) 或内置转换器
|
|
280
|
+
|
|
281
|
+
## 完整工作流程
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
1. 环境检查
|
|
285
|
+
└── 分析项目配置文件 (requirements.txt, pom.xml, go.mod 等)
|
|
286
|
+
└── 检查编译和测试工具是否安装
|
|
287
|
+
└── 提示缺失的依赖安装命令
|
|
288
|
+
|
|
289
|
+
2. 编译项目
|
|
290
|
+
└── 尝试编译
|
|
291
|
+
└── 失败 → 自动删除问题文件 → 重试 (最多10次)
|
|
292
|
+
|
|
293
|
+
3. 运行测试并生成 JUnit XML
|
|
294
|
+
├── Python: pytest --junitxml (原生支持)
|
|
295
|
+
├── Java: Maven Surefire (原生支持)
|
|
296
|
+
├── Go: go test -json → 转换为 JUnit XML
|
|
297
|
+
└── C/C++: Google Test XML 或转换为 JUnit XML
|
|
298
|
+
|
|
299
|
+
4. 解析测试报告
|
|
300
|
+
└── 提取失败和错误测试用例
|
|
301
|
+
|
|
302
|
+
5. 清理失败测试
|
|
303
|
+
└── 删除失败的测试函数
|
|
304
|
+
└── 重新运行测试验证
|
|
305
|
+
└── 循环直到全部通过或达到最大迭代次数
|
|
306
|
+
|
|
307
|
+
6. 生成覆盖率报告
|
|
308
|
+
└── Text / JSON / CSV / HTML 格式
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## 统一错误处理
|
|
312
|
+
|
|
313
|
+
所有语言的测试输出都会转换为统一的 JUnit XML 格式:
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
from junit_report_converter import JUnitReportConverter
|
|
317
|
+
|
|
318
|
+
# Go test JSON → JUnit XML
|
|
319
|
+
xml = JUnitReportConverter.convert_go_test(go_test_json)
|
|
320
|
+
|
|
321
|
+
# Google Test 文本 → JUnit XML
|
|
322
|
+
xml = JUnitReportConverter.convert_cpp_gtest(gtest_output, xml_path)
|
|
323
|
+
|
|
324
|
+
# 通用测试输出 → JUnit XML
|
|
325
|
+
xml = JUnitReportConverter.convert_generic_output(output, 'gtest')
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## 配置文件
|
|
329
|
+
|
|
330
|
+
工具使用 `config.py` 中的配置,支持自定义各语言的测试命令:
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
LANGUAGE_CONFIGS = {
|
|
334
|
+
Language.PYTHON: CoverageConfig(
|
|
335
|
+
language=Language.PYTHON,
|
|
336
|
+
test_command="python -m pytest --junitxml={junit_output}",
|
|
337
|
+
coverage_command="python -m coverage run --source={source} -m pytest",
|
|
338
|
+
test_file_pattern="**/*test*.py",
|
|
339
|
+
source_file_pattern="**/*.py"
|
|
340
|
+
),
|
|
341
|
+
# ... 其他语言配置
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## 高级用法
|
|
346
|
+
|
|
347
|
+
### 批量处理多个项目
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
#!/bin/bash
|
|
351
|
+
for lang in python java go cpp; do
|
|
352
|
+
for dir in projects/*/; do
|
|
353
|
+
python main.py -l $lang -t $dir -o ${dir}_report
|
|
354
|
+
done
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### CI/CD 集成
|
|
358
|
+
|
|
359
|
+
```yaml
|
|
360
|
+
# GitHub Actions 示例
|
|
361
|
+
name: Test Coverage
|
|
362
|
+
|
|
363
|
+
on: [push, pull_request]
|
|
364
|
+
|
|
365
|
+
jobs:
|
|
366
|
+
coverage:
|
|
367
|
+
runs-on: ubuntu-latest
|
|
368
|
+
steps:
|
|
369
|
+
- uses: actions/checkout@v2
|
|
370
|
+
- name: Set up Python
|
|
371
|
+
uses: actions/setup-python@v2
|
|
372
|
+
with:
|
|
373
|
+
python-version: '3.9'
|
|
374
|
+
- name: Run Coverage Tool
|
|
375
|
+
run: |
|
|
376
|
+
pip install -r requirements.txt
|
|
377
|
+
python main.py -l python -t ./src -o coverage_report -f json
|
|
378
|
+
- name: Upload Report
|
|
379
|
+
uses: actions/upload-artifact@v2
|
|
380
|
+
with:
|
|
381
|
+
name: coverage-report
|
|
382
|
+
path: coverage_report.json
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## 故障排除
|
|
386
|
+
|
|
387
|
+
### 常见问题
|
|
388
|
+
|
|
389
|
+
**Q: 工具提示缺少依赖,但实际已安装?**
|
|
390
|
+
A: 工具会根据项目配置文件自动检测依赖,请检查项目的 requirements.txt 或 pom.xml 是否正确配置。
|
|
391
|
+
|
|
392
|
+
**Q: 编译失败但文件未被删除?**
|
|
393
|
+
A: 检查是否使用了 `--no-delete` 参数,或确认删除逻辑适用于你的文件类型。
|
|
394
|
+
|
|
395
|
+
**Q: 测试覆盖率显示为 0?**
|
|
396
|
+
A: 确保已安装对应的覆盖率工具(如 coverage.py、JaCoCo 等)。
|
|
397
|
+
|
|
398
|
+
**Q: 无法找到测试文件?**
|
|
399
|
+
A: 检查测试文件命名是否符合规范(`*test*.py`、`*Test.java` 等)。
|
|
400
|
+
|
|
401
|
+
**Q: 环境检查失败怎么办?**
|
|
402
|
+
A: 工具会显示缺失的依赖和安装命令,按提示安装即可。也可使用 `--no-delete` 跳过检查。
|
|
403
|
+
|
|
404
|
+
## 项目结构
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
coverage_tool/
|
|
408
|
+
├── main.py # 主入口
|
|
409
|
+
├── config.py # 语言配置
|
|
410
|
+
├── runners.py # 各语言运行器
|
|
411
|
+
├── junit_parser.py # JUnit XML 解析器
|
|
412
|
+
├── junit_report_converter.py # JUnit XML 转换器
|
|
413
|
+
├── coverage_xml_parser.py # 覆盖率XML解析器
|
|
414
|
+
├── dependency_analyzer.py # 项目依赖分析器
|
|
415
|
+
├── env_checker.py # 环境检查器
|
|
416
|
+
├── failed_test_remover.py # 失败测试删除器(兼容层)
|
|
417
|
+
├── compilation_handler.py # 编译失败处理器
|
|
418
|
+
├── reporter.py # 报告生成器
|
|
419
|
+
├── test_removers/ # 测试删除器模块(重构后)
|
|
420
|
+
│ ├── __init__.py
|
|
421
|
+
│ ├── base.py # 基类和通用逻辑
|
|
422
|
+
│ ├── factory.py # 工厂类
|
|
423
|
+
│ ├── python_remover.py # Python删除器
|
|
424
|
+
│ ├── java_remover.py # Java删除器
|
|
425
|
+
│ ├── go_remover.py # Go删除器
|
|
426
|
+
│ ├── c_remover.py # C删除器
|
|
427
|
+
│ └── cpp_remover.py # C++删除器
|
|
428
|
+
├── requirements.txt # 依赖列表
|
|
429
|
+
└── __init__.py
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### 架构说明
|
|
433
|
+
|
|
434
|
+
**v1.2.0 架构改进**:
|
|
435
|
+
- 将 `failed_test_remover.py`(1269行)重构为模块化结构
|
|
436
|
+
- 提取公共逻辑到 `base.py`,消除5处重复代码
|
|
437
|
+
- 各语言删除器现在继承基类,只实现特定逻辑
|
|
438
|
+
- 保持向后兼容,原有导入方式仍然有效
|
|
439
|
+
|
|
440
|
+
**推荐导入方式**(新):
|
|
441
|
+
```python
|
|
442
|
+
from test_removers import SmartTestRemoverFactory
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**向后兼容方式**(仍支持):
|
|
446
|
+
```python
|
|
447
|
+
from failed_test_remover import SmartTestRemoverFactory
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## 功能验证
|
|
451
|
+
|
|
452
|
+
所有模块已通过语法检查和导入测试:
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
# 检查所有Python文件语法
|
|
456
|
+
python3 -m py_compile *.py
|
|
457
|
+
|
|
458
|
+
# 测试各语言删除器(推荐新方式)
|
|
459
|
+
from test_removers import SmartTestRemoverFactory
|
|
460
|
+
for lang in SmartTestRemoverFactory.supported_languages():
|
|
461
|
+
remover = SmartTestRemoverFactory.get_remover(lang, '/tmp')
|
|
462
|
+
print(f'✓ {lang}: {type(remover).__name__}')
|
|
463
|
+
|
|
464
|
+
# 或保持向后兼容
|
|
465
|
+
from failed_test_remover import SmartTestRemoverFactory
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## 版本历史
|
|
469
|
+
|
|
470
|
+
- **v1.2.0**: 重构架构,模块化测试删除器
|
|
471
|
+
- 将 `failed_test_remover.py` 拆分为 `test_removers/` 包
|
|
472
|
+
- 提取公共逻辑到基类,消除代码重复
|
|
473
|
+
- 预编译正则表达式提升性能
|
|
474
|
+
- 保持向后兼容
|
|
475
|
+
- **v1.1.0**: 添加智能环境检查和项目依赖分析
|
|
476
|
+
- **v1.0.0**: 初始版本,支持5种语言的基础功能
|
|
477
|
+
|
|
478
|
+
## 许可证
|
|
479
|
+
|
|
480
|
+
MIT License
|
|
481
|
+
|
|
482
|
+
## 贡献
|
|
483
|
+
|
|
484
|
+
欢迎提交 Issue 和 Pull Request!
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
coverage_tool/__init__.py,sha256=0j2DaSgKbtKY7LShLYx8VHbAhD09gm8aGQI__uo4CeU,123
|
|
2
|
+
coverage_tool/example.py,sha256=8d0VAve0F54wDXgKIpIgE5kn-ZzMEKDED6_74TfQMvo,2712
|
|
3
|
+
coverage_tool/main.py,sha256=cyHcWEcX3fK35kyLnr1_Nwf0Ug_svcLqG8K3wXbCk14,19416
|
|
4
|
+
coverage_tool/analyzers/__init__.py,sha256=GlcdK3CsmPtnGN0P13K0F6i-dMbL03wVRepIPW3U0O0,265
|
|
5
|
+
coverage_tool/analyzers/dependency.py,sha256=l6HywXXdBY506F6yzaFH-aXYYrinbWKuG3LTfT2CGJc,18759
|
|
6
|
+
coverage_tool/converters/__init__.py,sha256=h3wSGZgs1x_tKMjq3ZLAJepmcBgc3fR_-cGnQydZFhM,1830
|
|
7
|
+
coverage_tool/converters/base.py,sha256=STPYd1e6Lt5Eaz54rMRBRNXUuwToUqgI5uQb8VFHDg0,2838
|
|
8
|
+
coverage_tool/converters/cunit_converter.py,sha256=_a9Tg_nSit6XlG7x7IA0oxjcGAJEKQYNDzZzH1CPu9A,1130
|
|
9
|
+
coverage_tool/converters/factory.py,sha256=Qzg4ZmfX9YeNx4BcPJu3n37XLcszy6ysu2B4NHs1-6w,1003
|
|
10
|
+
coverage_tool/converters/generic_converter.py,sha256=35o6M5KyHxxOlX8al-nrN0dTT9v12PQF-Nc4hF7bHW8,1906
|
|
11
|
+
coverage_tool/converters/go_converter.py,sha256=KoNQ4bqZrv1zeDuGWm7GUhri6QFMqolnG-GV0YIF490,6287
|
|
12
|
+
coverage_tool/converters/gtest_converter.py,sha256=uTn65IvLEGy7OUTBk80uMx9o-mQ147Az0_Za7n575fI,1728
|
|
13
|
+
coverage_tool/core/__init__.py,sha256=rNM16navIyNkoMKVvJsEy2zVF7jAcyHV81nOsP1gKgI,415
|
|
14
|
+
coverage_tool/core/config.py,sha256=QmBxj72gcwhI-bEUDMDd7mCUPxJdn7NiO7DdfingaOA,2133
|
|
15
|
+
coverage_tool/core/reporter.py,sha256=GOsOhu8JX0u9sBHhEdbHHfrEFEfvFXQDVOyTLdeeD0w,9500
|
|
16
|
+
coverage_tool/handlers/__init__.py,sha256=6iAHa2i3LhqpDWqt32x98qx3-PbVeNcsDqQX6jHhm0U,253
|
|
17
|
+
coverage_tool/handlers/compilation.py,sha256=7rvrMGOs9nHPF1op4RXgFzXVs1wL4Skl_pBKclQotOI,11981
|
|
18
|
+
coverage_tool/handlers/env_checker.py,sha256=L6JJE39C-9DxKKtVC_ZUi-0ONxnjREZhQKiaj8t5Uoo,12665
|
|
19
|
+
coverage_tool/parsers/__init__.py,sha256=7Wmg-Tf_rAo-uD9PWZJv5gGwSeWWuzcAAO2qMm6O3QE,264
|
|
20
|
+
coverage_tool/parsers/junit.py,sha256=COjG9_YWvlAsX3Ztd11ttFRRDZnpjg-BZWWwr4egVTM,5555
|
|
21
|
+
coverage_tool/runners/__init__.py,sha256=w-Lnwfh-4jOdjxdSepKO-YSg4GqHmPtK6Ut6wQeQkJU,584
|
|
22
|
+
coverage_tool/runners/base.py,sha256=hyaFSIFoqW35O9Vou8iI3S2S0dTWCMvhn_92spz4lv0,8078
|
|
23
|
+
coverage_tool/runners/c_runner.py,sha256=DZPtEVUZXSNQLuA1nDdI449ODImT1Tkfx8q28HyC_Ko,2166
|
|
24
|
+
coverage_tool/runners/cpp_runner.py,sha256=f_L1FVuLRJH4DByj6Oo7uVGodOJFUDUEosZreqf70Ko,2154
|
|
25
|
+
coverage_tool/runners/factory.py,sha256=f_oM_AQfj3Yge1Ou_XSyERbcynluBLWb4s85m7YgYWs,1187
|
|
26
|
+
coverage_tool/runners/go_runner.py,sha256=FEOPpi-IMI5zu_zbzuaJ60vS0aoYJCTbRtW2q1TJEC0,6397
|
|
27
|
+
coverage_tool/runners/java_runner.py,sha256=BEzaR5-4npIzmPSCO8avzktgsDp_OwjSgQxT3A8-uSI,1936
|
|
28
|
+
coverage_tool/runners/python_runner.py,sha256=ZTOjY93ZY1vfuROM9-CX80d03AaAUA5fJhcprgWQ3Vk,3731
|
|
29
|
+
coverage_tool/test_removers/__init__.py,sha256=rPbFy8DRohFctpZgBz-QR-mld0rxqBg4G4KHjKQqGgI,958
|
|
30
|
+
coverage_tool/test_removers/base.py,sha256=LYvG0ZRcsbsI4p_h3HvwvStfO1-6i_ARzaupNFCE3BE,8911
|
|
31
|
+
coverage_tool/test_removers/c_remover.py,sha256=3hxmak2Zmpj__oxyr9WE9lLHohF3hYdBNRDJCqc7GZM,8355
|
|
32
|
+
coverage_tool/test_removers/cpp_remover.py,sha256=c-u7AAmXwNMjxQsnPAw6lFhaaYGC5AGU2awO5pHxTlg,10415
|
|
33
|
+
coverage_tool/test_removers/factory.py,sha256=y-tC3AkeZJqT-LYydysinBGY6s3ReuFCcvyRdQOchls,1660
|
|
34
|
+
coverage_tool/test_removers/go_remover.py,sha256=v8sW12PsgwUj4o2eoVJBIa7D-poORAlHH_XSvJcgzLI,4310
|
|
35
|
+
coverage_tool/test_removers/java_remover.py,sha256=-nNHQYhZVCsXCOm1TvmZLcJi3o_Bf5Ok1KjeLLZR-fs,9231
|
|
36
|
+
coverage_tool/test_removers/python_remover.py,sha256=1q5QzR7Dw6Ob5GFOB-zTl5DtMOuQRUXJfTXsvsWPZm8,6926
|
|
37
|
+
coverage_tool/utils/__init__.py,sha256=ojhcXq94rKP7JawogamZ59CgV4jSrqvIOfTLezU6ay4,609
|
|
38
|
+
coverage_tool/utils/dependency_graph.py,sha256=XcvOxCKlqbyIcBI3xeETCStdU_q7d_khBakrgXFo8pM,1758
|
|
39
|
+
coverage_tool/utils/file_backup.py,sha256=SSrVGAPlO-Lz4cx-dFLhRwonbL8V0h0siBm0ZPcTf_o,3287
|
|
40
|
+
coverage_tool/utils/helpers.py,sha256=t2aWyMtV_r1EGFli40q1H1gGmibNrpjd5pFlhXNEX0w,2587
|
|
41
|
+
coverage_tool/utils/logger.py,sha256=FGRPw39iXCT-VwrY4VOLpL_z2hALeYv4QAcYNC7SUsA,1596
|
|
42
|
+
coverage_tool/utils/progress.py,sha256=o8t-FvrEMN4oYSK-cq_ywnkMES5szCwNhl546i0JpUU,1312
|
|
43
|
+
coverage_tool-1.0.0.dist-info/METADATA,sha256=R5Q1L9EajJkA1YU94J1Fj4ZkNmoJWoZ71bIk13yaacU,13751
|
|
44
|
+
coverage_tool-1.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
45
|
+
coverage_tool-1.0.0.dist-info/entry_points.txt,sha256=gpUjpKt5x923IqF_YogfB-DMj_AhMyGivppNG61H7ig,58
|
|
46
|
+
coverage_tool-1.0.0.dist-info/top_level.txt,sha256=QXoWKxLBHkNWJAlCFZjqCuunXV-6uWjUhc0ni4enaYo,14
|
|
47
|
+
coverage_tool-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
coverage_tool
|