Skip to main content

expectation_harness/
driver.rs

1//! The system under test, as the runner sees it.
2
3use expectation_model::{Event, Value, Variable};
4
5/// Whether waiting could change anything.
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum Progress {
8    /// Time passed (a frame, a tick, a sleep); observe again.
9    Advanced,
10    /// Nothing will change by waiting; the observations so far are final.
11    Static,
12}
13
14pub struct Screenshot {
15    pub bytes: Vec<u8>,
16    /// File extension, e.g. "png" or "svg".
17    pub extension: &'static str,
18}
19
20impl Screenshot {
21    pub fn png(bytes: Vec<u8>) -> Self {
22        Screenshot { bytes, extension: "png" }
23    }
24
25    pub fn jpeg(bytes: Vec<u8>) -> Self {
26        Screenshot { bytes, extension: "jpg" }
27    }
28
29    pub fn svg(svg: String) -> Self {
30        Screenshot { bytes: svg.into_bytes(), extension: "svg" }
31    }
32}
33
34/// Something a plan needs the driver to do.
35#[derive(Clone, Copy, Debug)]
36pub enum Need<'a> {
37    Arrange(&'a Variable),
38    Set(&'a Variable),
39    Perform(&'a Event),
40    Observe(&'a Variable),
41}
42
43impl std::fmt::Display for Need<'_> {
44    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
45        match self {
46            Need::Arrange(v) => write!(f, "arrange {}", v.subject),
47            Need::Set(v) => write!(f, "set {}", v.subject),
48            Need::Perform(e) => write!(f, "make it happen that {}", e.text),
49            Need::Observe(v) => write!(f, "observe {}", v.subject),
50        }
51    }
52}
53
54/// Drives the system under test in the vocabulary's terms.
55///
56/// Calls may block. A real-time system (a game, a simulation) can let time pass in [`Driver::advance`]
57/// and the runner keeps observing until a step's checks hold or its patience runs out, so
58/// "Then the kettle is heating" means *eventually*, as it would for a person watching.
59pub trait Driver {
60    /// The external services this driver needs for its tests (see [`crate::service`]): a
61    /// controller, a database. The runner starts them before a plan, and when one cannot be had
62    /// here the plans are "not supported yet", with what to do about it.
63    fn needs(&self) -> Vec<String> {
64        vec![]
65    }
66
67    /// The services that must be started afresh before each test (a database the last
68    /// test wrote to): a subset of [`Driver::needs`].
69    fn fresh(&self) -> Vec<String> {
70        vec![]
71    }
72
73    /// Put the system in its starting state (what the Background describes), before each test.
74    fn reset(&mut self) -> Result<(), String> {
75        Ok(())
76    }
77
78    /// Make `var` hold `value` before the first step ("Given …").
79    fn arrange(&mut self, var: &Variable, value: &Value) -> Result<(), String> {
80        self.set(var, value)
81    }
82
83    /// Make `var` hold `value` as an action ("When the dial is 80 %").
84    fn set(&mut self, var: &Variable, value: &Value) -> Result<(), String>;
85
86    /// Make `event` happen ("When the user presses reset").
87    fn perform(&mut self, event: &Event) -> Result<(), String>;
88
89    /// What `var` is now. Enumerated values are matched to the vocabulary ignoring case.
90    fn observe(&mut self, var: &Variable) -> Result<Value, String>;
91
92    /// Can it put `var` in `value` to start a test? [`Driver::supports`] only knows the state; a
93    /// driver that can arrange some of its values and not others (a test account that can't
94    /// be emptied can't start with no messages) says so here, and the tests that need the rest
95    /// are "not supported yet" instead of failing.
96    fn can_arrange(&self, var: &Variable, value: &Value) -> bool {
97        let _ = (var, value);
98        true
99    }
100
101    /// Let the system settle after an action, before anything is observed: long enough for
102    /// what should happen to happen, and for what shouldn't to show. Without it, "Then the
103    /// kettle is off" could pass in the instant before it switches on.
104    fn settle(&mut self) {}
105
106    /// Let a little time pass before the runner observes again.
107    fn advance(&mut self) -> Progress {
108        Progress::Static
109    }
110
111    fn screenshot(&mut self) -> Result<Option<Screenshot>, String> {
112        Ok(None)
113    }
114
115    /// Can it do `need`? The runner checks every plan up front, so a missing binding fails
116    /// the test before it starts instead of halfway through.
117    fn supports(&self, need: Need<'_>) -> bool {
118        let _ = need;
119        true
120    }
121}