test_muse_client.py
python
| 1 | """Tests for MUSE client result types.""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | from tourdeforce.clients.muse import CheckoutResult, MergeResult |
| 6 | |
| 7 | |
| 8 | class TestCheckoutResult: |
| 9 | |
| 10 | def test_successful_checkout(self) -> None: |
| 11 | |
| 12 | r = CheckoutResult( |
| 13 | success=True, |
| 14 | blocked=False, |
| 15 | target="abc123", |
| 16 | head_moved=True, |
| 17 | executed=5, |
| 18 | plan_hash="deadbeefcafe1234", |
| 19 | ) |
| 20 | assert r.success is True |
| 21 | assert r.blocked is False |
| 22 | assert r.head_moved is True |
| 23 | d = r.to_dict() |
| 24 | assert d["success"] is True |
| 25 | assert d["plan_hash"] == "deadbeefcafe" # truncated to 12 |
| 26 | |
| 27 | def test_blocked_checkout(self) -> None: |
| 28 | |
| 29 | r = CheckoutResult( |
| 30 | success=False, |
| 31 | blocked=True, |
| 32 | target="abc123", |
| 33 | drift_severity="DIRTY", |
| 34 | drift_total_changes=3, |
| 35 | status_code=409, |
| 36 | ) |
| 37 | assert r.success is False |
| 38 | assert r.blocked is True |
| 39 | assert r.drift_severity == "DIRTY" |
| 40 | assert r.drift_total_changes == 3 |
| 41 | |
| 42 | def test_force_recovery_checkout(self) -> None: |
| 43 | |
| 44 | r = CheckoutResult( |
| 45 | success=True, |
| 46 | blocked=False, |
| 47 | target="abc123", |
| 48 | head_moved=True, |
| 49 | executed=10, |
| 50 | ) |
| 51 | assert r.success is True |
| 52 | assert r.blocked is False |
| 53 | |
| 54 | |
| 55 | class TestMergeResult: |
| 56 | |
| 57 | def test_successful_merge(self) -> None: |
| 58 | |
| 59 | r = MergeResult( |
| 60 | success=True, |
| 61 | merge_variation_id="merge_abc", |
| 62 | executed=8, |
| 63 | ) |
| 64 | assert r.success is True |
| 65 | d = r.to_dict() |
| 66 | assert d["conflict_count"] == 0 |
| 67 | |
| 68 | def test_conflict_merge(self) -> None: |
| 69 | |
| 70 | r = MergeResult( |
| 71 | success=False, |
| 72 | conflicts=[ |
| 73 | {"region_id": "r_keys", "type": "note", "description": "Both sides modified note at pitch=48 beat=4.0"}, |
| 74 | {"region_id": "r_keys", "type": "cc", "description": "Both sides modified cc event at beat=0.0"}, |
| 75 | ], |
| 76 | status_code=409, |
| 77 | ) |
| 78 | assert r.success is False |
| 79 | d = r.to_dict() |
| 80 | assert d["conflict_count"] == 2 |
| 81 | assert len(d["conflicts"]) == 2 |
| 82 | |
| 83 | def test_no_common_ancestor(self) -> None: |
| 84 | |
| 85 | r = MergeResult( |
| 86 | success=False, |
| 87 | conflicts=[{"region_id": "*", "type": "note", "description": "No common ancestor"}], |
| 88 | status_code=409, |
| 89 | ) |
| 90 | assert not r.success |
| 91 | assert r.conflicts[0]["region_id"] == "*" |