"""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() # Make two local commits then push normally 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 # Now rewrite history locally (reset past the second commit) repo.reset_hard(1) # The previous commit b is preserved on someone else's clone (modeled) 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) # Drop commit b locally # Nobody has b anywhere 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) # b now only lives in reflog 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 # Every new commit's files should lack secrets.env 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