""" Unit tests for the IoT layer: IntentParser, SensorBridge (mock), VoiceResponder. """ from __future__ import annotations import asyncio import pytest class TestIntentParser: def setup_method(self): from src.iot.intent_parser import IntentParser self.parser = IntentParser() def test_bambara_soil_intent(self): intent = self.parser.parse("bunding nɔgɔ foro", "bam") assert intent.action == "check_soil" assert intent.confidence > 0 def test_bambara_water_intent(self): intent = self.parser.parse("ji sanji foro", "bam") assert intent.action == "irrigation_status" def test_fula_soil_intent(self): intent = self.parser.parse("leydi ngesa ladde", "ful") assert intent.action == "check_soil" def test_fula_pest_intent(self): intent = self.parser.parse("biñ-biñ", "ful") assert intent.action == "pest_alert" def test_unknown_text_returns_some_intent(self): intent = self.parser.parse("hello world", "bam") # Should return something without crashing assert intent.action is not None assert intent.confidence == 0.0 def test_confidence_range(self): intent = self.parser.parse("bunding nɔgɔ", "bam") assert 0.0 <= intent.confidence <= 1.0 class TestSensorBridgeMock: def setup_method(self): from src.iot.sensor_bridge import SensorBridge self.bridge = SensorBridge(sensor_api_url=None) def test_mock_mode_enabled(self): assert self.bridge._mock_mode is True def test_get_soil_data_returns_sensor_data(self): from src.iot.sensor_bridge import SensorData data = asyncio.run(self.bridge.get_soil_data("field_001")) assert isinstance(data, SensorData) assert data.sensor_type == "soil" assert "moisture_pct" in data.values assert "ph" in data.values def test_get_weather_returns_sensor_data(self): from src.iot.sensor_bridge import SensorData data = asyncio.run(self.bridge.get_weather("zone_a")) assert isinstance(data, SensorData) assert "temperature_c" in data.values def test_fetch_dispatches_by_intent_action(self): from src.iot.intent_parser import Intent from src.iot.sensor_bridge import SensorData intent = Intent(action="check_soil", entity="soil", confidence=0.8) data = asyncio.run(self.bridge.fetch(intent)) assert isinstance(data, SensorData) assert data.sensor_type == "soil" class TestVoiceResponder: def setup_method(self): from src.iot.voice_responder import VoiceResponder self.responder = VoiceResponder(language="fr") def _make_intent(self, action): from src.iot.intent_parser import Intent return Intent(action=action, entity=action, confidence=1.0) def _make_sensor_data(self, sensor_type, values): from src.iot.sensor_bridge import SensorData from datetime import datetime return SensorData(sensor_type=sensor_type, values=values, timestamp=datetime.utcnow().isoformat()) def test_low_moisture_triggers_irrigation_warning(self): intent = self._make_intent("check_soil") data = self._make_sensor_data("soil", {"moisture_pct": 20.0, "ph": 6.5}) response = self.responder.generate_response(intent, data) assert "Irrigation" in response or "irrigation" in response def test_normal_soil_contains_moisture(self): intent = self._make_intent("check_soil") data = self._make_sensor_data("soil", {"moisture_pct": 45.0, "ph": 6.8}) response = self.responder.generate_response(intent, data) assert "45" in response def test_high_pest_level_triggers_warning(self): intent = self._make_intent("pest_alert") data = self._make_sensor_data("pest", {"alert_level": 3.0, "trap_count_24h": 45.0}) response = self.responder.generate_response(intent, data) assert "Traitement" in response or "traitement" in response def test_weather_response_contains_temperature(self): intent = self._make_intent("check_weather") data = self._make_sensor_data("weather", {"temperature_c": 36.0, "rain_probability_pct": 10.0}) response = self.responder.generate_response(intent, data) assert "36" in response def test_french_response_output(self): intent = self._make_intent("check_weather") data = self._make_sensor_data("weather", {"temperature_c": 30.0}) response = self.responder.generate_response(intent, data) # Response should be in French assert any(word in response for word in ["Température", "température", "Humidité", "Vent", "pluie"])