""" 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"])