Function modelator::run_tla_steps[][src]

pub fn run_tla_steps<P, System, Step>(
    tla_tests_file: P,
    tla_config_file: P,
    options: &Options,
    system: &mut System
) -> Result<(), TestError> where
    P: AsRef<Path>,
    System: StepRunner<Step> + Debug + Clone,
    Step: DeserializeOwned + Debug + Clone
Expand description

This is the most simple interface to run your system under test (SUT) against traces obtained from TLA+ tests. The function generates TLA+ traces using crate::traces and execute them against the SUT that implements StepRunner.

For more information, please consult the documentation of traces and StepRunner.

Example

use modelator::{run_tla_steps, StepRunner};
use serde::Deserialize;

// Suppose your system under test (SUT) consists of two integer variables,
// where each number can be increased independently;
// SUT also maintains the sum and product of the numbers.
use modelator::test_util::NumberSystem;

// We define a structure that is capable to serialize the states of a TLA+ trace.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct NumbersStep {
    a: u64,
    b: u64,
    action: Action,
    action_outcome: String
}

// We also define the abstract actions: do nothing / increase a / increase b.
#[derive(Debug, Clone, Deserialize)]
enum Action {
    None,
    IncreaseA,
    IncreaseB
}

// We implement `StepRunner` for our SUT
// This implementation needs to define only a couple of functions:
impl StepRunner<NumbersStep> for NumberSystem {
    // how to handle the initial step (initialize your system)
    fn initial_step(&mut self, step: NumbersStep) -> Result<(), String> {
        self.a = step.a;
        self.b = step.b;
        Ok(())
    }

    // how to handle all subsequent steps
    fn next_step(&mut self, step: NumbersStep) -> Result<(), String> {
        // Execute the action, and check the outcome
        let res = match step.action {
            Action::None => Ok(()),
            Action::IncreaseA => self.increase_a(1),
            Action::IncreaseB => self.increase_b(2),
        };
        let outcome = match res {
            Ok(()) => "OK".to_string(),
            Err(s) => s,
        };
        assert_eq!(outcome, step.action_outcome);

        // Check that the system state matches the state of the model
        assert_eq!(self.a, step.a);
        assert_eq!(self.b, step.b);

        Ok(())
    }
}

// To run your system against a TLA+ test, just point to the corresponding TLA+ files.
fn test() {
    let tla_tests_file = "tests/integration/tla/NumbersAMaxBMinTest.tla";
    let tla_config_file = "tests/integration/tla/Numbers.cfg";
    let options = modelator::Options::default();
    let mut system = NumberSystem::default();
    assert!(run_tla_steps(tla_tests_file, tla_config_file, &options, &mut system).is_ok());
}