""" Tests for Sentiment Analyzer This module tests the VADER sentiment analyzer functionality. """ import pytest from app.ml.sentiment_analyzer import ( analyze_sentiment, analyze_sentiment_batch, calculate_aggregated_metrics, classify_sentiment, test_analyzer_performance ) class TestClassifySentiment: """Test sentiment classification based on compound score.""" def test_positive_classification(self): """Test classification of positive sentiment.""" assert classify_sentiment(0.5) == 'positive' assert classify_sentiment(0.05) == 'positive' assert classify_sentiment(1.0) == 'positive' def test_negative_classification(self): """Test classification of negative sentiment.""" assert classify_sentiment(-0.5) == 'negative' assert classify_sentiment(-0.05) == 'negative' assert classify_sentiment(-1.0) == 'negative' def test_neutral_classification(self): """Test classification of neutral sentiment.""" assert classify_sentiment(0.0) == 'neutral' assert classify_sentiment(0.04) == 'neutral' assert classify_sentiment(-0.04) == 'neutral' class TestAnalyzeSentiment: """Test single text sentiment analysis.""" def test_positive_text(self): """Test analysis of positive text.""" text = "I love this game! It's absolutely amazing and wonderful!" result = analyze_sentiment(text) assert result['sentiment'] == 'positive' assert result['compound'] > 0.05 assert 0 <= result['positive'] <= 1 assert 0 <= result['negative'] <= 1 assert 0 <= result['neutral'] <= 1 def test_negative_text(self): """Test analysis of negative text.""" text = "This is terrible! I hate it and it's the worst ever." result = analyze_sentiment(text) assert result['sentiment'] == 'negative' assert result['compound'] < -0.05 assert 0 <= result['positive'] <= 1 assert 0 <= result['negative'] <= 1 assert 0 <= result['neutral'] <= 1 def test_neutral_text(self): """Test analysis of neutral text.""" text = "The game is okay. Nothing special but nothing bad." result = analyze_sentiment(text) assert result['sentiment'] in ['positive', 'negative', 'neutral'] assert 0 <= result['compound'] <= 1 assert 0 <= result['positive'] <= 1 assert 0 <= result['negative'] <= 1 assert 0 <= result['neutral'] <= 1 def test_empty_text_raises_error(self): """Test that empty text raises ValueError.""" with pytest.raises(ValueError): analyze_sentiment("") def test_invalid_input_raises_error(self): """Test that invalid input raises ValueError.""" with pytest.raises(ValueError): analyze_sentiment(None) with pytest.raises(ValueError): analyze_sentiment(123) class TestAnalyzeSentimentBatch: """Test batch sentiment analysis.""" def test_batch_analysis_multiple_texts(self): """Test analysis of multiple texts.""" texts = [ "I love this!", "This is terrible!", "It's okay." ] results = analyze_sentiment_batch(texts) assert len(results) == 3 assert all('compound' in r for r in results) assert all('positive' in r for r in results) assert all('negative' in r for r in results) assert all('neutral' in r for r in results) assert all('sentiment' in r for r in results) def test_batch_analysis_empty_list(self): """Test batch analysis with empty list.""" results = analyze_sentiment_batch([]) assert results == [] def test_batch_analysis_with_errors(self): """Test batch analysis handles errors gracefully.""" texts = [ "This is good!", "", # Invalid - should be handled gracefully "This is great!" ] results = analyze_sentiment_batch(texts) assert len(results) == 3 # The invalid text should return neutral sentiment assert results[1]['sentiment'] == 'neutral' assert results[1]['compound'] == 0.0 class TestCalculateAggregatedMetrics: """Test calculation of aggregated sentiment metrics.""" def test_aggregated_metrics_empty_list(self): """Test aggregated metrics with empty list.""" metrics = calculate_aggregated_metrics([]) assert metrics['total_count'] == 0 assert metrics['positive_count'] == 0 assert metrics['negative_count'] == 0 assert metrics['neutral_count'] == 0 assert metrics['positive_ratio'] == 0.0 assert metrics['negative_ratio'] == 0.0 assert metrics['neutral_ratio'] == 0.0 assert metrics['average_compound'] == 0.0 def test_aggregated_metrics_all_positive(self): """Test aggregated metrics with all positive sentiments.""" sentiments = [ {'compound': 0.5, 'sentiment': 'positive'}, {'compound': 0.7, 'sentiment': 'positive'}, {'compound': 0.9, 'sentiment': 'positive'} ] metrics = calculate_aggregated_metrics(sentiments) assert metrics['total_count'] == 3 assert metrics['positive_count'] == 3 assert metrics['negative_count'] == 0 assert metrics['neutral_count'] == 0 assert metrics['positive_ratio'] == 1.0 assert metrics['average_compound'] == pytest.approx(0.7, rel=0.01) def test_aggregated_metrics_mixed(self): """Test aggregated metrics with mixed sentiments.""" sentiments = [ {'compound': 0.5, 'sentiment': 'positive'}, {'compound': -0.5, 'sentiment': 'negative'}, {'compound': 0.0, 'sentiment': 'neutral'}, {'compound': 0.7, 'sentiment': 'positive'} ] metrics = calculate_aggregated_metrics(sentiments) assert metrics['total_count'] == 4 assert metrics['positive_count'] == 2 assert metrics['negative_count'] == 1 assert metrics['neutral_count'] == 1 assert metrics['positive_ratio'] == 0.5 assert metrics['negative_ratio'] == 0.25 assert metrics['neutral_ratio'] == 0.25 assert metrics['average_compound'] == pytest.approx(0.175, rel=0.01) class TestAnalyzerPerformance: """Test performance of the sentiment analyzer.""" def test_performance_1000_tweets(self): """Test that 1000 tweets can be analyzed in less than 1 second.""" time_taken = test_analyzer_performance(1000) assert time_taken < 1.0, f"Analysis took {time_taken:.4f}s, expected < 1.0s" def test_performance_5000_tweets(self): """Test performance with 5000 tweets.""" time_taken = test_analyzer_performance(5000) # Should still be fast, but we allow some scaling assert time_taken < 5.0, f"Analysis took {time_taken:.4f}s, expected < 5.0s" def test_performance_10000_tweets(self): """Test performance with 10000 tweets.""" time_taken = test_analyzer_performance(10000) # Should still be very fast assert time_taken < 10.0, f"Analysis took {time_taken:.4f}s, expected < 10.0s"