Files
local-api-docs-search/tests/test_cli.py
7000pctAUTO e6e2e8d9f0
Some checks failed
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / build (push) Has been cancelled
CI / test (3.10) (push) Has been cancelled
fix: resolve CI/CD issues - remove unused variables and add type stubs
2026-02-03 01:38:55 +00:00

242 lines
7.8 KiB
Python

"""Tests for CLI commands."""
import pytest
from unittest.mock import Mock, patch
from click.testing import CliRunner
from src.cli.commands import cli
class TestCLIBasics:
"""Basic CLI tests."""
@pytest.fixture
def runner(self):
"""Create a CLI runner."""
return CliRunner()
def test_cli_help(self, runner):
"""Test CLI help output."""
result = runner.invoke(cli, ["--help"])
assert result.exit_code == 0
assert "Local API Docs Search" in result.output
def test_cli_verbose_flag(self, runner):
"""Test verbose flag parsing."""
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.get_stats.return_value = Mock(total_documents=0)
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["--verbose", "list"])
assert result.exit_code == 0
class TestIndexCommand:
"""Tests for the index command."""
@pytest.fixture
def runner(self):
"""Create a CLI runner."""
return CliRunner()
def test_index_requires_path(self, runner):
"""Test that index command requires a path."""
result = runner.invoke(cli, ["index"])
assert result.exit_code != 0
assert "Missing argument" in result.output or "path" in result.output.lower()
def test_index_invalid_path(self, runner):
"""Test index with non-existent path."""
result = runner.invoke(cli, ["index", "/nonexistent/path"])
assert result.exit_code != 0
def test_index_type_option(self, runner, tmp_path):
"""Test index with type option."""
openapi_file = tmp_path / "test.yaml"
openapi_file.write_text("openapi: '3.0.0'\ninfo:\n title: Test\n version: '1.0'\npaths: {}")
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.index.return_value = 1
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["index", str(tmp_path), "--type", "openapi"])
assert result.exit_code == 0
mock_searcher.index.assert_called_once()
def test_index_recursive_option(self, runner, tmp_path):
"""Test index with recursive option."""
subdir = tmp_path / "subdir"
subdir.mkdir()
openapi_file = subdir / "test.yaml"
openapi_file.write_text("openapi: '3.0.0'\ninfo:\n title: Test\n version: '1.0'\npaths: {}")
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.index.return_value = 1
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["index", str(tmp_path), "--recursive"])
assert result.exit_code == 0
class TestSearchCommand:
"""Tests for the search command."""
@pytest.fixture
def runner(self):
"""Create a CLI runner."""
return CliRunner()
def test_search_requires_query(self, runner):
"""Test that search requires a query."""
result = runner.invoke(cli, ["search"])
assert result.exit_code != 0
assert "Missing argument" in result.output
def test_search_limit_option(self, runner):
"""Test search with limit option."""
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.hybrid_search.return_value = []
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["search", "test", "--limit", "5"])
assert result.exit_code == 0
mock_searcher.hybrid_search.assert_called_once()
def test_search_type_filter(self, runner):
"""Test search with type filter."""
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.hybrid_search.return_value = []
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["search", "test", "--type", "openapi"])
assert result.exit_code == 0
def test_search_json_output(self, runner):
"""Test search with JSON output."""
from src.models.document import Document, SourceType, SearchResult
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_doc = Document(
id="test",
content="test content",
source_type=SourceType.OPENAPI,
title="Test",
)
mock_result = SearchResult(document=mock_doc, score=0.9)
mock_searcher.hybrid_search.return_value = [mock_result]
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["search", "test", "--json"])
assert result.exit_code == 0
assert "test" in result.output or '"' in result.output
class TestListCommand:
"""Tests for the list command."""
@pytest.fixture
def runner(self):
"""Create a CLI runner."""
return CliRunner()
def test_list_command(self, runner):
"""Test list command."""
from src.models.document import IndexStats
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_stats = IndexStats(
total_documents=10,
openapi_count=5,
readme_count=3,
code_count=2,
)
mock_searcher.get_stats.return_value = mock_stats
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["list"])
assert result.exit_code == 0
assert "10" in result.output or "total" in result.output.lower()
def test_list_with_type_filter(self, runner):
"""Test list with type filter."""
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.get_stats.return_value = Mock(total_documents=5)
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["list", "--type", "openapi"])
assert result.exit_code == 0
class TestConfigCommand:
"""Tests for the config command."""
@pytest.fixture
def runner(self):
"""Create a CLI runner."""
return CliRunner()
def test_config_show(self, runner):
"""Test config show command."""
with patch("src.cli.commands.get_config") as mock_get_config:
mock_config = Mock()
mock_config.to_dict.return_value = {
"index_path": "./docs",
"model_name": "test-model",
}
mock_get_config.return_value = mock_config
result = runner.invoke(cli, ["config", "--show"])
assert result.exit_code == 0
assert "./docs" in result.output or "test-model" in result.output
def test_config_reset(self, runner):
"""Test config reset command."""
with patch("src.cli.commands.get_config") as mock_get_config:
mock_config = Mock()
mock_get_config.return_value = mock_config
result = runner.invoke(cli, ["config", "--reset"])
assert result.exit_code == 0
mock_config.reset.assert_called_once()
class TestInteractiveCommand:
"""Tests for the interactive command."""
@pytest.fixture
def runner(self):
"""Create a CLI runner."""
return CliRunner()
def test_interactive_command(self, runner):
"""Test interactive command."""
with patch("src.cli.interactive.run_interactive") as mock_run:
mock_run.side_effect = (KeyboardInterrupt, SystemExit(0))
runner.invoke(cli, ["interactive"])
mock_run.assert_called_once()