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
use crate::rule::Rule;
use std::sync::{Arc, Mutex};

pub struct When<I, O> {
    input: I,
    rules: Arc<Mutex<Vec<Rule<I, O>>>>,
}

impl<I, O> When<I, O> {
    pub(crate) fn new(input: I, rules: Arc<Mutex<Vec<Rule<I, O>>>>) -> Self {
        When { input, rules }
    }
}

impl<I: PartialEq, O> When<I, O> {
    /// Use the when return value when the mock is called with the specified
    /// input
    pub fn will_return(self, value: O) {
        let mut rules_locked = self.rules.lock().unwrap();
        let when_value = rules_locked
            .iter()
            .enumerate()
            .find(|(_i, value)| value.input == self.input);

        let rule = Rule::new(self.input, value);
        match when_value {
            Some((index, _value)) => {
                let _old_rule = std::mem::replace(&mut rules_locked[index], rule);
                ()
            }
            None => rules_locked.push(rule),
        }
    }
}

impl<I: PartialEq, O: Default> When<I, O> {
    /// Use `Default::default` when the mock is called with the specified input
    pub fn will_return_default(self) {
        self.will_return(O::default())
    }
}

#[cfg(test)]
mod tests {
    use super::When;
    use crate::rule::Rule;
    use std::sync::{Arc, Mutex};

    /// When `Given::will_return` is called with an output, the corresponding
    /// rule is added to the rules list
    #[test]
    fn add_rule_to_list() {
        let rules = Arc::new(Mutex::new(Vec::new()));
        let when = When::new("hello", rules.clone());

        when.will_return(true);

        let rules = rules.lock().unwrap();
        assert_eq!(*rules, vec![Rule::new("hello", true)]);
    }

    #[test]
    fn when_input_already_match_another_rule_replace_old_rule() {
        let rules = Arc::new(Mutex::new(Vec::new()));
        let when = When::new("sameinput", rules.clone());

        let assert_rule = |input, output| {
            let rules_locked = rules.lock().unwrap();
            let rule = rules_locked.get(0).unwrap();
            assert_eq!(rules_locked.len(), 1, "Rules should have only one rule.");
            assert_eq!(rule.input, input);
            assert_eq!(rule.output, output);
        };

        when.will_return("rule1");
        assert_rule("sameinput", "rule1");

        let when = When::new("sameinput", rules.clone());
        when.will_return("rule2");
        assert_rule("sameinput", "rule2");
    }

    /// When `Given::will_return_default` is called, a rule is made with the
    /// default of the output type
    #[test]
    fn add_default() {
        let rules = Arc::new(Mutex::new(Vec::new()));
        let when: When<&str, bool> = When::new("hello", rules.clone());

        when.will_return_default();

        let rules = rules.lock().unwrap();
        assert_eq!(*rules, vec![Rule::new("hello", false)]);
    }
}