Add speech-first diff review mode with navigation and tests

This commit is contained in:
Storm Dragon
2026-02-15 15:55:46 -05:00
parent 1e67876883
commit 4050c32a16
31 changed files with 1628 additions and 3 deletions

View File

@@ -0,0 +1,135 @@
"""
Unit tests for DiffReviewManager parsing and presentation behavior.
"""
from unittest.mock import Mock
import pytest
import fenrirscreenreader.core.diffReviewManager as diff_review_module
from fenrirscreenreader.core.diffReviewManager import DiffReviewManager
@pytest.fixture
def diff_manager(monkeypatch):
"""Create a DiffReviewManager with a minimal test environment."""
monkeypatch.setattr(diff_review_module, "_", lambda text: text)
spoken_messages = []
output_manager = Mock()
def _capture_message(message, **_kwargs):
spoken_messages.append(message)
output_manager.present_text.side_effect = _capture_message
settings_manager = Mock()
settings_manager.get_setting.side_effect = (
lambda section, setting: "compact"
if (section, setting) == ("general", "diff_verbosity")
else "default"
)
env = {
"runtime": {
"DebugManager": Mock(write_debug_out=Mock()),
"OutputManager": output_manager,
"SettingsManager": settings_manager,
"MemoryManager": Mock(
is_index_list_empty=Mock(return_value=True),
get_index_list_element=Mock(return_value=""),
),
},
"bindings": {},
"rawBindings": {},
}
manager = DiffReviewManager()
manager.initialize(env)
return manager, spoken_messages
@pytest.mark.unit
class TestDiffReviewManager:
"""Test diff review parsing and speech presentation edge cases."""
def test_parse_unified_diff_tracks_sections_and_counts(self, diff_manager):
manager, _ = diff_manager
lines = [
"diff --git a/example.txt b/example.txt",
"index 1111111..2222222 100644",
"--- a/example.txt",
"+++ b/example.txt",
"@@ -1,2 +1,3 @@",
" context line",
"-old line",
"+new line one",
"+new line two",
]
manager._parse_lines(lines, "/tmp/example.diff")
assert len(manager.file_sections) == 1
assert len(manager.hunk_sections) == 1
assert manager.total_added == 2
assert manager.total_removed == 1
assert manager.file_sections[0]["added_count"] == 2
assert manager.file_sections[0]["removed_count"] == 1
assert manager.hunk_sections[0]["position_in_file"] == 1
assert manager.hunk_sections[0]["hunks_in_file"] == 1
def test_formats_classic_diff_markers(self, diff_manager):
manager, _ = diff_manager
assert manager._format_classic_diff_command("17c17") == "line 17 changed"
assert manager._format_classic_diff_command("17d16") == "line 17 deleted"
assert manager._format_classic_diff_command("16a17") == "line 17 added"
assert (
manager._format_classic_diff_command("20,22c30,32")
== "lines 20 through 22 changed"
)
assert manager._format_classic_diff_command("not a diff marker") is None
def test_announces_classic_marker_line_as_plain_language(self, diff_manager):
manager, spoken_messages = diff_manager
manager._parse_lines(["17c17"], "/tmp/classic.diff")
manager.current_line = 0
manager._announce_current_line()
assert spoken_messages[-1] == "line 17 changed"
def test_marker_only_added_removed_lines_become_words(self, diff_manager):
manager, spoken_messages = diff_manager
manager._parse_lines(["+++", "---"], "/tmp/markers.diff")
manager.current_line = 0
manager._announce_current_line()
manager.current_line = 1
manager._announce_current_line()
assert spoken_messages[-2] == "added"
assert spoken_messages[-1] == "removed"
def test_large_diff_parsing_stays_consistent(self, diff_manager):
manager, spoken_messages = diff_manager
line_count = 1500
lines = [
"diff --git a/large.txt b/large.txt",
"--- a/large.txt",
"+++ b/large.txt",
"@@ -1,1500 +1,1500 @@",
]
for index in range(1, line_count + 1):
lines.append(f"-old value {index}")
lines.append(f"+new value {index}")
manager._parse_lines(lines, "/tmp/large.diff")
manager.next_added()
assert len(manager.file_sections) == 1
assert len(manager.hunk_sections) == 1
assert manager.total_added == line_count
assert manager.total_removed == line_count
assert manager.current_line == manager.added_lines[0]
assert spoken_messages[-1].startswith("Added line.")