111 lines
3.6 KiB
Python
111 lines
3.6 KiB
Python
"""Behavioral coverage for registry-aware picker and deprecation UX."""
|
|
|
|
from io import StringIO
|
|
import sys
|
|
import time
|
|
from unittest.mock import patch
|
|
|
|
import cmdforge.cli.picker as picker
|
|
import pytest
|
|
from cmdforge import __version__
|
|
from cmdforge.cli.picker import PickerResult
|
|
|
|
|
|
class FakeTTY:
|
|
def __init__(self, *characters):
|
|
self.characters = iter(characters)
|
|
|
|
def getch(self, timeout=None):
|
|
if timeout is not None:
|
|
time.sleep(0.01)
|
|
return None
|
|
return next(self.characters)
|
|
|
|
|
|
def setup_function():
|
|
picker._registry_cache.clear()
|
|
picker._ui_out = StringIO()
|
|
|
|
|
|
def test_public_registry_search_does_not_require_token():
|
|
class Client:
|
|
token = ""
|
|
|
|
def semantic_search(self, query, limit):
|
|
return {"available": False, "data": [], "error": None}
|
|
|
|
def search_tools(self, query, per_page):
|
|
return [{
|
|
"owner": "official", "name": "weather",
|
|
"description": "Weather", "score": 0.8,
|
|
"quality_score": 91, "quality_coverage": 70,
|
|
}]
|
|
|
|
with patch("cmdforge.registry_client.get_client", return_value=Client()):
|
|
results = picker.search_registry("weather")
|
|
assert results[0]["name"] == "official/weather"
|
|
assert results[0]["quality_score"] == 91
|
|
assert results[0]["quality_coverage"] == 70
|
|
|
|
|
|
def test_picker_can_install_when_no_local_tools():
|
|
registry_tool = {
|
|
"name": "official/weather", "desc": "Weather", "args": [],
|
|
"registry": True, "quality_score": 91, "quality_coverage": 70,
|
|
"relevance": 0.8,
|
|
}
|
|
with patch.object(picker, "get_tools", return_value=[]), patch.object(
|
|
picker, "search_registry", return_value=[registry_tool]
|
|
), patch.object(
|
|
picker, "_install_registry_selection",
|
|
return_value=PickerResult("official/weather", {}),
|
|
) as install:
|
|
result = picker.run_picker(FakeTTY("w", "e", "\n"))
|
|
install.assert_called_once()
|
|
assert result.tool_name == "official/weather"
|
|
assert "Q91/70%" in picker._ui_out.getvalue()
|
|
|
|
|
|
def test_tab_installs_registry_selection_too():
|
|
registry_tool = {
|
|
"name": "official/weather", "desc": "Weather", "args": [],
|
|
"registry": True,
|
|
}
|
|
with patch.object(picker, "get_tools", return_value=[]), patch.object(
|
|
picker, "search_registry", return_value=[registry_tool]
|
|
), patch.object(
|
|
picker, "_install_registry_selection",
|
|
return_value=PickerResult("official/weather", {}),
|
|
) as install:
|
|
result = picker.run_picker(FakeTTY("w", "e", "\t"))
|
|
install.assert_called_once()
|
|
assert result.tool_name == "official/weather"
|
|
|
|
|
|
def test_local_deprecation_selection_prints_migration_guidance():
|
|
tool = {
|
|
"name": "old", "desc": "", "args": [], "deprecated": True,
|
|
"deprecated_message": "Moved.", "replacement": "official/new",
|
|
}
|
|
result = picker._local_selection(tool)
|
|
assert result.tool_name == "old"
|
|
output = picker._ui_out.getvalue()
|
|
assert "Moved." in output
|
|
assert "official/new" in output
|
|
|
|
|
|
def test_picker_help_does_not_require_a_terminal(capsys):
|
|
with patch.object(sys, "argv", ["cf", "--help"]), pytest.raises(SystemExit) as exc:
|
|
picker.main()
|
|
|
|
assert exc.value.code == 0
|
|
assert "Interactively find and run" in capsys.readouterr().out
|
|
|
|
|
|
def test_picker_version_does_not_require_a_terminal(capsys):
|
|
with patch.object(sys, "argv", ["cf", "--version"]), pytest.raises(SystemExit) as exc:
|
|
picker.main()
|
|
|
|
assert exc.value.code == 0
|
|
assert f"cf {__version__}" in capsys.readouterr().out
|