File size: 4,752 Bytes
76db545
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""
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"])