from __future__ import annotations from pathlib import Path from subprocess import CompletedProcess import pytest from app.opener import ( OpenWithOption, available_openers, is_blocking_option, launch_background_option, launch_blocking_option, ) def test_available_openers_headless_file_excludes_gui( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: file_path = tmp_path / "notes.txt" file_path.write_text("hello", encoding="utf-8") monkeypatch.setenv("SSH_CONNECTION", "1") available = { "antigravity": "/usr/local/bin/antigravity", "nvim": "/usr/local/bin/nvim", "nano": "/usr/bin/nano", "less": "/usr/bin/less", "bat": "/usr/local/bin/bat", "code": "/usr/local/bin/code", "open": "/usr/bin/open", } monkeypatch.setattr("app.opener.shutil.which", lambda name: available.get(name)) labels = [option.label for option in available_openers(file_path)] assert "VS Code" not in labels assert "Open (system)" not in labels assert labels == ["Antigravity", "Neovim", "Nano", "Less", "Bat"] def test_available_openers_gui_directory_filters_file_only_tools( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: folder = tmp_path / "project" folder.mkdir() monkeypatch.delenv("SSH_CONNECTION", raising=False) monkeypatch.setattr("app.opener.sys.platform", "darwin") available = { "antigravity": "/usr/local/bin/antigravity", "nvim": "/usr/local/bin/nvim", "nano": "/usr/bin/nano", "less": "/usr/bin/less", "bat": "/usr/local/bin/bat", "code": "/usr/local/bin/code", "open": "/usr/bin/open", } monkeypatch.setattr("app.opener.shutil.which", lambda name: available.get(name)) labels = [option.label for option in available_openers(folder)] assert labels == ["VS Code", "Antigravity", "Neovim"] def test_launch_background_option_returns_success( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: option = OpenWithOption( label="VS Code", command_template="code {path}", executable="code", launch_mode="background", requires_gui=True, ) monkeypatch.setattr("app.opener.subprocess.Popen", lambda *args, **kwargs: None) success, message = launch_background_option(tmp_path, option) assert success is True assert "VS Code" in message def test_launch_blocking_option_reports_non_zero_exit( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: option = OpenWithOption( label="Neovim", command_template="nvim {path}", executable="nvim", launch_mode="blocking", ) monkeypatch.setattr( "app.opener.subprocess.run", lambda *args, **kwargs: CompletedProcess(args=[], returncode=2), ) success, message = launch_blocking_option(tmp_path, option) assert success is False assert "code 2" in message def test_is_blocking_option_uses_launch_mode() -> None: blocking = OpenWithOption( label="Neovim", command_template="nvim {path}", executable="nvim", launch_mode="blocking", ) background = OpenWithOption( label="VS Code", command_template="code {path}", executable="code", launch_mode="background", ) assert is_blocking_option(blocking) is True assert is_blocking_option(background) is False def test_launch_blocking_option_handles_paths_with_spaces( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: target_path = tmp_path / "COMPETENCIAS A.LEDO" option = OpenWithOption( label="Neovim", command_template="nvim {path}", executable="nvim", launch_mode="blocking", ) captured: dict[str, list[str]] = {} def fake_run(command: list[str], check: bool) -> CompletedProcess[object]: captured["command"] = command return CompletedProcess(args=[], returncode=0) monkeypatch.setattr("app.opener.subprocess.run", fake_run) success, _message = launch_blocking_option(target_path, option) assert success is True assert captured["command"] == ["nvim", str(target_path)]