"""Tests for merge-simulation worktree mutation verifier (#317).""" import sys import unittest from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from reviewer_merge_simulation import ( # noqa: E402 assess_merge_simulation_report, merge_simulation_commands, ) def _good_simulation_report(**overrides) -> str: lines = [ "Worktree/index mutations: merge simulation in branches/review-pr281", "Worktree path: branches/review-pr281", "Pre-simulation clean status: clean (git status --porcelain empty)", "Merge result: conflicts in review_proofs.py", "Abort command: git merge --abort", "Post-abort clean status: clean after abort (git status --porcelain empty)", ] text = "\n".join(lines) for key, value in overrides.items(): text = text.replace(f"{key}:", f"{key}: {value}") return text class TestMergeSimulationDetection(unittest.TestCase): def test_detects_no_commit_merge(self): commands = merge_simulation_commands([ "git merge prgs/master --no-commit --no-ff", "git status", ]) self.assertEqual(commands, ["git merge prgs/master --no-commit --no-ff"]) def test_detects_merge_abort(self): commands = merge_simulation_commands([ "git merge prgs/master --no-commit --no-ff", "git merge --abort", ]) self.assertIn("git merge --abort", commands) class TestMergeSimulationReport(unittest.TestCase): def test_no_simulation_passes(self): result = assess_merge_simulation_report( "Review complete. Worktree/index mutations: none", command_log=["git status --porcelain", "git diff prgs/master...HEAD"], ) self.assertTrue(result["proven"]) def test_documented_simulation_passes(self): report = _good_simulation_report() result = assess_merge_simulation_report( report, command_log=[ "git merge prgs/master --no-commit --no-ff", "git merge --abort", ], ) self.assertTrue(result["proven"], result["reasons"]) def test_readonly_classification_blocks(self): report = "\n".join([ "Read-only diagnostics: git merge prgs/master --no-commit --no-ff, git status", "Worktree/index mutations: none", ]) result = assess_merge_simulation_report( report, command_log=["git merge prgs/master --no-commit --no-ff"], ) self.assertFalse(result["proven"]) self.assertTrue(result["block"]) self.assertTrue(any("read-only" in r.lower() for r in result["reasons"])) def test_missing_worktree_field_blocks(self): report = "Merge simulation ran but only noted in prose." result = assess_merge_simulation_report( report, command_log=["git merge prgs/master --no-commit --no-ff"], ) self.assertFalse(result["proven"]) self.assertTrue(any("worktree/index mutations" in r.lower() for r in result["reasons"])) def test_conflict_simulation_requires_merge_result(self): report = _good_simulation_report().replace( "Merge result: conflicts in review_proofs.py", "", ) result = assess_merge_simulation_report( report, command_log=["git merge prgs/master --no-commit --no-ff"], ) self.assertFalse(result["proven"]) self.assertTrue(any("merge result" in r.lower() for r in result["reasons"])) def test_aborted_simulation_requires_post_clean_proof(self): report = _good_simulation_report().replace( "Post-abort clean status: clean after abort (git status --porcelain empty)", "", ) result = assess_merge_simulation_report( report, command_log=[ "git merge prgs/master --no-commit --no-ff", "git merge --abort", ], ) self.assertFalse(result["proven"]) self.assertTrue(any("post-abort" in r.lower() for r in result["reasons"])) def test_successful_simulation_without_abort_omits_abort_fields(self): report = "\n".join([ "Worktree/index mutations: merge simulation completed cleanly", "Worktree path: branches/review-pr281", "Pre-simulation clean status: clean before simulation", "Merge result: clean fast-forward simulation", ]) result = assess_merge_simulation_report( report, command_log=["git merge prgs/master --no-commit --no-ff"], ) self.assertTrue(result["proven"], result["reasons"]) class TestExport(unittest.TestCase): def test_review_proofs_reexport(self): from review_proofs import assess_merge_simulation_report as exported self.assertTrue(callable(exported)) if __name__ == "__main__": unittest.main()