""" Tests for the search_system_factory module. These tests verify that the strategy registry is consistent with the factory. """ import pytest from unittest.mock import MagicMock class TestAvailableStrategies: """Tests for the AVAILABLE_STRATEGIES registry.""" def test_available_strategies_not_empty(self): """Test AVAILABLE_STRATEGIES is not empty.""" from local_deep_research.search_system_factory import ( AVAILABLE_STRATEGIES, ) assert len(AVAILABLE_STRATEGIES) > 0 def test_available_strategies_has_required_fields(self): """Test each strategy has name and description.""" from local_deep_research.search_system_factory import ( AVAILABLE_STRATEGIES, ) for strategy in AVAILABLE_STRATEGIES: assert "name" in strategy, f"Strategy missing 'name': {strategy}" assert "description" in strategy, ( f"Strategy missing 'description': {strategy}" ) assert len(strategy["name"]) > 0, "Strategy name is empty" assert len(strategy["description"]) > 0, ( "Strategy description is empty" ) def test_get_available_strategies_function(self): """Test get_available_strategies returns correct data.""" from local_deep_research.search_system_factory import ( get_available_strategies, AVAILABLE_STRATEGIES, ) result = get_available_strategies() assert result == AVAILABLE_STRATEGIES # Verify it's a copy assert result is not AVAILABLE_STRATEGIES class TestStrategyCreation: """Tests for create_strategy function.""" @pytest.fixture def mock_model(self): """Create a mock language model.""" model = MagicMock() model.invoke = MagicMock(return_value=MagicMock(content="test")) return model @pytest.fixture def mock_search(self): """Create a mock search engine.""" search = MagicMock() search.run = MagicMock(return_value=[]) return search def test_create_source_based_strategy(self, mock_model, mock_search): """Test creating source-based strategy.""" from local_deep_research.search_system_factory import create_strategy strategy = create_strategy("source-based", mock_model, mock_search) assert strategy is not None assert hasattr(strategy, "analyze_topic") def test_create_focused_iteration_strategy(self, mock_model, mock_search): """Test creating focused-iteration strategy.""" from local_deep_research.search_system_factory import create_strategy strategy = create_strategy("focused-iteration", mock_model, mock_search) assert strategy is not None def test_mcp_alias_routes_to_langgraph(self, mock_model, mock_search): """The removed 'mcp'/'agentic' keys are deprecated aliases that route to langgraph-agent (not the source-based fallback).""" from local_deep_research.search_system_factory import create_strategy for alias in ("mcp", "agentic"): strategy = create_strategy(alias, mock_model, mock_search) assert type(strategy).__name__ == "LangGraphAgentStrategy" def test_create_rapid_strategy(self, mock_model, mock_search): """Test creating rapid strategy.""" from local_deep_research.search_system_factory import create_strategy strategy = create_strategy("rapid", mock_model, mock_search) assert strategy is not None def test_create_unknown_strategy_defaults_to_source_based( self, mock_model, mock_search ): """Test unknown strategy defaults to source-based.""" from local_deep_research.search_system_factory import create_strategy strategy = create_strategy("unknown-strategy", mock_model, mock_search) assert strategy is not None # Should be source-based type assert "SourceBasedSearchStrategy" in type(strategy).__name__ def test_strategy_names_case_insensitive(self, mock_model, mock_search): """Test strategy names are case insensitive.""" from local_deep_research.search_system_factory import create_strategy strategy1 = create_strategy("SOURCE-BASED", mock_model, mock_search) strategy2 = create_strategy("source-based", mock_model, mock_search) assert type(strategy1).__name__ == type(strategy2).__name__ def test_strategy_names_with_underscores(self, mock_model, mock_search): """Test strategy names work with underscores instead of hyphens.""" from local_deep_research.search_system_factory import create_strategy strategy1 = create_strategy("source-based", mock_model, mock_search) strategy2 = create_strategy("source_based", mock_model, mock_search) assert type(strategy1).__name__ == type(strategy2).__name__ class TestStrategyRegistryConsistency: """Tests to verify the strategy registry matches available strategies.""" @pytest.fixture def mock_model(self): """Create a mock language model.""" model = MagicMock() model.invoke = MagicMock(return_value=MagicMock(content="test")) return model @pytest.fixture def mock_search(self): """Create a mock search engine.""" search = MagicMock() search.run = MagicMock(return_value=[]) return search def test_all_registered_strategies_can_be_created( self, mock_model, mock_search ): """Test that all strategies in AVAILABLE_STRATEGIES can be created.""" from local_deep_research.search_system_factory import ( AVAILABLE_STRATEGIES, create_strategy, ) # Known issues with some strategies (pre-existing bugs) known_issues = {} for strategy_info in AVAILABLE_STRATEGIES: name = strategy_info["name"] try: strategy = create_strategy(name, mock_model, mock_search) # Should not default to source-based (except for source-based itself) if name != "source-based": # Check it's not just defaulting assert strategy is not None, ( f"Strategy '{name}' returned None" ) except ImportError as e: # Some strategies may have optional dependencies pytest.skip(f"Strategy '{name}' has missing dependencies: {e}") except TypeError as e: # Known parameter compatibility issues if name in known_issues: pytest.skip( f"Known issue with '{name}': {known_issues[name]}" ) else: pytest.fail(f"Failed to create strategy '{name}': {e}") except Exception as e: pytest.fail(f"Failed to create strategy '{name}': {e}") def test_no_duplicate_strategy_names(self): """Test there are no duplicate strategy names in the registry.""" from local_deep_research.search_system_factory import ( AVAILABLE_STRATEGIES, ) names = [s["name"] for s in AVAILABLE_STRATEGIES] duplicates = [name for name in names if names.count(name) > 1] assert len(duplicates) == 0, ( f"Duplicate strategy names found: {set(duplicates)}" )