|
1 | | -# tests/agent_core/core/ecs/test_component.py |
2 | | -""" |
3 | | -Unit tests for core ECS components in agent_core. |
4 | | -""" |
| 1 | +# tests/agent-core/core/ecs/test_components.py |
5 | 2 |
|
6 | | -import pytest |
7 | | -from agent_core.core.ecs.component import ValidationComponent |
| 3 | +from agent_core.core.ecs.component import ( |
| 4 | + ActionOutcomeComponent, |
| 5 | + ActionPlanComponent, |
| 6 | + AffectComponent, |
| 7 | + BeliefSystemComponent, |
| 8 | + CompetenceComponent, |
| 9 | + EmotionComponent, |
| 10 | + GoalComponent, |
| 11 | + TimeBudgetComponent, |
| 12 | +) |
8 | 13 |
|
9 | 14 |
|
10 | | -class TestValidationComponent: |
11 | | - """Tests for the ValidationComponent.""" |
| 15 | +class TestTimeBudgetComponent: |
| 16 | + """Tests for the TimeBudgetComponent.""" |
12 | 17 |
|
13 | | - def test_initialization(self): |
14 | | - """Tests that the component initializes with default values.""" |
15 | | - comp = ValidationComponent() |
16 | | - assert comp.reflection_confidence_scores == {} |
17 | | - assert comp.causal_model_confidence == 0.0 |
| 18 | + def test_validation_success(self): |
| 19 | + """Test that a valid component passes validation.""" |
| 20 | + comp = TimeBudgetComponent(initial_time_budget=100.0) |
| 21 | + is_valid, errors = comp.validate("agent_1") |
| 22 | + assert is_valid |
| 23 | + assert not errors |
18 | 24 |
|
19 | | - def test_to_dict(self): |
20 | | - """Tests the serialization of the component's state.""" |
21 | | - comp = ValidationComponent() |
22 | | - comp.reflection_confidence_scores = {10: 0.8} |
23 | | - comp.causal_model_confidence = 0.95 |
| 25 | + def test_validation_failure_negative_budget(self): |
| 26 | + """Test that a negative current budget fails validation.""" |
| 27 | + comp = TimeBudgetComponent(initial_time_budget=100.0) |
| 28 | + comp.current_time_budget = -10.0 |
| 29 | + is_valid, errors = comp.validate("agent_1") |
| 30 | + assert not is_valid |
| 31 | + assert "current_time_budget cannot be negative" in errors[0] |
| 32 | + |
| 33 | + def test_validation_failure_mismatched_active_state(self): |
| 34 | + """Test validation failure when is_active contradicts the budget.""" |
| 35 | + comp = TimeBudgetComponent(initial_time_budget=100.0) |
| 36 | + comp.current_time_budget = 0 |
| 37 | + comp.is_active = True # Should be inactive |
| 38 | + is_valid, errors = comp.validate("agent_1") |
| 39 | + assert not is_valid |
| 40 | + assert "Entity marked active but has no time budget" in errors[0] |
| 41 | + |
| 42 | + def test_auto_fix_negative_budget(self): |
| 43 | + """Test that auto_fix corrects a negative budget.""" |
| 44 | + comp = TimeBudgetComponent(initial_time_budget=100.0) |
| 45 | + comp.current_time_budget = -5.0 |
| 46 | + fixed = comp.auto_fix("agent_1", {}) |
| 47 | + assert fixed |
| 48 | + assert comp.current_time_budget == 0.0 |
| 49 | + assert not comp.is_active |
| 50 | + |
| 51 | + def test_to_dict_serialization(self): |
| 52 | + """Test that the component serializes to a dictionary correctly.""" |
| 53 | + comp = TimeBudgetComponent(initial_time_budget=150.0) |
| 54 | + comp.current_time_budget = 120.5 |
| 55 | + comp.is_active = True |
| 56 | + data = comp.to_dict() |
| 57 | + assert data["initial_time_budget"] == 150.0 |
| 58 | + assert data["current_time_budget"] == 120.5 |
| 59 | + assert data["is_active"] |
| 60 | + |
| 61 | + |
| 62 | +class TestEmotionComponent: |
| 63 | + """Tests for the EmotionComponent.""" |
| 64 | + |
| 65 | + def test_validation_out_of_bounds(self): |
| 66 | + """Test that valence and arousal outside their bounds fail validation.""" |
| 67 | + comp_valence = EmotionComponent(valence=1.5) |
| 68 | + is_valid, errors = comp_valence.validate("agent_1") |
| 69 | + assert not is_valid |
| 70 | + assert "Valence out of bounds" in errors[0] |
| 71 | + |
| 72 | + comp_arousal = EmotionComponent(arousal=-0.5) |
| 73 | + is_valid, errors = comp_arousal.validate("agent_1") |
| 74 | + assert not is_valid |
| 75 | + assert "Arousal out of bounds" in errors[0] |
| 76 | + |
| 77 | + def test_to_dict_serialization(self): |
| 78 | + """Test correct serialization.""" |
| 79 | + comp = EmotionComponent(valence=0.5, arousal=0.8, current_emotion_category="happy") |
24 | 80 | data = comp.to_dict() |
25 | | - assert data == { |
26 | | - "confidence_scores": {10: 0.8}, |
27 | | - "causal_model_confidence": 0.95, |
28 | | - } |
29 | | - |
30 | | - @pytest.mark.parametrize( |
31 | | - "scores, confidence, is_valid", |
32 | | - [ |
33 | | - ({}, 0.5, True), |
34 | | - ({1: 1.0}, 1.0, True), |
35 | | - (None, 0.5, False), # Invalid scores type |
36 | | - ({}, "high", False), # Invalid confidence type |
37 | | - ], |
38 | | - ) |
39 | | - def test_validation(self, scores, confidence, is_valid): |
40 | | - """Tests the validation logic for various states.""" |
41 | | - comp = ValidationComponent() |
42 | | - comp.reflection_confidence_scores = scores |
43 | | - comp.causal_model_confidence = confidence |
44 | | - valid, errors = comp.validate("agent_1") |
45 | | - assert valid is is_valid |
46 | | - if not is_valid: |
47 | | - assert len(errors) > 0 |
48 | | - |
49 | | - def test_auto_fix(self): |
50 | | - """ |
51 | | - Tests that the auto_fix method correctly resets an invalid state and |
52 | | - returns True, indicating a fix was made. |
53 | | - """ |
54 | | - comp = ValidationComponent() |
55 | | - # Set an invalid state that auto_fix is designed to correct |
56 | | - comp.reflection_confidence_scores = None |
57 | | - |
58 | | - # ACT: Run the auto_fix method |
59 | | - # The auto_fix for ValidationComponent doesn't do anything, so we expect False |
60 | | - was_fixed = comp.auto_fix("agent_1", {}) |
61 | | - |
62 | | - # ASSERT: The auto_fix method for this component doesn't fix this, so it should return False |
63 | | - assert was_fixed is False |
| 81 | + assert data["valence"] == 0.5 |
| 82 | + assert data["arousal"] == 0.8 |
| 83 | + assert data["current_emotion_category"] == "happy" |
| 84 | + |
| 85 | + |
| 86 | +class TestAffectComponent: |
| 87 | + """Tests for the AffectComponent.""" |
| 88 | + |
| 89 | + def test_validation_nan_dissonance(self): |
| 90 | + """Test that NaN cognitive dissonance fails validation.""" |
| 91 | + comp = AffectComponent(affective_buffer_maxlen=10) |
| 92 | + comp.cognitive_dissonance = float("nan") |
| 93 | + is_valid, errors = comp.validate("agent_1") |
| 94 | + assert not is_valid |
| 95 | + assert "Cognitive dissonance is not a finite number" in errors[0] |
| 96 | + |
| 97 | + |
| 98 | +class TestCompetenceComponent: |
| 99 | + """Tests for the CompetenceComponent.""" |
| 100 | + |
| 101 | + def test_auto_fix_incorrect_type(self): |
| 102 | + """Test that auto_fix corrects the type of action_counts.""" |
| 103 | + comp = CompetenceComponent() |
| 104 | + # Intentionally set to a wrong type |
| 105 | + comp.action_counts = {} |
| 106 | + fixed = comp.auto_fix("agent_1", {}) |
| 107 | + assert fixed |
| 108 | + from collections import defaultdict |
| 109 | + |
| 110 | + assert isinstance(comp.action_counts, defaultdict) |
| 111 | + |
| 112 | + |
| 113 | +class TestBeliefSystemComponent: |
| 114 | + """Tests for the BeliefSystemComponent.""" |
| 115 | + |
| 116 | + def test_validation_wrong_types(self): |
| 117 | + """Test that incorrect attribute types fail validation.""" |
| 118 | + comp = BeliefSystemComponent() |
| 119 | + comp.belief_base = [] # Should be a dict |
| 120 | + is_valid, errors = comp.validate("agent_1") |
| 121 | + assert not is_valid |
| 122 | + assert "'belief_base' attribute must be a dictionary" in errors[0] |
| 123 | + |
| 124 | + |
| 125 | +# You can continue adding simple test classes for other components |
| 126 | +# to quickly boost coverage. |
| 127 | + |
| 128 | + |
| 129 | +def test_goal_component_validation(): |
| 130 | + """Test GoalComponent validation logic.""" |
| 131 | + comp = GoalComponent(embedding_dim=10) |
| 132 | + comp.current_symbolic_goal = "explore" |
| 133 | + # Fails because 'explore' is not in the symbolic_goals_data |
| 134 | + is_valid, errors = comp.validate("agent_1") |
| 135 | + assert not is_valid |
| 136 | + assert "not in goal data" in errors[0] |
| 137 | + |
| 138 | + # Should pass now |
| 139 | + comp.symbolic_goals_data["explore"] = {} |
| 140 | + is_valid, errors = comp.validate("agent_1") |
| 141 | + assert is_valid |
| 142 | + |
| 143 | + |
| 144 | +def test_action_plan_and_outcome_components(): |
| 145 | + """Simple validation and serialization tests for action-related components.""" |
| 146 | + plan = ActionPlanComponent() |
| 147 | + is_valid, _ = plan.validate("agent_1") |
| 148 | + assert is_valid |
| 149 | + assert isinstance(plan.to_dict(), dict) |
| 150 | + |
| 151 | + outcome = ActionOutcomeComponent() |
| 152 | + is_valid, _ = outcome.validate("agent_1") |
| 153 | + assert is_valid |
| 154 | + assert isinstance(outcome.to_dict(), dict) |
0 commit comments