""" Comprehensive tests for TopicBasedRecommender class. Tests recommendation generation, topic filtering, and user preferences. """ from unittest.mock import Mock, patch class TestTopicBasedRecommenderInit: """Tests for TopicBasedRecommender initialization.""" def test_inherits_from_base(self): """Test inherits from BaseRecommender.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) from local_deep_research.news.recommender.base_recommender import ( BaseRecommender, ) assert issubclass(TopicBasedRecommender, BaseRecommender) def test_default_max_recommendations(self): """Test default max_recommendations is 5.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() assert recommender.max_recommendations == 5 class TestGenerateRecommendations: """Tests for generate_recommendations method.""" @patch.object( __import__( "local_deep_research.news.recommender.topic_based", fromlist=["TopicBasedRecommender"], ).TopicBasedRecommender, "_get_trending_topics", ) @patch.object( __import__( "local_deep_research.news.recommender.topic_based", fromlist=["TopicBasedRecommender"], ).TopicBasedRecommender, "_get_user_preferences", ) @patch.object( __import__( "local_deep_research.news.recommender.topic_based", fromlist=["TopicBasedRecommender"], ).TopicBasedRecommender, "_filter_topics_by_preferences", ) @patch.object( __import__( "local_deep_research.news.recommender.topic_based", fromlist=["TopicBasedRecommender"], ).TopicBasedRecommender, "_sort_by_relevance", ) def test_returns_list( self, mock_sort, mock_filter, mock_prefs, mock_topics ): """Test returns a list.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) mock_topics.return_value = [] mock_prefs.return_value = {} mock_filter.return_value = [] mock_sort.return_value = [] recommender = TopicBasedRecommender() result = recommender.generate_recommendations("user123") assert isinstance(result, list) @patch.object( __import__( "local_deep_research.news.recommender.topic_based", fromlist=["TopicBasedRecommender"], ).TopicBasedRecommender, "_get_trending_topics", ) def test_updates_progress(self, mock_topics): """Test updates progress during generation.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) mock_topics.return_value = [] recommender = TopicBasedRecommender() recommender._update_progress = Mock() with patch.object( recommender, "_get_user_preferences", return_value={} ): with patch.object( recommender, "_filter_topics_by_preferences", return_value=[] ): with patch.object( recommender, "_sort_by_relevance", return_value=[] ): recommender.generate_recommendations("user123") recommender._update_progress.assert_called() @patch.object( __import__( "local_deep_research.news.recommender.topic_based", fromlist=["TopicBasedRecommender"], ).TopicBasedRecommender, "_get_trending_topics", ) def test_handles_exception(self, mock_topics): """Test handles exception gracefully.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) mock_topics.side_effect = Exception("Error getting topics") recommender = TopicBasedRecommender() result = recommender.generate_recommendations("user123") assert result == [] class TestGetTrendingTopics: """Tests for _get_trending_topics method.""" def test_returns_list(self): """Test returns a list.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() result = recommender._get_trending_topics(None) assert isinstance(result, list) def test_returns_fallback_topics_when_empty(self): """Test returns fallback topics when no topics found.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() recommender.topic_registry = None # No registry result = recommender._get_trending_topics(None) assert len(result) > 0 # Should have fallback topics def test_uses_topic_registry_when_available(self): """Test uses topic registry when available.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) mock_registry = Mock() mock_registry.get_trending_topics.return_value = ["AI", "Climate"] recommender = TopicBasedRecommender() recommender.topic_registry = mock_registry result = recommender._get_trending_topics(None) assert "AI" in result assert "Climate" in result def test_adds_context_topics(self): """Test adds topics from context.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() context = {"current_news_topics": ["Blockchain"]} result = recommender._get_trending_topics(context) assert "Blockchain" in result class TestFilterTopicsByPreferences: """Tests for _filter_topics_by_preferences method.""" def test_returns_list(self): """Test returns a list.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() result = recommender._filter_topics_by_preferences(["AI", "Sports"], {}) assert isinstance(result, list) def test_filters_disliked_topics(self): """Test filters out disliked topics.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() preferences = {"disliked_topics": ["Sports"]} result = recommender._filter_topics_by_preferences( ["AI", "Sports", "Tech"], preferences ) assert "Sports" not in result def test_preserves_non_disliked_topics(self): """Test preserves non-disliked topics.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() preferences = {"disliked_topics": ["Sports"]} result = recommender._filter_topics_by_preferences( ["AI", "Sports", "Tech"], preferences ) assert "AI" in result assert "Tech" in result class TestGenerateTopicQuery: """Tests for _generate_topic_query method.""" def test_returns_string(self): """Test returns a string.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() result = recommender._generate_topic_query("artificial intelligence") assert isinstance(result, str) def test_includes_topic(self): """Test query includes the topic.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() result = recommender._generate_topic_query("blockchain") assert "blockchain" in result.lower() class TestCreateRecommendationCard: """Tests for _create_recommendation_card method.""" @patch("local_deep_research.news.recommender.topic_based.CardFactory") def test_returns_card_or_none(self, mock_factory): """Test returns card or None.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() result = recommender._create_recommendation_card( "AI", "AI news today", "user123" ) # May return None or card depending on implementation assert result is None or hasattr(result, "topic") class TestSortByRelevance: """Tests for _sort_by_relevance method.""" def test_returns_list(self): """Test returns a list.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() result = recommender._sort_by_relevance([], "user123") assert isinstance(result, list) def test_preserves_cards(self): """Test preserves all cards in output.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) # Mock cards with required attributes for sorting mock_cards = [ Mock(impact_score=5.0, category="tech", metadata={}), Mock(impact_score=8.0, category="news", metadata={}), Mock(impact_score=3.0, category="science", metadata={}), ] recommender = TopicBasedRecommender() result = recommender._sort_by_relevance(mock_cards, "user123") assert len(result) == len(mock_cards) class TestTopicBasedRecommenderWithContext: """Tests for recommendations with various contexts.""" def test_handles_empty_context(self): """Test handles empty context dict.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() with patch.object( recommender, "_get_trending_topics", return_value=["AI"] ) as mock_topics: with patch.object( recommender, "_get_user_preferences", return_value={} ): with patch.object( recommender, "_filter_topics_by_preferences", return_value=[], ): with patch.object( recommender, "_sort_by_relevance", return_value=[] ): recommender.generate_recommendations( "user123", context={} ) mock_topics.assert_called_once_with({}) def test_handles_none_context(self): """Test handles None context.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() with patch.object( recommender, "_get_trending_topics", return_value=["AI"] ) as mock_topics: with patch.object( recommender, "_get_user_preferences", return_value={} ): with patch.object( recommender, "_filter_topics_by_preferences", return_value=[], ): with patch.object( recommender, "_sort_by_relevance", return_value=[] ): recommender.generate_recommendations( "user123", context=None ) mock_topics.assert_called_once_with(None) class TestTopicBasedRecommenderEdgeCases: """Edge case tests for TopicBasedRecommender.""" def test_handles_no_topics(self): """Test handles case with no topics.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() with patch.object(recommender, "_get_trending_topics", return_value=[]): with patch.object( recommender, "_get_user_preferences", return_value={} ): with patch.object( recommender, "_filter_topics_by_preferences", return_value=[], ): with patch.object( recommender, "_sort_by_relevance", return_value=[] ): result = recommender.generate_recommendations("user123") assert result == [] def test_limits_recommendations(self): """Test limits recommendations to max_recommendations.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) recommender = TopicBasedRecommender() recommender.max_recommendations = 3 with patch.object( recommender, "_get_trending_topics", return_value=["A", "B", "C", "D", "E"], ): with patch.object( recommender, "_get_user_preferences", return_value={} ): with patch.object( recommender, "_filter_topics_by_preferences", return_value=["A", "B", "C", "D", "E"], ): with patch.object( recommender, "_create_recommendation_card", return_value=None, ): with patch.object( recommender, "_sort_by_relevance", return_value=[] ): recommender.generate_recommendations("user123") # Implementation should only process max_recommendations topics class TestTopicBasedRecommenderImports: """Tests for module imports.""" def test_is_class(self): """Test TopicBasedRecommender is a class.""" from local_deep_research.news.recommender.topic_based import ( TopicBasedRecommender, ) assert isinstance(TopicBasedRecommender, type)