Spaces:
Sleeping
Sleeping
| """ | |
| VoiceForge - Coverage & Function Tracker | |
| ----------------------------------------- | |
| Tracks test coverage and identifies untested functions: | |
| - Collects all public functions in codebase | |
| - Matches against existing tests | |
| - Generates coverage report | |
| """ | |
| import ast | |
| import sys | |
| from pathlib import Path | |
| from collections import defaultdict | |
| def collect_functions(root_dir: Path) -> dict[str, list[str]]: | |
| """Collect all public functions from Python files""" | |
| functions = defaultdict(list) | |
| for py_file in root_dir.rglob("*.py"): | |
| if '__pycache__' in str(py_file) or 'test_' in py_file.name: | |
| continue | |
| try: | |
| with open(py_file, 'r', encoding='utf-8', errors='ignore') as f: | |
| source = f.read() | |
| tree = ast.parse(source) | |
| module_name = py_file.stem | |
| for node in ast.walk(tree): | |
| if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): | |
| # Skip private functions | |
| if not node.name.startswith('_'): | |
| functions[module_name].append(node.name) | |
| except Exception: | |
| pass | |
| return functions | |
| def collect_tested_functions(test_dir: Path) -> set[str]: | |
| """Extract function names that are being tested""" | |
| tested = set() | |
| for test_file in test_dir.rglob("test_*.py"): | |
| try: | |
| with open(test_file, 'r', encoding='utf-8', errors='ignore') as f: | |
| source = f.read() | |
| tree = ast.parse(source) | |
| for node in ast.walk(tree): | |
| if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): | |
| # Extract tested function name from test name | |
| test_name = node.name | |
| if test_name.startswith('test_'): | |
| # e.g., test_transcribe_audio -> transcribe_audio | |
| func_name = test_name[5:] | |
| tested.add(func_name) | |
| # Also check for mocked functions | |
| for child in ast.walk(node): | |
| if isinstance(child, ast.Attribute): | |
| tested.add(child.attr) | |
| except Exception: | |
| pass | |
| return tested | |
| def run_coverage_analysis(app_dir: str = "app", test_dir: str = "tests"): | |
| """Run coverage analysis and report untested functions""" | |
| print("=" * 60) | |
| print("📊 VoiceForge Function Coverage Tracker") | |
| print("=" * 60) | |
| app_path = Path(app_dir) | |
| test_path = Path(test_dir) | |
| if not app_path.exists(): | |
| print(f"❌ App directory not found: {app_dir}") | |
| sys.exit(1) | |
| # Collect all functions | |
| all_functions = collect_functions(app_path) | |
| total_functions = sum(len(funcs) for funcs in all_functions.values()) | |
| # Collect tested functions | |
| tested_functions = collect_tested_functions(test_path) | |
| print(f"\n📁 Scanned: {len(all_functions)} modules, {total_functions} functions") | |
| print(f"🧪 Tests cover: {len(tested_functions)} function patterns\n") | |
| # Find untested | |
| untested = defaultdict(list) | |
| tested_count = 0 | |
| for module, funcs in all_functions.items(): | |
| for func in funcs: | |
| if func in tested_functions or any(func in t for t in tested_functions): | |
| tested_count += 1 | |
| else: | |
| untested[module].append(func) | |
| coverage = (tested_count / total_functions * 100) if total_functions > 0 else 0 | |
| print("📈 COVERAGE SUMMARY") | |
| print("-" * 40) | |
| print(f" Total Functions: {total_functions}") | |
| print(f" Tested: {tested_count}") | |
| print(f" Untested: {total_functions - tested_count}") | |
| print(f" Coverage: {coverage:.1f}%") | |
| # Coverage bar | |
| bar_length = int(coverage / 5) | |
| bar = "█" * bar_length + "░" * (20 - bar_length) | |
| print(f"\n [{bar}] {coverage:.1f}%") | |
| # Untested by module | |
| print("\n⚠️ UNTESTED FUNCTIONS (by module)") | |
| print("-" * 40) | |
| for module, funcs in sorted(untested.items())[:10]: | |
| print(f"\n 📦 {module}:") | |
| for func in funcs[:5]: | |
| print(f" • {func}()") | |
| if len(funcs) > 5: | |
| print(f" ... and {len(funcs) - 5} more") | |
| print("\n" + "=" * 60) | |
| if coverage >= 70: | |
| print("✅ Coverage: GOOD") | |
| return 0 | |
| elif coverage >= 40: | |
| print("⚠️ Coverage: NEEDS IMPROVEMENT") | |
| return 1 | |
| else: | |
| print("❌ Coverage: LOW") | |
| return 2 | |
| if __name__ == "__main__": | |
| import argparse | |
| parser = argparse.ArgumentParser(description="Track VoiceForge function coverage") | |
| parser.add_argument("--app", default="app", help="App source directory") | |
| parser.add_argument("--tests", default="tests", help="Tests directory") | |
| args = parser.parse_args() | |
| sys.exit(run_coverage_analysis(args.app, args.tests)) | |