| """Tests for permanence.world.git — reversibility + isolation.""" |
| from __future__ import annotations |
|
|
| import socket |
| import subprocess |
| from unittest.mock import patch |
|
|
| from permanence.world.git import MockGitRepo |
|
|
|
|
| def test_initial_commit_and_log_are_r1_r2(): |
| repo = MockGitRepo() |
| res = repo.commit("add feature", {"src/main.py": b"print(1)"}) |
| assert res.ok and res.r_level == 2 |
| log_res = repo.log() |
| assert log_res.ok and log_res.r_level == 1 |
|
|
|
|
| def test_reset_hard_is_r3_via_reflog(): |
| repo = MockGitRepo() |
| repo.commit("a", {"a": b"1"}) |
| repo.commit("b", {"a": b"1", "b": b"2"}) |
| res = repo.reset_hard(1) |
| assert res.ok and res.r_level == 3 |
| assert len(res.orphaned_commits) == 1 |
|
|
|
|
| def test_reset_hard_after_reflog_expired_is_r4(): |
| repo = MockGitRepo() |
| repo.commit("a", {"a": b"1"}) |
| repo.commit("b", {"a": b"1", "b": b"2"}) |
| repo.reflog_expire_all() |
| res = repo.reset_hard(1) |
| assert res.ok and res.r_level == 4 |
|
|
|
|
| def test_branch_delete_with_reflog_is_r3(): |
| repo = MockGitRepo() |
| repo.checkout_branch("feature", create=True) |
| repo.commit("feature work", {"x": b"1"}) |
| repo.checkout_branch("main") |
| res = repo.delete_branch("feature") |
| assert res.ok and res.r_level == 3 |
| assert len(res.orphaned_commits) == 1 |
|
|
|
|
| def test_push_is_r2_and_force_push_preserved_elsewhere_is_r4(): |
| repo = MockGitRepo() |
| |
| repo.commit("a", {"a": b"1"}) |
| repo.commit("b", {"a": b"1", "b": b"2"}) |
| push = repo.push() |
| assert push.ok and push.r_level == 2 |
|
|
| |
| repo.reset_hard(1) |
| |
| remote_tip = repo.remote_branches["main"] |
| repo.other_clones_have_commits.add(remote_tip) |
| res = repo.push_force() |
| assert res.ok and res.r_level == 4 |
|
|
|
|
| def test_force_push_without_preservation_is_r5(): |
| repo = MockGitRepo() |
| repo.commit("a", {"a": b"1"}) |
| repo.commit("b", {"a": b"1", "b": b"2"}) |
| repo.push() |
| repo.reset_hard(1) |
| |
| res = repo.push_force() |
| assert res.ok and res.r_level == 5 |
| assert len(res.orphaned_commits) >= 1 |
|
|
|
|
| def test_reflog_expire_all_with_orphans_is_r5(): |
| repo = MockGitRepo() |
| repo.commit("a", {"a": b"1"}) |
| repo.commit("b", {"a": b"1", "b": b"2"}) |
| repo.reset_hard(1) |
| res = repo.reflog_expire_all() |
| assert res.ok and res.r_level == 5 |
|
|
|
|
| def test_filter_branch_rewrites_history_r4(): |
| repo = MockGitRepo() |
| repo.commit("add secrets", {"src/main.py": b"x", "secrets.env": b"KEY=abc"}) |
| repo.commit("more work", {"src/main.py": b"y", "secrets.env": b"KEY=abc"}) |
| res = repo.filter_branch_drop("secrets.env") |
| assert res.ok and res.r_level == 4 |
| |
| tip = repo.branches["main"] |
| assert "secrets.env" not in repo.commits[tip].files |
|
|
|
|
| def test_mock_git_never_shells_out_or_hits_network(): |
| """Same isolation guarantee as the mock FS.""" |
| with patch.object(subprocess, "run") as mock_run, patch.object( |
| subprocess, "Popen" |
| ) as mock_popen, patch.object(socket, "socket") as mock_sock: |
| repo = MockGitRepo() |
| repo.commit("x", {"a": b"1"}) |
| repo.checkout_branch("feat", create=True) |
| repo.commit("y", {"a": b"2"}) |
| repo.checkout_branch("main") |
| repo.delete_branch("feat") |
| repo.push() |
| repo.reset_hard(1) |
| repo.push_force() |
| assert mock_run.call_count == 0 |
| assert mock_popen.call_count == 0 |
| assert mock_sock.call_count == 0 |
|
|