diff --git a/tests/test_gui_2_result.py b/tests/test_gui_2_result.py index 00d5ed98..bdb793db 100644 --- a/tests/test_gui_2_result.py +++ b/tests/test_gui_2_result.py @@ -481,6 +481,58 @@ def test_phase_3_l1284_handle_history_logic_result_success(): The simplest success path is when _last_ui_snapshot is None (first snapshot, early return) or when nothing changed (no push needed). """ + + +def test_phase_3_invariant_batch_a_count_dropped(): + """ + Phase 3 invariant: the audit's INTERNAL_BROAD_CATCH count for src/gui_2.py + has dropped from 25 to 17 (a drop of 8 sites). + + The 8 migrated sites are: L731 (main font), L742 (mono font), L1123 + (_gui_func), L1171 (_show_menus do_generate), L1197 (_show_menus hwnd), + L1222 (_show_menus is_max), L1284 (_handle_history_logic), L4848 + (render_warmup_status_indicator). + """ + result = subprocess.run( + ["uv", "run", "python", "scripts/audit_exception_handling.py", "--src", "src", "--json"], + capture_output=True, + text=True, + ) + assert result.returncode == 0, ( + f"audit_exception_handling.py exited {result.returncode}; stderr:\n" + f"{result.stderr[:2000]}" + ) + data = json.loads(result.stdout) + gui2 = [f for f in data.get("files", []) if "gui_2" in f.get("filename", "")][0] + broad_catches = [f for f in gui2.get("findings", []) if f.get("category") == "INTERNAL_BROAD_CATCH"] + assert len(broad_catches) == 17, ( + f"Phase 3 invariant: expected 17 INTERNAL_BROAD_CATCH sites in src/gui_2.py " + f"(down from 25); found {len(broad_catches)}. The 8 Batch A sites must be " + f"migrated to Result[T] helpers. Lines: {[f.get('line') for f in broad_catches]}" + ) + + +def test_phase_3_invariant_all_8_migration_sites_have_tests(): + """ + Phase 3 invariant: each of the 8 Batch A sites has both success and + failure tests in this test file. + """ + import re + text = Path(__file__).read_text(encoding="utf-8") + # Expected: each line number in {731, 742, 1123, 1171, 1197, 1222, 1284, 4848} + # should have both _success and _failure tests + expected_lines = [731, 742, 1123, 1171, 1197, 1222, 1284, 4848] + for line in expected_lines: + success_pattern = f"test_phase_3_l{line}_.*_success" + failure_pattern = f"test_phase_3_l{line}_.*_failure" + assert re.search(success_pattern, text), ( + f"Phase 3 invariant: missing success test for L{line}. " + f"Expected a test matching '{success_pattern}'." + ) + assert re.search(failure_pattern, text), ( + f"Phase 3 invariant: missing failure test for L{line}. " + f"Expected a test matching '{failure_pattern}'." + ) from src import gui_2 from unittest.mock import MagicMock app = MagicMock()