mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-14 08:09:16 +03:00
113 lines
3.9 KiB
Python
113 lines
3.9 KiB
Python
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from nanobot.webui import native_folder_picker as picker
|
|
|
|
|
|
def _picker_command(tmp_path: Path, body: str) -> picker._PickerCommand:
|
|
script = tmp_path / "picker.py"
|
|
script.write_text(f"{body}\n", encoding="utf-8")
|
|
return picker._PickerCommand((sys.executable, str(script)), frozenset({1}))
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_pick_native_folder_returns_selected_directory(tmp_path, monkeypatch) -> None:
|
|
selected = tmp_path / "project"
|
|
selected.mkdir()
|
|
command = _picker_command(tmp_path, f"print({str(selected)!r}, end='')")
|
|
monkeypatch.setattr(
|
|
picker,
|
|
"_picker_command",
|
|
lambda: command,
|
|
)
|
|
|
|
assert await picker.pick_native_folder() == str(selected)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_pick_native_folder_uses_secret_free_environment(tmp_path, monkeypatch) -> None:
|
|
selected = tmp_path / "project"
|
|
selected.mkdir()
|
|
command = _picker_command(tmp_path, f"print({str(selected)!r}, end='')")
|
|
monkeypatch.setattr(picker, "_picker_command", lambda: command)
|
|
monkeypatch.setenv("HOME", str(tmp_path))
|
|
monkeypatch.setenv("OPENAI_API_KEY", "must-not-reach-picker")
|
|
original_spawn = picker.asyncio.create_subprocess_exec
|
|
captured_env: dict[str, str] = {}
|
|
|
|
async def capture_spawn(*args, **kwargs):
|
|
captured_env.update(kwargs["env"])
|
|
return await original_spawn(*args, **kwargs)
|
|
|
|
monkeypatch.setattr(picker.asyncio, "create_subprocess_exec", capture_spawn)
|
|
|
|
assert await picker.pick_native_folder() == str(selected)
|
|
assert captured_env["HOME"] == str(tmp_path)
|
|
assert "OPENAI_API_KEY" not in captured_env
|
|
|
|
|
|
def test_picker_environment_preserves_linux_display_context(monkeypatch) -> None:
|
|
monkeypatch.setattr(picker.sys, "platform", "linux")
|
|
monkeypatch.setenv("DISPLAY", ":42")
|
|
monkeypatch.setenv("DBUS_SESSION_BUS_ADDRESS", "unix:path=/run/user/test/bus")
|
|
monkeypatch.setenv("ANTHROPIC_API_KEY", "must-not-reach-picker")
|
|
|
|
environment = picker._picker_environment()
|
|
|
|
assert environment["DISPLAY"] == ":42"
|
|
assert environment["DBUS_SESSION_BUS_ADDRESS"] == "unix:path=/run/user/test/bus"
|
|
assert "ANTHROPIC_API_KEY" not in environment
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_pick_native_folder_maps_dialog_cancel_to_none(tmp_path, monkeypatch) -> None:
|
|
command = _picker_command(tmp_path, "raise SystemExit(1)")
|
|
monkeypatch.setattr(
|
|
picker,
|
|
"_picker_command",
|
|
lambda: command,
|
|
)
|
|
|
|
assert await picker.pick_native_folder() is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_pick_native_folder_rejects_non_directory_result(tmp_path, monkeypatch) -> None:
|
|
missing = tmp_path / "missing"
|
|
command = _picker_command(tmp_path, f"print({str(missing)!r}, end='')")
|
|
monkeypatch.setattr(
|
|
picker,
|
|
"_picker_command",
|
|
lambda: command,
|
|
)
|
|
|
|
with pytest.raises(picker.NativeFolderPickerError, match="invalid directory"):
|
|
await picker.pick_native_folder()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_pick_native_folder_reports_unavailable(monkeypatch) -> None:
|
|
monkeypatch.setattr(picker, "_picker_command", lambda: None)
|
|
|
|
assert picker.native_folder_picker_available() is False
|
|
with pytest.raises(picker.NativeFolderPickerError, match="unavailable"):
|
|
await picker.pick_native_folder()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_pick_native_folder_wraps_process_start_failure(tmp_path, monkeypatch) -> None:
|
|
command = _picker_command(tmp_path, "raise AssertionError('not started')")
|
|
monkeypatch.setattr(picker, "_picker_command", lambda: command)
|
|
|
|
async def fail_spawn(*args, **kwargs):
|
|
raise OSError("executable disappeared")
|
|
|
|
monkeypatch.setattr(picker.asyncio, "create_subprocess_exec", fail_spawn)
|
|
|
|
with pytest.raises(picker.NativeFolderPickerError, match="failed to start"):
|
|
await picker.pick_native_folder()
|