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
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::mpsc::Receiver;
use std::sync::Mutex;
use crate::io;
use crate::io::dummy::DummyIO;
use crate::io::temperatures::{Sensor, TemperatureManager};
use async_trait::async_trait;

pub enum ModifyState {
    SetTemp(Sensor, f32),
    SetTemps(HashMap<Sensor, f32>)
}

pub struct Dummy {
    receiver: Mutex<Receiver<ModifyState>>,
    temps: Mutex<RefCell<HashMap<Sensor, f32>>>,
}

#[async_trait]
impl TemperatureManager for Dummy {

    async fn retrieve_sensors(&mut self) -> Result<(), String> {
        Ok(())
    }

    async fn retrieve_temperatures(&self) -> Result<HashMap<Sensor, f32>, String> {
        self.update_state();
        let guard = self.temps.lock()
            .unwrap();
        let map = (*guard).borrow().clone();
        Ok(map)
    }
}

impl DummyIO for Dummy {
    type MessageType = ModifyState;
    type Config = ();

    fn new(receiver: Receiver<Self::MessageType>, _config: &()) -> Self {
        Dummy {
            receiver: Mutex::new(receiver),
            temps: Mutex::new(RefCell::new(HashMap::new())),
        }
    }
}

impl Dummy {
    fn update_state(&self) {
        let guard = self.receiver.lock().unwrap();
        io::dummy::read_all(&*guard, |message| {
            match message {
                ModifyState::SetTemp(sensor, temp) => { (*self.temps.lock().unwrap()).borrow_mut().insert(sensor, temp); },
                ModifyState::SetTemps(temps) => {self.temps.lock().unwrap().replace(temps);},
            };
        })
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use crate::io::dummy::DummyIO;
    use crate::io::temperatures::dummy::{Dummy, ModifyState};
    use crate::io::temperatures::{Sensor, TemperatureManager};

    #[tokio::test]
    async fn starts_blank() {
        let (dummy, _sender) = Dummy::create(&());
        let temps = dummy.retrieve_temperatures().await
            .expect("Should retrieve temperatures");
        assert!(temps.is_empty(), "Expected no temperatures");
    }

    #[tokio::test]
    async fn set_single_temp() {
        let set_value = 37.2;
        let sensor = Sensor::TKRT;
        let (dummy, sender) = Dummy::create(&());
        sender.send(ModifyState::SetTemp(sensor.clone(), set_value))
            .expect("Should be able to send message");
        let temps = get_temps(&dummy).await;
        let mut expected = HashMap::new();
        expected.insert(sensor.clone(), set_value);
        assert_eq!(temps, expected, "Mismatch between set and received values.");
    }

    #[tokio::test]
    async fn set_multiple_temps() {
        let mut map = HashMap::new();
        map.insert(Sensor::TKEN, 39.3);
        map.insert(Sensor::HPFL, 23.3);
        map.insert(Sensor::TKBT, 18.1);
        map.insert(Sensor::HXIR, 14.5);
        let (dummy, sender) = Dummy::create(&());
        sender.send(ModifyState::SetTemps(map.clone()))
            .expect("Should be able to send message");
        let temps = get_temps(&dummy).await;
        assert_eq!(temps, map, "Expected ")
    }

    async fn get_temps(dummy: &Dummy) -> HashMap<Sensor, f32> {
        dummy.retrieve_temperatures().await
            .expect("Should retrieve temperatures")
    }
}