""" Test runner for TouchGrass project. This script runs all unit tests and generates a comprehensive test report. """ import subprocess import sys import argparse from pathlib import Path from datetime import datetime import json def run_tests(test_path: str = "tests", markers: str = None, verbose: bool = True, junit_xml: str = None, coverage: bool = False): """Run pytest with specified options.""" cmd = ["pytest", test_path] if markers: cmd.extend(["-m", markers]) if verbose: cmd.append("-v") if junit_xml: cmd.extend(["--junit-xml", junit_xml]) if coverage: cmd.extend([ "--cov=TouchGrass", "--cov-report=html", "--cov-report=term" ]) # Add --tb=short for shorter tracebacks cmd.append("--tb=short") print(f"Running: {' '.join(cmd)}\n") result = subprocess.run(cmd) return result.returncode def generate_test_report(output_dir: str = "test_reports"): """Generate a comprehensive test report.""" output_dir = Path(output_dir) output_dir.mkdir(parents=True, exist_ok=True) report = { "timestamp": datetime.now().isoformat(), "summary": {}, "details": [] } # Run tests with JSON output json_output = output_dir / "test_results.json" cmd = [ "pytest", "tests", "-v", "--tb=short", f"--junit-xml={output_dir / 'junit.xml'}", "--json-report", f"--json-report-file={json_output}" ] try: subprocess.run(cmd, check=False) except Exception as e: print(f"Warning: Could not generate JSON report: {e}") # Read JSON report if it exists if json_output.exists(): with open(json_output, 'r') as f: try: results = json.load(f) report["summary"] = { "total": results.get("summary", {}).get("total", 0), "passed": results.get("summary", {}).get("passed", 0), "failed": results.get("summary", {}).get("failed", 0), "skipped": results.get("summary", {}).get("skipped", 0) } except json.JSONDecodeError: pass # Save report report_file = output_dir / "test_report.json" with open(report_file, 'w') as f: json.dump(report, f, indent=2) print(f"\nāœ“ Test report generated at {report_file}") return report def main(): parser = argparse.ArgumentParser(description="Run TouchGrass test suite") parser.add_argument("--tests", type=str, default="tests", help="Test directory or specific test file") parser.add_argument("--markers", type=str, default=None, help="Only run tests with specified markers (e.g., 'not slow')") parser.add_argument("--no-verbose", action="store_true", help="Disable verbose output") parser.add_argument("--junit-xml", type=str, default=None, help="Output JUnit XML report to specified file") parser.add_argument("--coverage", action="store_true", help="Run with coverage reporting") parser.add_argument("--report-dir", type=str, default="test_reports", help="Directory for test reports") parser.add_argument("--skip-report", action="store_true", help="Skip generating test report") args = parser.parse_args() # Run tests exit_code = run_tests( test_path=args.tests, markers=args.markers, verbose=not args.no_verbose, junit_xml=args.junit_xml, coverage=args.coverage ) # Generate report unless skipped if not args.skip_report: generate_test_report(args.report_dir) print("\n" + "=" * 60) if exit_code == 0: print("āœ“ All tests passed!") else: print(f"āœ— Some tests failed (exit code: {exit_code})") print("=" * 60) return exit_code if __name__ == "__main__": exit_code = main() sys.exit(exit_code)