| """ |
| RoboMind VLA — Comprehensive Test Suite. |
| |
| Tests: |
| - Unit tests for hybrid_judge module |
| - Unit tests for sound detection |
| - Integration test for end-to-end pipeline |
| - Regression tests for known predictions |
| |
| Run: |
| python -m pytest tests_comprehensive.py -v |
| """ |
| import json |
| import sys |
| import os |
|
|
| sys.path.insert(0, os.path.dirname(__file__)) |
|
|
|
|
| class TestHybridJudge: |
| """Test the hybrid judge module.""" |
|
|
| def test_vlm_to_reward_stable(self): |
| from robomind.hybrid import vlm_to_reward |
| parsed = {"stability": "stable", "gait_quality": 0.9, "predicted_reward": 0.95} |
| reward, confidence, details = vlm_to_reward(parsed) |
| assert 0.7 <= reward <= 1.0, f"Expected high reward for stable, got {reward}" |
| assert confidence > 0.5, f"Expected high confidence, got {confidence}" |
|
|
| def test_vlm_to_reward_falling(self): |
| from robomind.hybrid import vlm_to_reward |
| parsed = {"stability": "falling", "gait_quality": 0.0, "predicted_reward": 0.0, "anomaly": "fell through ground"} |
| reward, confidence, details = vlm_to_reward(parsed) |
| assert reward < 0.2, f"Expected low reward for falling, got {reward}" |
|
|
| def test_vlm_to_reward_text_values(self): |
| from robomind.hybrid import vlm_to_reward |
| parsed = {"stability": "stable", "gait_quality": "good", "predicted_reward": "high"} |
| reward, confidence, details = vlm_to_reward(parsed) |
| assert 0.5 <= reward <= 1.0, f"Expected reasonable reward, got {reward}" |
|
|
| def test_rule_based_expert(self): |
| from robomind.hybrid import rule_based_reward |
| reward, explanation = rule_based_reward(10000, 5000, 11000, False, 1000, "expert") |
| assert reward > 0.7, f"Expected high reward for expert, got {reward}" |
|
|
| def test_rule_based_simple(self): |
| from robomind.hybrid import rule_based_reward |
| reward, explanation = rule_based_reward(4000, 5000, 11000, False, 1000, "simple") |
| assert reward < 0.3, f"Expected low reward for simple, got {reward}" |
|
|
| def test_rule_based_fell(self): |
| from robomind.hybrid import rule_based_reward |
| reward, explanation = rule_based_reward(10000, 5000, 11000, True, 1000, "expert") |
| assert reward == 0.0, f"Expected zero reward for fall, got {reward}" |
|
|
| def test_blend_rewards(self): |
| from robomind.hybrid import blend_rewards |
| blended, rule_w = blend_rewards(0.9, 0.8, 0.5) |
| assert 0.5 < blended < 0.9, f"Expected blended between 0.5-0.9, got {blended}" |
|
|
| def test_hybrid_judge_expert(self): |
| from robomind.hybrid import hybrid_judge, hybrid_to_dict |
| parsed = {"stability": "stable", "gait_quality": 0.9, "predicted_reward": 0.95} |
| score = hybrid_judge(parsed, ep_return=10000, min_return=5000, max_return=11000, fell=False, tier="expert") |
| assert score.blended_reward > 0.7, f"Expected expert > 0.7, got {score.blended_reward}" |
| assert score.method == "hybrid" |
|
|
| def test_hybrid_judge_vlm_only(self): |
| from robomind.hybrid import hybrid_judge |
| parsed = {"stability": "stable", "gait_quality": 0.9, "predicted_reward": 0.95} |
| score = hybrid_judge(parsed) |
| assert score.method == "vlm_only" |
|
|
| def test_hybrid_to_dict(self): |
| from robomind.hybrid import hybrid_judge, hybrid_to_dict |
| parsed = {"stability": "stable", "gait_quality": 0.8, "predicted_reward": 0.9} |
| score = hybrid_judge(parsed) |
| d = hybrid_to_dict(score) |
| assert "predicted_reward" in d |
| assert "vlm_reward" in d |
| assert "rule_reward" in d |
| assert "method" in d |
|
|
|
|
| class TestSoundDetection: |
| """Test the sound detection module.""" |
|
|
| def test_audio_features_defaults(self): |
| from robomind.sound import AudioFeatures |
| f = AudioFeatures() |
| assert f.rms_energy == 0.0 |
| assert f.peak_amplitude == 0.0 |
|
|
| def test_sound_analysis_no_sound(self): |
| from robomind.sound import SoundAnalyzer, AudioFeatures |
| analyzer = SoundAnalyzer() |
| features = AudioFeatures(rms_energy=0.01, peak_amplitude=0.05, silence_ratio=0.9) |
| analysis = analyzer._analyze(features) |
| assert not analysis.has_fall |
| assert not analysis.has_impact |
|
|
| def test_sound_analysis_fall(self): |
| from robomind.sound import SoundAnalyzer, AudioFeatures |
| analyzer = SoundAnalyzer() |
| features = AudioFeatures(peak_amplitude=0.9, impact_severity=0.7, silence_ratio=0.5) |
| analysis = analyzer._analyze(features) |
| assert analysis.has_fall |
| assert analysis.fall_confidence > 0 |
|
|
| def test_sound_analysis_gait(self): |
| from robomind.sound import SoundAnalyzer, AudioFeatures |
| analyzer = SoundAnalyzer() |
| features = AudioFeatures(gait_regularity=0.8, tempo=120.0) |
| analysis = analyzer._analyze(features) |
| assert analysis.has_rhythmic_gait |
|
|
|
|
| class TestJudge: |
| """Test the VLM judge module.""" |
|
|
| def test_parse_response_json(self): |
| from robomind.judge import RoboMindJudge |
| response = '{"stability": "stable", "predicted_reward": 0.9}' |
| parsed = RoboMindJudge._parse_response(response) |
| assert parsed["stability"] == "stable" |
| assert parsed["predicted_reward"] == 0.9 |
|
|
| def test_parse_response_with_text(self): |
| from robomind.judge import RoboMindJudge |
| response = "Here is my analysis:\n```json\n{\"stability\": \"wobbling\", \"predicted_reward\": 0.5}\n```" |
| parsed = RoboMindJudge._parse_response(response) |
| assert "stability" in parsed |
|
|
|
|
| class TestIntegration: |
| """Integration tests.""" |
|
|
| def test_full_pipeline(self): |
| from robomind.hybrid import hybrid_judge, hybrid_to_dict |
| vlm_parsed = { |
| "stability": "stable", |
| "fall_risk": "low", |
| "gait_quality": 0.85, |
| "predicted_reward": 0.9, |
| "anomaly": None, |
| } |
| score = hybrid_judge( |
| vlm_parsed, ep_return=8000, min_return=4000, max_return=10000, |
| fell=False, num_steps=1000, tier="medium", env="walker2d", |
| ) |
| result = hybrid_to_dict(score) |
| assert result["method"] == "hybrid" |
| assert 0.0 <= result["predicted_reward"] <= 1.0 |
| assert 0.0 <= result["vlm_reward"] <= 1.0 |
| assert 0.0 <= result["rule_reward"] <= 1.0 |
|
|
| def test_tier_ordering(self): |
| from robomind.hybrid import hybrid_judge |
| rewards = {} |
| for tier, ep_ret in [("expert", 10000), ("medium", 7000), ("simple", 4500)]: |
| parsed = {"stability": "stable", "gait_quality": 0.8, "predicted_reward": 0.85} |
| score = hybrid_judge(parsed, ep_return=ep_ret, min_return=4000, max_return=11000, fell=False, tier=tier) |
| rewards[tier] = score.blended_reward |
| assert rewards["expert"] > rewards["medium"] > rewards["simple"], \ |
| f"Expected expert > medium > simple, got {rewards}" |
|
|
|
|
| if __name__ == "__main__": |
| import pytest |
| pytest.main([__file__, "-v"]) |
|
|