""" Tests for the emotional intelligence system. """ import pytest import torch import numpy as np from datetime import datetime, timedelta from lyra.emotions.system import ( EmotionalSystem, EmotionalState, EmotionMemory ) from lyra.emotions.expressions import EmotionalExpressionEngine from tests.conftest import assert_tensor_shape, assert_tensor_range class TestEmotionalState: """Tests for emotional state representation.""" def test_emotional_state_initialization(self): """Test emotional state initialization with default values.""" state = EmotionalState() # Check that all emotions are within valid range [0, 1] emotions = [ state.joy, state.sadness, state.anger, state.fear, state.surprise, state.disgust, state.trust, state.anticipation, state.love, state.guilt, state.shame, state.pride, state.jealousy, state.hope, state.despair, state.curiosity ] for emotion in emotions: assert 0.0 <= emotion <= 1.0 # Check meta-emotional states assert 0.0 <= state.emotional_intensity <= 1.0 assert 0.0 <= state.emotional_stability <= 1.0 assert 0.0 <= state.emotional_clarity <= 1.0 # Check timestamp is set assert state.timestamp is not None assert isinstance(state.timestamp, datetime) def test_emotional_state_to_tensor(self, sample_emotional_state, device): """Test conversion to tensor.""" tensor = sample_emotional_state.to_tensor(device) assert_tensor_shape(tensor, (19,), "emotional state tensor") assert_tensor_range(tensor, 0.0, 1.0, "emotional values") def test_emotional_state_from_tensor(self, device): """Test creation from tensor.""" tensor = torch.rand(19, device=device) state = EmotionalState.from_tensor(tensor, trigger="test") assert state.trigger == "test" assert 0.0 <= state.joy <= 1.0 assert 0.0 <= state.emotional_intensity <= 1.0 def test_dominant_emotion_detection(self, sample_emotional_state): """Test dominant emotion detection.""" emotion, intensity = sample_emotional_state.get_dominant_emotion() assert isinstance(emotion, str) assert 0.0 <= intensity <= 1.0 assert emotion in [ 'joy', 'sadness', 'anger', 'fear', 'surprise', 'disgust', 'trust', 'anticipation', 'love', 'guilt', 'shame', 'pride', 'jealousy', 'hope', 'despair', 'curiosity' ] def test_emotional_valence_calculation(self): """Test emotional valence (positive/negative) calculation.""" # Very positive state positive_state = EmotionalState(joy=0.9, love=0.8, hope=0.9) valence = positive_state.get_emotional_valence() assert valence > 0.5 # Should be positive # Very negative state negative_state = EmotionalState(sadness=0.9, anger=0.8, despair=0.9) valence = negative_state.get_emotional_valence() assert valence < -0.5 # Should be negative def test_emotional_arousal_calculation(self): """Test emotional arousal (calm/excited) calculation.""" # High arousal state excited_state = EmotionalState(anger=0.9, surprise=0.8, joy=0.9) arousal = excited_state.get_emotional_arousal() assert arousal > 0.5 # Should be high arousal # Low arousal state calm_state = EmotionalState(trust=0.8, sadness=0.3) arousal = calm_state.get_emotional_arousal() assert arousal < 0.7 # Should be lower arousal class TestEmotionMemory: """Tests for emotional memory system.""" def test_emotion_memory_initialization(self, sample_emotional_state): """Test emotion memory initialization.""" memory = EmotionMemory( emotional_state=sample_emotional_state, context="test interaction", intensity=0.8, impact_score=0.7 ) assert memory.emotional_state == sample_emotional_state assert memory.context == "test interaction" assert memory.intensity == 0.8 assert memory.impact_score == 0.7 assert memory.decay_rate == 0.95 assert hasattr(memory, 'creation_time') def test_memory_impact_decay(self, sample_emotional_state): """Test memory impact decay over time.""" memory = EmotionMemory( emotional_state=sample_emotional_state, context="test", intensity=0.8, impact_score=1.0, decay_rate=0.9 ) # Simulate time passage by modifying creation_time memory.creation_time = datetime.now() - timedelta(hours=1) current_impact = memory.get_current_impact() assert current_impact < memory.impact_score # Should decay def test_memory_significance_check(self, sample_emotional_state): """Test memory significance determination.""" # High impact memory high_impact_memory = EmotionMemory( emotional_state=sample_emotional_state, context="important event", intensity=0.9, impact_score=0.8 ) assert high_impact_memory.is_significant(threshold=0.5) # Low impact memory after decay low_impact_memory = EmotionMemory( emotional_state=sample_emotional_state, context="minor event", intensity=0.3, impact_score=0.1 ) assert not low_impact_memory.is_significant(threshold=0.5) class TestEmotionalSystem: """Tests for the core emotional system.""" @pytest.mark.asyncio async def test_emotional_system_initialization(self, device): """Test emotional system initialization.""" system = EmotionalSystem( input_dim=128, emotion_dim=19, memory_capacity=100, device=device ) assert system.device == device assert system.emotion_dim == 19 assert system.memory_capacity == 100 assert isinstance(system.current_state, EmotionalState) assert len(system.emotion_memories) == 0 @pytest.mark.asyncio async def test_emotional_processing_forward_pass(self, emotional_system, sample_context_embedding): """Test emotional processing forward pass.""" new_state, emotion_info = emotional_system( context_embedding=sample_context_embedding ) assert isinstance(new_state, EmotionalState) assert isinstance(emotion_info, dict) # Check required keys in emotion_info required_keys = [ 'dominant_emotion', 'emotional_valence', 'emotional_arousal', 'memory_influence_strength', 'emotional_maturity' ] for key in required_keys: assert key in emotion_info @pytest.mark.asyncio async def test_emotional_memory_storage(self, emotional_system, sample_context_embedding): """Test storage of significant emotional experiences.""" # Create an emotionally significant state significant_state = EmotionalState( joy=0.9, emotional_intensity=0.9, trigger="amazing_news" ) emotional_system.current_state = significant_state # Process context to trigger memory storage new_state, info = emotional_system( context_embedding=sample_context_embedding, social_context={'trigger': 'positive_interaction'} ) # Check if memory was stored assert len(emotional_system.emotion_memories) > 0 @pytest.mark.asyncio async def test_emotional_learning_from_feedback(self, emotional_system, sample_context_embedding): """Test learning from user feedback.""" original_lr = float(emotional_system.emotional_learning_rate) # Positive feedback should increase learning rate positive_feedback = torch.tensor([[0.9]], device=emotional_system.device) new_state, info = emotional_system( context_embedding=sample_context_embedding, user_feedback=positive_feedback ) assert 'feedback_received' in info assert info['feedback_received'] > 0.7 # Learning rate should have been adjusted new_lr = float(emotional_system.emotional_learning_rate) assert new_lr != original_lr @pytest.mark.asyncio async def test_emotional_regulation(self, emotional_system, sample_context_embedding): """Test emotional regulation in different contexts.""" # Test with formal social context (should regulate emotions) formal_context = { 'formality_level': 0.9, 'group_size': 10, 'has_conflict': False } regulated_state, info = emotional_system( context_embedding=sample_context_embedding, social_context=formal_context, regulate_emotions=True ) assert info['regulation_applied'] is True # Test without regulation unregulated_state, info = emotional_system( context_embedding=sample_context_embedding, social_context=formal_context, regulate_emotions=False ) assert info['regulation_applied'] is False @pytest.mark.asyncio async def test_emotional_context_for_response(self, emotional_system): """Test generation of emotional context for responses.""" context = emotional_system.get_emotional_context_for_response() required_keys = [ 'dominant_emotion', 'emotion_intensity', 'emotional_valence', 'emotional_arousal', 'emotional_stability', 'emotional_maturity' ] for key in required_keys: assert key in context assert isinstance(context[key], (int, float, str)) def test_emotional_reaction_simulation(self, emotional_system): """Test simulation of emotional reactions to triggers.""" # Test different triggers triggers = ['praise', 'criticism', 'surprise', 'threat', 'love'] for trigger in triggers: reaction = emotional_system.simulate_emotional_reaction(trigger, intensity=0.8) assert isinstance(reaction, EmotionalState) assert reaction.trigger == trigger assert reaction.emotional_intensity == 0.8 @pytest.mark.asyncio async def test_emotional_summary(self, emotional_system): """Test emotional system summary generation.""" summary = emotional_system.get_emotional_summary() required_sections = [ 'current_state', 'emotional_growth', 'memory_system', 'emotional_patterns' ] for section in required_sections: assert section in summary # Check current state details current_state = summary['current_state'] assert 'dominant_emotion' in current_state assert 'valence' in current_state assert 'arousal' in current_state @pytest.mark.asyncio async def test_emotional_persistence(self, emotional_system, temp_directory): """Test saving and loading emotional state.""" save_path = temp_directory / "emotional_state_test.json" # Modify emotional state emotional_system.current_state.joy = 0.9 emotional_system.emotional_maturity = 0.8 emotional_system.emotional_experiences = 100 # Save state emotional_system.save_emotional_state(save_path) assert save_path.exists() # Create new system and load new_system = EmotionalSystem(device=emotional_system.device) new_system.load_emotional_state(save_path) assert abs(new_system.current_state.joy - 0.9) < 0.01 assert abs(new_system.emotional_maturity - 0.8) < 0.01 assert new_system.emotional_experiences == 100 class TestEmotionalExpressionEngine: """Tests for emotional expression in text.""" @pytest.mark.asyncio async def test_expression_engine_initialization(self, device): """Test expression engine initialization.""" engine = EmotionalExpressionEngine( vocab_size=1000, expression_dim=128, device=device ) assert engine.vocab_size == 1000 assert engine.expression_dim == 128 assert engine.device == device assert hasattr(engine, 'emotional_vocabularies') assert hasattr(engine, 'expression_patterns') @pytest.mark.asyncio async def test_emotional_expression_application(self, sample_emotional_state): """Test application of emotional expression to text.""" engine = EmotionalExpressionEngine(device=torch.device("cpu")) base_text = "I think this is a good idea." expressed_text, expression_info = engine( text=base_text, emotional_state=sample_emotional_state, intensity_multiplier=1.0 ) assert isinstance(expressed_text, str) assert isinstance(expression_info, dict) assert 'modifications' in expression_info assert 'dominant_emotion' in expression_info @pytest.mark.asyncio async def test_emotion_specific_expressions(self): """Test different emotions produce different expressions.""" engine = EmotionalExpressionEngine(device=torch.device("cpu")) base_text = "That's interesting." # Test joy expression joy_state = EmotionalState(joy=0.9, emotional_intensity=0.8) joy_text, joy_info = engine(base_text, joy_state) # Test sadness expression sad_state = EmotionalState(sadness=0.9, emotional_intensity=0.8) sad_text, sad_info = engine(base_text, sad_state) # Should produce different expressions assert joy_info['dominant_emotion'][0] != sad_info['dominant_emotion'][0] def test_expression_analysis(self): """Test analysis of emotional expression in text.""" engine = EmotionalExpressionEngine(device=torch.device("cpu")) # Test text with clear emotional indicators emotional_text = "I'm SO excited about this!!! This is amazing!" analysis = engine.analyze_emotional_expression(emotional_text) assert 'detected_emotions' in analysis assert 'expression_intensity' in analysis assert 'punctuation_analysis' in analysis # Should detect excitement/joy emotions = [e['emotion'] for e in analysis['detected_emotions']] assert any(emotion in ['joy', 'excitement'] for emotion in emotions) def test_expression_statistics(self): """Test expression statistics generation.""" engine = EmotionalExpressionEngine(device=torch.device("cpu")) stats = engine.get_expression_statistics() required_keys = [ 'current_typo_probability', 'excitement_threshold', 'available_emotions', 'expression_patterns' ] for key in required_keys: assert key in stats def test_contextual_expression_adjustments(self, sample_emotional_state): """Test contextual adjustments for different conversation contexts.""" engine = EmotionalExpressionEngine(device=torch.device("cpu")) base_text = "I understand your concern about this issue." # Test formal context formal_text, formal_info = engine( base_text, sample_emotional_state, context='formal' ) # Test casual context casual_text, casual_info = engine( base_text, sample_emotional_state, context='casual' ) # Should apply different modifications assert formal_info['modifications'] != casual_info['modifications'] def test_human_like_inconsistencies(self): """Test human-like inconsistencies in expression.""" engine = EmotionalExpressionEngine(device=torch.device("cpu")) # High arousal state should potentially add typos excited_state = EmotionalState( joy=0.9, surprise=0.8, emotional_intensity=0.9 ) base_text = "This is really great news!" # Test multiple times to check for variability results = [] for _ in range(10): expressed_text, info = engine( base_text, excited_state, intensity_multiplier=2.0 ) results.append(expressed_text) # Should show some variation in outputs unique_results = set(results) assert len(unique_results) > 1 # Should have some variation