Skip to main content

expectation_harness/
bindings.rs

1//! A [`Driver`] made of closures over the system under test, one per vocabulary term:
2//!
3//! ```ignore
4//! let mut driver = Bindings::new(World::default())
5//!     .observe("the kettle", |w| w.phase.label())
6//!     .set("the dial", |w, v| w.dial = v.as_f64().unwrap())
7//!     .on("the user presses reset", |w| w.reset())
8//!     .on_settle(|w| w.tick(1.0))
9//!     .on_advance(|w| { w.tick(0.1); Progress::Advanced });
10//! ```
11
12use crate::driver::{Driver, Need, Progress, Screenshot};
13use expectation_model::text;
14use expectation_model::{Event, Value, Variable};
15use std::collections::HashMap;
16
17type Observer<W> = Box<dyn FnMut(&W) -> Value>;
18type Setter<W> = Box<dyn FnMut(&mut W, &Value)>;
19type Action<W> = Box<dyn FnMut(&mut W)>;
20type Advancer<W> = Box<dyn FnMut(&mut W) -> Progress>;
21type Shooter<W> = Box<dyn FnMut(&W) -> Screenshot>;
22
23pub struct Bindings<W> {
24    pub world: W,
25    observers: HashMap<String, Observer<W>>,
26    setters: HashMap<String, Setter<W>>,
27    arrangers: HashMap<String, Setter<W>>,
28    events: HashMap<String, Action<W>>,
29    reset: Option<Action<W>>,
30    settle: Option<Action<W>>,
31    advance: Option<Advancer<W>>,
32    screenshot: Option<Shooter<W>>,
33    needs: Vec<String>,
34    fresh: Vec<String>,
35}
36
37impl<W> Bindings<W> {
38    pub fn new(world: W) -> Self {
39        Bindings {
40            world,
41            observers: HashMap::new(),
42            setters: HashMap::new(),
43            arrangers: HashMap::new(),
44            events: HashMap::new(),
45            reset: None,
46            settle: None,
47            advance: None,
48            screenshot: None,
49            needs: vec![],
50            fresh: vec![],
51        }
52    }
53
54    /// The services to start afresh before each test (a subset of those it needs).
55    pub fn fresh(mut self, services: &[&str]) -> Self {
56        self.fresh = services.iter().map(|s| s.to_string()).collect();
57        self
58    }
59
60    /// The external services these bindings need (see [`crate::service`]).
61    pub fn needs(mut self, services: &[&str]) -> Self {
62        self.needs = services.iter().map(|s| s.to_string()).collect();
63        self
64    }
65
66    /// How to read a state. Subjects match the vocabulary ignoring case and a leading "the".
67    pub fn observe<V: Into<Value>>(mut self, subject: &str, mut f: impl FnMut(&W) -> V + 'static) -> Self {
68        self.observers.insert(text::key(subject), Box::new(move |w| f(w).into()));
69        self
70    }
71
72    /// How to change a state, as an action and (unless [`Bindings::arrange`] says otherwise)
73    /// when arranging the start.
74    pub fn set(mut self, subject: &str, f: impl FnMut(&mut W, &Value) + 'static) -> Self {
75        self.setters.insert(text::key(subject), Box::new(f));
76        self
77    }
78
79    /// How to put a state in place before the first step, when that differs from [`Bindings::set`].
80    pub fn arrange(mut self, subject: &str, f: impl FnMut(&mut W, &Value) + 'static) -> Self {
81        self.arrangers.insert(text::key(subject), Box::new(f));
82        self
83    }
84
85    pub fn on(mut self, event: &str, f: impl FnMut(&mut W) + 'static) -> Self {
86        self.events.insert(text::key(event), Box::new(f));
87        self
88    }
89
90    pub fn on_reset(mut self, f: impl FnMut(&mut W) + 'static) -> Self {
91        self.reset = Some(Box::new(f));
92        self
93    }
94
95    pub fn on_settle(mut self, f: impl FnMut(&mut W) + 'static) -> Self {
96        self.settle = Some(Box::new(f));
97        self
98    }
99
100    pub fn on_advance(mut self, f: impl FnMut(&mut W) -> Progress + 'static) -> Self {
101        self.advance = Some(Box::new(f));
102        self
103    }
104
105    pub fn on_screenshot(mut self, f: impl FnMut(&W) -> Screenshot + 'static) -> Self {
106        self.screenshot = Some(Box::new(f));
107        self
108    }
109}
110
111fn unbound(what: &str, name: &str) -> String {
112    format!("nothing is bound to {what} `{name}`")
113}
114
115impl<W> Driver for Bindings<W> {
116    fn needs(&self) -> Vec<String> {
117        self.needs.clone()
118    }
119
120    fn fresh(&self) -> Vec<String> {
121        self.fresh.clone()
122    }
123
124    fn reset(&mut self) -> Result<(), String> {
125        if let Some(f) = &mut self.reset {
126            f(&mut self.world);
127        }
128        Ok(())
129    }
130
131    fn arrange(&mut self, var: &Variable, value: &Value) -> Result<(), String> {
132        let f = self.arrangers.get_mut(&var.key).or_else(|| self.setters.get_mut(&var.key));
133        f.map(|f| f(&mut self.world, value)).ok_or_else(|| unbound("arrange", &var.subject))
134    }
135
136    fn set(&mut self, var: &Variable, value: &Value) -> Result<(), String> {
137        let f = self.setters.get_mut(&var.key);
138        f.map(|f| f(&mut self.world, value)).ok_or_else(|| unbound("set", &var.subject))
139    }
140
141    fn perform(&mut self, event: &Event) -> Result<(), String> {
142        let f = self.events.get_mut(&event.key);
143        f.map(|f| f(&mut self.world)).ok_or_else(|| unbound("the event", &event.text))
144    }
145
146    fn observe(&mut self, var: &Variable) -> Result<Value, String> {
147        let f = self.observers.get_mut(&var.key);
148        f.map(|f| f(&self.world)).ok_or_else(|| unbound("observe", &var.subject))
149    }
150
151    fn settle(&mut self) {
152        if let Some(f) = &mut self.settle {
153            f(&mut self.world);
154        }
155    }
156
157    fn advance(&mut self) -> Progress {
158        self.advance.as_mut().map_or(Progress::Static, |f| f(&mut self.world))
159    }
160
161    fn screenshot(&mut self) -> Result<Option<Screenshot>, String> {
162        Ok(self.screenshot.as_mut().map(|f| f(&self.world)))
163    }
164
165    fn supports(&self, need: Need<'_>) -> bool {
166        match need {
167            Need::Arrange(v) => self.arrangers.contains_key(&v.key) || self.setters.contains_key(&v.key),
168            Need::Set(v) => self.setters.contains_key(&v.key),
169            Need::Perform(e) => self.events.contains_key(&e.key),
170            Need::Observe(v) => self.observers.contains_key(&v.key),
171        }
172    }
173}