Add test files
This commit is contained in:
242
tests/test_cli.py
Normal file
242
tests/test_cli.py
Normal file
@@ -0,0 +1,242 @@
|
||||
"""Tests for CLI commands."""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import Mock, patch
|
||||
from click.testing import CliRunner
|
||||
|
||||
from src.cli.commands import cli, index_command, search_command, list_command
|
||||
from src.cli.interactive import run_interactive
|
||||
|
||||
|
||||
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))
|
||||
|
||||
result = runner.invoke(cli, ["interactive"])
|
||||
|
||||
mock_run.assert_called_once()
|
||||
Reference in New Issue
Block a user