""" Tests for Energy Service. This module tests the energy service business logic including: - Energy score calculation and storage - Retrieval of energy scores - Updating and deleting energy scores - Filtering and querying """ import pytest from datetime import datetime from app.services.energy_service import ( calculate_and_store_energy_score, get_energy_score, get_energy_scores_by_match, get_energy_scores_by_team, get_energy_score_by_match_and_team, update_energy_score, delete_energy_score, list_energy_scores ) from app.schemas.energy_score import EnergyScoreCalculationRequest, EnergyScoreUpdate class TestCalculateAndStoreEnergyScore: """Test energy score calculation and storage.""" def test_calculate_and_store_with_all_sources(self, db_session): """Test calculation and storage with all sources available.""" # Arrange request = EnergyScoreCalculationRequest( match_id=1, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ], reddit_sentiments=[ {'compound': 0.3, 'positive': 0.4, 'negative': 0.3, 'neutral': 0.3, 'sentiment': 'positive'} ], rss_sentiments=[ {'compound': 0.4, 'positive': 0.5, 'negative': 0.2, 'neutral': 0.3, 'sentiment': 'positive'} ] ) # Act energy_score = calculate_and_store_energy_score(db_session, request) # Assert assert energy_score is not None assert energy_score.match_id == 1 assert energy_score.team_id == 1 assert 0 <= energy_score.score <= 100 assert energy_score.confidence > 0 assert len(energy_score.sources_used) == 3 assert energy_score.twitter_score is not None assert energy_score.reddit_score is not None assert energy_score.rss_score is not None def test_calculate_and_store_with_twitter_only(self, db_session): """Test calculation and storage with only Twitter source.""" # Arrange request = EnergyScoreCalculationRequest( match_id=1, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) # Act energy_score = calculate_and_store_energy_score(db_session, request) # Assert assert energy_score is not None assert energy_score.match_id == 1 assert energy_score.team_id == 1 assert len(energy_score.sources_used) == 1 assert 'twitter' in energy_score.sources_used assert energy_score.twitter_score is not None assert energy_score.reddit_score is None assert energy_score.rss_score is None # Lower confidence in degraded mode assert energy_score.confidence < 0.7 def test_calculate_and_store_no_sentiment_data(self, db_session): """Test calculation with no sentiment data.""" # Arrange request = EnergyScoreCalculationRequest( match_id=1, team_id=1, twitter_sentiments=[], reddit_sentiments=[], rss_sentiments=[] ) # Act energy_score = calculate_and_store_energy_score(db_session, request) # Assert assert energy_score is not None assert energy_score.score == 0.0 assert energy_score.confidence == 0.0 assert len(energy_score.sources_used) == 0 class TestGetEnergyScore: """Test retrieval of energy scores.""" def test_get_energy_score_by_id(self, db_session): """Test retrieving energy score by ID.""" # Arrange request = EnergyScoreCalculationRequest( match_id=1, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) created = calculate_and_store_energy_score(db_session, request) # Act retrieved = get_energy_score(db_session, created.id) # Assert assert retrieved is not None assert retrieved.id == created.id assert retrieved.match_id == created.match_id assert retrieved.team_id == created.team_id assert retrieved.score == created.score def test_get_energy_score_not_found(self, db_session): """Test retrieving non-existent energy score.""" # Act retrieved = get_energy_score(db_session, 99999) # Assert assert retrieved is None class TestGetEnergyScoresByMatch: """Test retrieval of energy scores by match.""" def test_get_energy_scores_by_match_id(self, db_session): """Test retrieving all energy scores for a specific match.""" # Arrange # Create energy scores for different matches for match_id in [1, 1, 2]: request = EnergyScoreCalculationRequest( match_id=match_id, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) calculate_and_store_energy_score(db_session, request) # Act scores_for_match_1 = get_energy_scores_by_match(db_session, 1) scores_for_match_2 = get_energy_scores_by_match(db_session, 2) # Assert assert len(scores_for_match_1) == 2 assert all(score.match_id == 1 for score in scores_for_match_1) assert len(scores_for_match_2) == 1 assert scores_for_match_2[0].match_id == 2 class TestGetEnergyScoresByTeam: """Test retrieval of energy scores by team.""" def test_get_energy_scores_by_team_id(self, db_session): """Test retrieving all energy scores for a specific team.""" # Arrange # Create energy scores for different teams for team_id in [1, 1, 2]: request = EnergyScoreCalculationRequest( match_id=1, team_id=team_id, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) calculate_and_store_energy_score(db_session, request) # Act scores_for_team_1 = get_energy_scores_by_team(db_session, 1) scores_for_team_2 = get_energy_scores_by_team(db_session, 2) # Assert assert len(scores_for_team_1) == 2 assert all(score.team_id == 1 for score in scores_for_team_1) assert len(scores_for_team_2) == 1 assert scores_for_team_2[0].team_id == 2 class TestGetEnergyScoreByMatchAndTeam: """Test retrieval of most recent energy score by match and team.""" def test_get_energy_score_by_match_and_team(self, db_session): """Test retrieving most recent energy score for match and team.""" # Arrange request = EnergyScoreCalculationRequest( match_id=1, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) calculate_and_store_energy_score(db_session, request) # Act retrieved = get_energy_score_by_match_and_team(db_session, 1, 1) # Assert assert retrieved is not None assert retrieved.match_id == 1 assert retrieved.team_id == 1 def test_get_energy_score_by_match_and_team_not_found(self, db_session): """Test retrieving non-existent energy score.""" # Act retrieved = get_energy_score_by_match_and_team(db_session, 999, 999) # Assert assert retrieved is None class TestUpdateEnergyScore: """Test updating energy scores.""" def test_update_energy_score(self, db_session): """Test updating an existing energy score.""" # Arrange request = EnergyScoreCalculationRequest( match_id=1, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) created = calculate_and_store_energy_score(db_session, request) # Act update = EnergyScoreUpdate( score=75.0, confidence=0.9 ) updated = update_energy_score(db_session, created.id, update) # Assert assert updated is not None assert updated.id == created.id assert updated.score == 75.0 assert updated.confidence == 0.9 assert updated.updated_at > created.updated_at def test_update_energy_score_not_found(self, db_session): """Test updating non-existent energy score.""" # Arrange update = EnergyScoreUpdate(score=75.0, confidence=0.9) # Act updated = update_energy_score(db_session, 99999, update) # Assert assert updated is None class TestDeleteEnergyScore: """Test deleting energy scores.""" def test_delete_energy_score(self, db_session): """Test deleting an existing energy score.""" # Arrange request = EnergyScoreCalculationRequest( match_id=1, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) created = calculate_and_store_energy_score(db_session, request) # Act deleted = delete_energy_score(db_session, created.id) # Assert assert deleted is True retrieved = get_energy_score(db_session, created.id) assert retrieved is None def test_delete_energy_score_not_found(self, db_session): """Test deleting non-existent energy score.""" # Act deleted = delete_energy_score(db_session, 99999) # Assert assert deleted is False class TestListEnergyScores: """Test listing and filtering energy scores.""" def test_list_energy_scores_default(self, db_session): """Test listing energy scores with default parameters.""" # Arrange for i in range(5): request = EnergyScoreCalculationRequest( match_id=i, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) calculate_and_store_energy_score(db_session, request) # Act scores = list_energy_scores(db_session) # Assert assert len(scores) == 5 def test_list_energy_scores_with_match_filter(self, db_session): """Test listing energy scores filtered by match ID.""" # Arrange for match_id in [1, 1, 2]: request = EnergyScoreCalculationRequest( match_id=match_id, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) calculate_and_store_energy_score(db_session, request) # Act scores = list_energy_scores(db_session, match_id=1) # Assert assert len(scores) == 2 assert all(score.match_id == 1 for score in scores) def test_list_energy_scores_with_score_filter(self, db_session): """Test listing energy scores filtered by score range.""" # Arrange for score in [30.0, 50.0, 70.0, 90.0]: request = EnergyScoreCalculationRequest( match_id=1, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) created = calculate_and_store_energy_score(db_session, request) # Manually update score for testing created.score = score db_session.commit() # Act scores = list_energy_scores(db_session, min_score=40.0, max_score=80.0) # Assert assert len(scores) == 2 assert all(40.0 <= score.score <= 80.0 for score in scores) def test_list_energy_scores_with_pagination(self, db_session): """Test listing energy scores with pagination.""" # Arrange for i in range(10): request = EnergyScoreCalculationRequest( match_id=i, team_id=1, twitter_sentiments=[ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] ) calculate_and_store_energy_score(db_session, request) # Act page1 = list_energy_scores(db_session, limit=5, offset=0) page2 = list_energy_scores(db_session, limit=5, offset=5) # Assert assert len(page1) == 5 assert len(page2) == 5 # Verify no overlap page1_ids = [score.id for score in page1] page2_ids = [score.id for score in page2] assert set(page1_ids).isdisjoint(set(page2_ids)) if __name__ == '__main__': pytest.main([__file__, '-v'])