diff --git a/tests/test_audit_dataclass_coverage.py b/tests/test_audit_dataclass_coverage.py new file mode 100644 index 00000000..bd445382 --- /dev/null +++ b/tests/test_audit_dataclass_coverage.py @@ -0,0 +1,98 @@ +"""Tests for scripts/audit_dataclass_coverage.py + +The audit counts `dict[str, Any]` and `list[dict[...]]` annotations that +remain outside the 5 promoted dataclass sites (mcp_tool_specs, openai_schemas, +provider_state, log_registry.Session, api_hooks.WebSocketMessage). + +Mirrors tests/test_audit_weak_types.py structure. + +CONVENTION: 1-space indentation. NO COMMENTS. +""" +from __future__ import annotations + +import json +import subprocess +import sys +from pathlib import Path + +import pytest + + +REPO_ROOT = Path(__file__).resolve().parents[1] +AUDIT_SCRIPT = REPO_ROOT / "scripts" / "audit_dataclass_coverage.py" +BASELINE_FILE = REPO_ROOT / "scripts" / "audit_dataclass_coverage.baseline.json" + + +def _run_audit(*args: str) -> subprocess.CompletedProcess[str]: + return subprocess.run( + [sys.executable, str(AUDIT_SCRIPT), *args], + cwd=str(REPO_ROOT), + capture_output=True, + text=True, + timeout=60, + ) + + +def test_audit_script_exists() -> None: + assert AUDIT_SCRIPT.is_file(), f"audit script missing: {AUDIT_SCRIPT}" + + +def test_audit_help_runs() -> None: + result = _run_audit("--help") + assert result.returncode == 0 + assert "audit" in result.stdout.lower() + + +def test_audit_json_mode_emits_valid_json() -> None: + result = _run_audit("--json") + assert result.returncode == 0, f"audit --json failed: {result.stderr}" + payload = json.loads(result.stdout) + assert "files_scanned" in payload + assert "total_weak" in payload + assert "by_category" in payload + assert isinstance(payload["total_weak"], int) + assert payload["total_weak"] >= 0 + + +def test_audit_default_mode_emits_human_report() -> None: + result = _run_audit() + assert result.returncode == 0, f"audit default mode failed: {result.stderr}" + assert "Dataclass Coverage Audit" in result.stdout or "dataclass" in result.stdout.lower() + + +def test_audit_strict_mode_against_existing_baseline_passes() -> None: + if not BASELINE_FILE.is_file(): + pytest.skip("baseline not yet generated; skip --strict assertion") + result = _run_audit("--strict", "--baseline", str(BASELINE_FILE)) + assert result.returncode == 0, ( + f"audit --strict failed (current count > baseline): {result.stderr}" + ) + assert "STRICT OK" in result.stdout + + +def test_audit_strict_mode_fails_when_baseline_is_zero() -> None: + tmp_baseline = REPO_ROOT / "tests" / "artifacts" / "tier2_state" / "any_type_componentization_20260621" / "_zero_baseline.json" + tmp_baseline.parent.mkdir(parents=True, exist_ok=True) + tmp_baseline.write_text(json.dumps({"total_weak": 0}), encoding="utf-8") + try: + result = _run_audit("--strict", "--baseline", str(tmp_baseline)) + assert result.returncode == 1, "audit --strict should fail when current > baseline=0" + assert "STRICT" in result.stderr or "regression" in result.stderr.lower() + finally: + if tmp_baseline.exists(): + tmp_baseline.unlink() + + +def test_audit_baseline_field_shape() -> None: + result = _run_audit("--json") + assert result.returncode == 0 + payload = json.loads(result.stdout) + assert "total_weak" in payload + assert "files_with_findings" in payload + assert "by_category" in payload + assert "by_file" in payload + assert isinstance(payload["by_file"], list) + if payload["by_file"]: + entry = payload["by_file"][0] + assert "filename" in entry + assert "weak_count" in entry \ No newline at end of file