""" Manual test script for energy calculator. This script runs basic tests to verify the energy calculator implementation. """ from datetime import datetime, timedelta from app.ml.energy_calculator import ( calculate_energy_score, apply_source_weights, adjust_weights_for_degraded_mode, apply_temporal_weighting, normalize_score, calculate_confidence ) def test_apply_source_weights(): """Test source weight application.""" print("\n=== Test: Apply Source Weights ===") # Test with all sources weighted_score = apply_source_weights( twitter_score=50.0, reddit_score=40.0, rss_score=30.0, available_sources=['twitter', 'reddit', 'rss'] ) expected = (50.0 * 0.60) + (40.0 * 0.25) + (30.0 * 0.15) assert weighted_score == expected, f"Expected {expected}, got {weighted_score}" print(f"✓ All sources: {weighted_score} (expected: {expected})") # Test with Twitter only weighted_score = apply_source_weights( twitter_score=50.0, reddit_score=0.0, rss_score=0.0, available_sources=['twitter'] ) assert weighted_score == 50.0, f"Expected 50.0, got {weighted_score}" print(f"✓ Twitter only: {weighted_score}") def test_adjust_weights_for_degraded_mode(): """Test degraded mode weight adjustment.""" print("\n=== Test: Adjust Weights for Degraded Mode ===") original_weights = { 'twitter': 0.60, 'reddit': 0.25, 'rss': 0.15 } # Test with Twitter and Reddit only adjusted = adjust_weights_for_degraded_mode( original_weights=original_weights, available_sources=['twitter', 'reddit'] ) total_weight = sum(adjusted.values()) assert abs(total_weight - 1.0) < 0.001, f"Total weight should be 1.0, got {total_weight}" print(f"✓ Twitter+Reddit weights: {adjusted} (total: {total_weight})") # Test with only Twitter adjusted = adjust_weights_for_degraded_mode( original_weights=original_weights, available_sources=['twitter'] ) total_weight = sum(adjusted.values()) assert adjusted['twitter'] == 1.0, f"Twitter weight should be 1.0, got {adjusted['twitter']}" print(f"✓ Twitter only: {adjusted}") def test_normalize_score(): """Test score normalization.""" print("\n=== Test: Normalize Score ===") # Test negative score normalized = normalize_score(-10.0) assert normalized == 0.0, f"Expected 0.0, got {normalized}" print(f"✓ Negative score: -10.0 → {normalized}") # Test score above 100 normalized = normalize_score(150.0) assert normalized == 100.0, f"Expected 100.0, got {normalized}" print(f"✓ Score above 100: 150.0 → {normalized}") # Test score in range normalized = normalize_score(50.0) assert normalized == 50.0, f"Expected 50.0, got {normalized}" print(f"✓ Score in range: 50.0 → {normalized}") def test_calculate_confidence(): """Test confidence calculation.""" print("\n=== Test: Calculate Confidence ===") # Test with all sources confidence = calculate_confidence( available_sources=['twitter', 'reddit', 'rss'], total_weight=1.0 ) assert confidence > 0.6, f"Confidence should be > 0.6, got {confidence}" print(f"✓ All sources: {confidence}") # Test with single source (Twitter) confidence = calculate_confidence( available_sources=['twitter'], total_weight=0.6 ) assert confidence == 0.6, f"Expected 0.6, got {confidence}" print(f"✓ Twitter only: {confidence}") # Test with no sources confidence = calculate_confidence( available_sources=[], total_weight=0.0 ) assert confidence == 0.0, f"Expected 0.0, got {confidence}" print(f"✓ No sources: {confidence}") def test_apply_temporal_weighting(): """Test temporal weighting.""" print("\n=== Test: Apply Temporal Weighting ===") base_score = 50.0 now = datetime.utcnow() # Test with recent tweets (within 1 hour) recent_tweets = [ { 'compound': 0.5, 'created_at': now - timedelta(minutes=30) }, { 'compound': 0.6, 'created_at': now - timedelta(minutes=15) } ] weighted_score = apply_temporal_weighting( base_score=base_score, tweets_with_timestamps=recent_tweets ) assert 0 <= weighted_score <= 100, f"Score should be between 0 and 100, got {weighted_score}" print(f"✓ Recent tweets: {base_score} → {weighted_score}") # Test with old tweets (24+ hours) old_tweets = [ { 'compound': 0.5, 'created_at': now - timedelta(hours=30) }, { 'compound': 0.6, 'created_at': now - timedelta(hours=25) } ] weighted_score = apply_temporal_weighting( base_score=base_score, tweets_with_timestamps=old_tweets ) assert 0 <= weighted_score <= 100, f"Score should be between 0 and 100, got {weighted_score}" print(f"✓ Old tweets: {base_score} → {weighted_score}") def test_calculate_energy_score_all_sources(): """Test energy score calculation with all sources.""" print("\n=== Test: Calculate Energy Score (All Sources) ===") twitter_sentiments = [ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'}, {'compound': 0.7, 'positive': 0.7, 'negative': 0.1, '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'} ] result = calculate_energy_score( match_id=1, team_id=1, twitter_sentiments=twitter_sentiments, reddit_sentiments=reddit_sentiments, rss_sentiments=rss_sentiments ) assert 'score' in result, "Result should contain 'score'" assert 'confidence' in result, "Result should contain 'confidence'" assert 'sources_used' in result, "Result should contain 'sources_used'" assert 0 <= result['score'] <= 100, f"Score should be between 0 and 100, got {result['score']}" assert len(result['sources_used']) == 3, f"Should use 3 sources, got {len(result['sources_used'])}" assert result['confidence'] > 0.6, f"Confidence should be > 0.6, got {result['confidence']}" print(f"✓ Score: {result['score']}") print(f"✓ Confidence: {result['confidence']}") print(f"✓ Sources used: {result['sources_used']}") def test_calculate_energy_score_degraded_mode(): """Test energy score calculation in degraded mode.""" print("\n=== Test: Calculate Energy Score (Degraded Mode) ===") twitter_sentiments = [ {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'} ] result = calculate_energy_score( match_id=1, team_id=1, twitter_sentiments=twitter_sentiments, reddit_sentiments=[], rss_sentiments=[] ) assert result['score'] >= 0, f"Score should be >= 0, got {result['score']}" assert result['confidence'] < 0.6, f"Confidence should be < 0.6 in degraded mode, got {result['confidence']}" assert len(result['sources_used']) == 1, f"Should use 1 source, got {len(result['sources_used'])}" assert 'twitter' in result['sources_used'], "Should use Twitter" print(f"✓ Score: {result['score']}") print(f"✓ Confidence: {result['confidence']} (lower in degraded mode)") print(f"✓ Sources used: {result['sources_used']}") def test_calculate_energy_score_no_data(): """Test energy score calculation with no data.""" print("\n=== Test: Calculate Energy Score (No Data) ===") result = calculate_energy_score( match_id=1, team_id=1, twitter_sentiments=[], reddit_sentiments=[], rss_sentiments=[] ) assert result['score'] == 0.0, f"Score should be 0.0, got {result['score']}" assert result['confidence'] == 0.0, f"Confidence should be 0.0, got {result['confidence']}" assert len(result['sources_used']) == 0, f"Should use 0 sources, got {len(result['sources_used'])}" print(f"✓ Score: {result['score']}") print(f"✓ Confidence: {result['confidence']}") print(f"✓ Sources used: {result['sources_used']}") def main(): """Run all manual tests.""" print("=" * 60) print("MANUAL TESTS FOR ENERGY CALCULATOR") print("=" * 60) try: test_apply_source_weights() test_adjust_weights_for_degraded_mode() test_normalize_score() test_calculate_confidence() test_apply_temporal_weighting() test_calculate_energy_score_all_sources() test_calculate_energy_score_degraded_mode() test_calculate_energy_score_no_data() print("\n" + "=" * 60) print("✅ ALL TESTS PASSED!") print("=" * 60) return 0 except AssertionError as e: print(f"\n❌ TEST FAILED: {e}") return 1 except Exception as e: print(f"\n❌ UNEXPECTED ERROR: {e}") import traceback traceback.print_exc() return 1 if __name__ == '__main__': exit(main())