"""Tests for external editor integration.""" import pytest from unittest.mock import patch, MagicMock from src.models import TextEditorConfig, ExternalEditorConfig from src.external_editor import ( ExternalEditorLauncher, get_default_launcher, resolve_project_editor_override, create_temp_modified_file, ) @pytest.fixture def vscode_editor(): return TextEditorConfig(name="vscode", path="C:\\path\\to\\code.exe", diff_args=["--diff"]) @pytest.fixture def notepadpp_editor(): return TextEditorConfig(name="notepad++", path="C:\\path\\to\\notepad++.exe", diff_args=["-multiInst", "-nosession"]) @pytest.fixture def ext_config(vscode_editor, notepadpp_editor): return ExternalEditorConfig( editors={"vscode": vscode_editor, "notepad++": notepadpp_editor}, default_editor="vscode", ) @pytest.fixture def launcher(ext_config): return ExternalEditorLauncher(ext_config) class TestTextEditorConfig: def test_from_dict_with_diff_args(self): data = {"name": "vscode", "path": "C:\\code.exe", "diff_args": ["--diff"]} editor = TextEditorConfig.from_dict(data) assert editor.name == "vscode" assert editor.path == "C:\\code.exe" assert editor.diff_args == ["--diff"] def test_from_dict_without_diff_args(self): data = {"name": "vscode", "path": "C:\\code.exe"} editor = TextEditorConfig.from_dict(data) assert editor.diff_args == [] def test_to_dict(self, vscode_editor): result = vscode_editor.to_dict() assert result["name"] == "vscode" assert result["path"] == "C:\\path\\to\\code.exe" assert result["diff_args"] == ["--diff"] class TestExternalEditorConfig: def test_from_dict_with_string_editors(self): data = {"editors": {"vscode": "C:\\code.exe"}, "default_editor": "vscode"} config = ExternalEditorConfig.from_dict(data) assert "vscode" in config.editors assert config.editors["vscode"].path == "C:\\code.exe" def test_from_dict_with_dict_editors(self, vscode_editor): data = {"editors": {"vscode": {"name": "vscode", "path": "C:\\code.exe", "diff_args": ["--diff"]}}} config = ExternalEditorConfig.from_dict(data) assert config.editors["vscode"].diff_args == ["--diff"] def test_get_default_returns_configured(self, ext_config): result = ext_config.get_default() assert result.name == "vscode" def test_get_default_fallback_to_first(self): config = ExternalEditorConfig(editors={"notepad++": TextEditorConfig(name="notepad++", path="C:\\npp.exe")}) result = config.get_default() assert result.name == "notepad++" def test_get_default_returns_none_when_empty(self): config = ExternalEditorConfig(editors={}) assert config.get_default() is None def test_to_dict(self, ext_config): result = ext_config.to_dict() assert result["default_editor"] == "vscode" assert "vscode" in result["editors"] class TestExternalEditorLauncher: def test_get_editor_by_name(self, launcher): editor = launcher.get_editor("notepad++") assert editor.name == "notepad++" def test_get_editor_returns_default(self, launcher): editor = launcher.get_editor() assert editor.name == "vscode" def test_get_editor_unknown_name(self, launcher): editor = launcher.get_editor("unknown") assert editor is None def test_build_diff_command(self, launcher, vscode_editor): cmd = launcher.build_diff_command(vscode_editor, "orig.txt", "mod.txt") assert cmd == ["C:\\path\\to\\code.exe", "--diff", "orig.txt", "mod.txt"] def test_launch_diff_missing_editor(self, launcher): result = launcher.launch_diff("nonexistent", "orig.txt", "mod.txt") assert result is None @patch("subprocess.Popen") def test_launch_diff_success(self, mock_popen, launcher): mock_popen.return_value = MagicMock() result = launcher.launch_diff("vscode", "orig.txt", "mod.txt") assert result is not None mock_popen.assert_called_once() @patch("subprocess.Popen") def test_launch_diff_file_not_found(self, mock_popen, launcher): mock_popen.side_effect = FileNotFoundError() result = launcher.launch_diff("vscode", "orig.txt", "mod.txt") assert result is None class TestHelperFunctions: def test_create_temp_modified_file(self): content = "test content" path = create_temp_modified_file(content) assert path.endswith("_modified") with open(path, encoding="utf-8") as f: assert f.read() == content import os os.unlink(path)