metamon/stateful
Run a sequence of Command(model, real) against an initial
(model, real) pair, asserting that every command’s
precondition holds against the model and that run against
the real returns Ok(Nil).
This is the minimum surface needed for model-based testing. It
intentionally does not generate command sequences: callers
construct the list themselves (or with metamon.forall_with over
a list-of-commands generator). Shrinking command sequences and
scheduler-based parallelism are out of scope for this minimum;
the explicit list-driven flow is enough to catch model/real
drift in straightforward state machines.
Types
Outcome of running a command sequence.
pub type Outcome(model) {
Passed(final_model: model, ran: Int, skipped: Int)
Failed(
index: Int,
command_name: String,
reason: String,
model_at_failure: model,
)
}
Constructors
-
Passed(final_model: model, ran: Int, skipped: Int)All commands whose preconditions held passed against the real world. The final model state is reported for inspection.
-
Failed( index: Int, command_name: String, reason: String, model_at_failure: model, )The i-th command (zero-indexed) failed: either its real-side
runreturnedErroror no command of the original list had a satisfied precondition (in which caseindex = -1).
Values
pub fn assert_passed(outcome: Outcome(model)) -> Nil
Convenience: assert that the outcome is Passed. On Failed,
panic with a structured message that mirrors the regular failure
report style.
pub fn names_of(
commands: List(command.Command(model, real)),
) -> List(String)
Names of all commands in the sequence, in order. Useful for the stateful test’s own failure messages.
pub fn run(
initial_model: model,
initial_real: real,
commands: List(command.Command(model, real)),
) -> Outcome(model)
Run commands left-to-right starting from initial_model and
initial_real. Commands whose preconditions fail are skipped
(counted but not run). The first real-side Error(_) halts the
sequence and is returned as Failed.