State machine tests inspired by [ScalaCheck](https://github.com/typelevel/scalacheck/blob/main/doc/UserGuide.md#stateful-testing) and [quickcheck-state-machine](https://hackage.haskell.org/package/quickcheck-state-machine).
| 5 | /// State machine tests inspired by [ScalaCheck](https://github.com/typelevel/scalacheck/blob/main/doc/UserGuide.md#stateful-testing) |
| 6 | /// and [quickcheck-state-machine](https://hackage.haskell.org/package/quickcheck-state-machine). |
| 7 | pub trait StateMachine { |
| 8 | /// System Under Test. |
| 9 | type System; |
| 10 | /// The idealised reference state we are testing aginst. |
| 11 | type State: Clone; |
| 12 | /// The random commands we can apply on the state in each step. |
| 13 | type Command; |
| 14 | /// The return result from command application. |
| 15 | type Result; |
| 16 | |
| 17 | /// Generate a random initial state. |
| 18 | fn gen_state(&self, u: &mut Unstructured) -> arbitrary::Result<Self::State>; |
| 19 | |
| 20 | /// Create a new System Under Test reflecting the given initial state. |
| 21 | /// |
| 22 | /// The [System] should free all of its resources when it goes out of scope. |
| 23 | fn new_system(&self, state: &Self::State) -> Self::System; |
| 24 | |
| 25 | /// Generate a random command given the latest state. |
| 26 | fn gen_command( |
| 27 | &self, |
| 28 | u: &mut Unstructured, |
| 29 | state: &Self::State, |
| 30 | ) -> arbitrary::Result<Self::Command>; |
| 31 | |
| 32 | /// Apply a command on the System Under Test. |
| 33 | fn run_command(&self, system: &mut Self::System, cmd: &Self::Command) -> Self::Result; |
| 34 | |
| 35 | /// Use assertions to check that the result returned by the System Under Test |
| 36 | /// was correct, given the model pre-state. |
| 37 | fn check_result(&self, cmd: &Self::Command, pre_state: &Self::State, result: Self::Result); |
| 38 | |
| 39 | /// Apply a command on the model state. |
| 40 | /// |
| 41 | /// We could use `Cow` here if we wanted to preserve the history of state and |
| 42 | /// also avoid cloning when there's no change. |
| 43 | fn next_state(&self, cmd: &Self::Command, state: Self::State) -> Self::State; |
| 44 | |
| 45 | /// Use assertions to check that the state transition on the System Under Test |
| 46 | /// was correct, by comparing to the model post-state. |
| 47 | /// |
| 48 | /// This can be used to check invariants which should always be true. |
| 49 | /// |
| 50 | /// Returns a flag indicating whether we should continue testing this system. |
| 51 | fn check_system( |
| 52 | &self, |
| 53 | cmd: &Self::Command, |
| 54 | post_state: &Self::State, |
| 55 | post_system: &Self::System, |
| 56 | ) -> bool; |
| 57 | } |
| 58 | |
| 59 | /// Run a state machine test by generating `max_steps` commands. |
| 60 | /// |
nothing calls this directly
no outgoing calls
no test coverage detected