"""Integration tests for external editor - launches real editors.""" import os import tempfile import pytest from unittest.mock import patch, MagicMock from src.external_editor import ( ExternalEditorLauncher, ExternalEditorConfig, TextEditorConfig, create_temp_modified_file, ) @pytest.fixture def vscode_editor(): return TextEditorConfig(name="vscode", path="code.exe", diff_args=["--diff"]) @pytest.fixture def ext_config(vscode_editor): return ExternalEditorConfig(editors={"vscode": vscode_editor}, default_editor="vscode") @pytest.fixture def launcher(ext_config): return ExternalEditorLauncher(ext_config) class TestExternalEditorIntegration: def test_create_temp_modified_file_creates_valid_file(self): content = "line1\nline2\nline3\n" path = create_temp_modified_file(content) try: assert os.path.exists(path) with open(path, encoding="utf-8") as f: assert f.read() == content finally: if os.path.exists(path): os.unlink(path) def test_build_diff_command_format(self, launcher, vscode_editor): cmd = launcher.build_diff_command(vscode_editor, "original.txt", "modified.txt") assert cmd == ["code.exe", "--diff", "original.txt", "modified.txt"] @patch("subprocess.Popen") def test_launch_diff_calls_subprocess(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_with(["code.exe", "--diff", "orig.txt", "mod.txt"]) @patch("subprocess.Popen") def test_launch_diff_with_real_files(self, mock_popen, launcher): mock_popen.return_value = MagicMock() with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False, encoding="utf-8") as f: f.write("original content\n") orig_path = f.name try: mod_path = create_temp_modified_file("modified content\n") try: result = launcher.launch_diff("vscode", orig_path, mod_path) assert result is not None call_args = mock_popen.call_args[0][0] assert call_args[0] == "code.exe" assert call_args[1] == "--diff" assert call_args[2] == orig_path assert call_args[3] == mod_path finally: if os.path.exists(mod_path): os.unlink(mod_path) finally: if os.path.exists(orig_path): os.unlink(orig_path) class TestExternalEditorWithRealVSCode: @pytest.mark.skipif( os.environ.get("TEST_REAL_VSCODE") != "1", reason="Set TEST_REAL_VSCODE=1 environment variable to run this test" ) def test_launch_real_vscode_diff(self): vscode_path = os.environ.get("VSCODE_PATH", "code.exe") if not os.path.exists(vscode_path) and vscode_path == "code.exe": import shutil if not shutil.which("code"): pytest.skip("VSCode not found in PATH") config = ExternalEditorConfig( editors={"vscode": TextEditorConfig(name="vscode", path=vscode_path, diff_args=["--diff"])}, default_editor="vscode" ) launcher = ExternalEditorLauncher(config) with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False, encoding="utf-8") as f: f.write("line1\nline2\nline3\n") orig_path = f.name try: mod_path = create_temp_modified_file("line1\nmodified line2\nline3\n") try: import subprocess proc = launcher.launch_diff("vscode", orig_path, mod_path) assert proc is not None import time time.sleep(1) proc.terminate() proc.wait(timeout=5) finally: if os.path.exists(mod_path): os.unlink(mod_path) finally: if os.path.exists(orig_path): os.unlink(orig_path) if __name__ == "__main__": pytest.main([__file__, "-v"])