from __future__ import annotations
import subprocess
from pathlib import Path
from typing import Optional
from .file_scanner import discover_python_sources, relative_to_root
from .unit_test_generator import generate_unit_tests_for_paths
def full_test_pipeline(
project_root: str,
language: str = "python",
test_command: Optional[str] = None,
):
root = Path(project_root).resolve()
# Ensure needed test folders exist
for folder in ["unit", "integration", "e2e", "snapshots"]:
(root / "tests" / folder).mkdir(parents=True, exist_ok=True)
# Discover source files
sources = discover_python_sources(root)
relative = relative_to_root(sources, root)
# Generate unit tests
unit_result = generate_unit_tests_for_paths(
project_root=root,
paths=sources,
language=language,
)
# Run pytest
if test_command is None:
test_command = "pytest --maxfail=1 --disable-warnings --cov=. --cov-report=term-missing"
process = subprocess.Popen(
test_command,
cwd=str(root),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)
stdout, _ = process.communicate()
exit_code = process.returncode
failures = int("FAILED" in stdout or "ERROR" in stdout)
coverage = _extract_coverage(stdout)
mcp_dir = root / ".mcp"
mcp_dir.mkdir(exist_ok=True)
(mcp_dir / "test_output.log").write_text(stdout)
return {
"tests_generated": unit_result.generated,
"tests_run": -1,
"failures": failures,
"coverage_percent": coverage,
"report_files": [str(mcp_dir / "test_output.log")],
"exit_code": exit_code,
}
def _extract_coverage(text: str) -> float:
import re
match = re.search(r"(\d+\.\d+)%", text)
return float(match.group(1)) if match else -1.0