Fix #13: Expose Pre-edit Backup restoration

Preserve full diff opcodes before grouping, route modal navigation to a two-axis viewport-sized scroller, and calculate side-by-side layout using terminal cell widths so tabbed Hosts File lines keep a stable divider.
This commit is contained in:
Philip Henning 2026-09-04 20:19:17 +02:00
parent 6a3e1e0d5a
commit e268794564
13 changed files with 1103 additions and 19 deletions

View file

@ -13,6 +13,7 @@ from unittest.mock import Mock, patch
from src.hosts.core.manager import PermissionManager, HostsManager
from src.hosts.core.models import HostEntry, HostsFile
from src.hosts.core.commands import ToggleEntryCommand
from src.hosts.core.restore_preview import fingerprint_file
class TestPermissionManager:
@ -592,15 +593,69 @@ class TestHostsManager:
manager._backup_path = Path(backup_file.name)
try:
manager.undo_redo_history.clear_history = Mock()
success, message = manager.restore_backup()
assert success
assert "restored successfully" in message
mock_run.assert_called_once()
assert mock_run.call_count == 2
assert mock_run.call_args_list[0].args[0][:2] == ["sudo", "cp"]
assert mock_run.call_args_list[0].args[0][-1] != temp_file.name
assert mock_run.call_args_list[1].args[0][:2] == ["sudo", "mv"]
assert mock_run.call_args_list[1].args[0][-1] == temp_file.name
manager.undo_redo_history.clear_history.assert_called_once_with()
finally:
# Clean up
manager._backup_path.unlink()
@patch("subprocess.run")
def test_restore_backup_copy_failure_leaves_hosts_file_target_untouched(
self, mock_run
):
"""A failed staged copy never opens the Hosts File target for writing."""
mock_run.return_value = Mock(returncode=1, stderr="Disk full")
with tempfile.NamedTemporaryFile() as temp_file:
manager = HostsManager(temp_file.name)
manager.edit_mode = True
with tempfile.NamedTemporaryFile(delete=False) as backup_file:
manager._backup_path = Path(backup_file.name)
try:
success, message = manager.restore_backup()
assert not success
assert "Disk full" in message
mock_run.assert_called_once()
assert mock_run.call_args.args[0][-1] != temp_file.name
finally:
manager._backup_path.unlink()
@patch("subprocess.run")
def test_restore_backup_refuses_files_that_changed_since_preview(self, mock_run):
"""The privileged write uses the exact source and target the user reviewed."""
with tempfile.NamedTemporaryFile() as temp_file:
manager = HostsManager(temp_file.name)
manager.edit_mode = True
with tempfile.NamedTemporaryFile(delete=False) as backup_file:
backup_file.write(b"127.0.0.1 restored.test\n")
manager._backup_path = Path(backup_file.name)
try:
backup_digest = fingerprint_file(
manager._backup_path, "Pre-edit Backup"
)
hosts_digest = fingerprint_file(manager.parser.file_path, "Hosts File")
Path(temp_file.name).write_text("192.0.2.2 changed.test\n")
success, message = manager.restore_backup(backup_digest, hosts_digest)
assert not success
assert "changed since review" in message
mock_run.assert_not_called()
finally:
manager._backup_path.unlink()
def test_restore_backup_not_in_edit_mode(self):
"""Test restoring backup when not in edit mode."""
with tempfile.NamedTemporaryFile() as temp_file: