Struct ModelatorRuntime

Source
pub struct ModelatorRuntime {
    pub model_checker_runtime: ModelCheckerRuntime,
    pub dir: PathBuf,
}
Expand description

Set of options to configure modelator runtime.

Fields§

§model_checker_runtime: ModelCheckerRuntime

Model checker runtime.

§dir: PathBuf

Modelator directory.

Implementations§

Source§

impl ModelatorRuntime

Source

pub fn model_checker_runtime( self, model_checker_runtime: ModelCheckerRuntime, ) -> Self

Set TLC runtime.

Source

pub fn dir(self, dir: impl AsRef<Path>) -> Self

Set modelator directory.

Source

pub fn traces<P: AsRef<Path>>( &self, tla_tests_file_path: P, tla_config_file_path: P, ) -> Result<BTreeMap<String, Result<Vec<JsonTrace>, Error>>, Error>

Given a crate::artifact::TlaFile with TLA+ test assertions, as well as a crate::artifact::TlaConfigFile with TLA+ configuration, generate all traces resulting from the test assertions.

The traces are generated by executing a model checker, which can be selected via ModelatorRuntime.

§Examples
let tla_tests_file_path = "tests/integration/resource/NumbersAMaxBMinTest.tla";
let tla_config_file_path = "tests/integration/resource/Numbers.cfg";
let runtime = modelator::ModelatorRuntime::default();
let trace_results = runtime.traces(tla_tests_file_path, tla_config_file_path).unwrap();
println!("{:?}", trace_results);
Source

pub fn run_tla_steps<P, System, Step>( &self, tla_tests_file_path: P, tla_config_file_path: P, system: &mut System, ) -> Result<TestReport, Error>
where P: AsRef<Path>, System: StepRunner<Step> + Debug + Clone, Step: DeserializeOwned + Debug + Clone,

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 ModelatorRuntime::traces and execute them against the SUT that implements StepRunner.

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

§Example
use modelator::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;
        self.recalculate();
        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_path = "tests/integration/resource/NumbersAMaxBMinTest.tla";
    let tla_config_file_path = "tests/integration/resource/Numbers.cfg";
    let runtime = modelator::ModelatorRuntime::default();
    let mut system = NumberSystem::default();
    assert!(runtime.run_tla_steps(tla_tests_file_path, tla_config_file_path, &mut system).is_ok());
}
Source

pub fn run_tla_events<P, System>( &self, tla_tests_file_path: P, tla_config_file_path: P, system: &mut System, runner: &mut EventRunner<System>, ) -> Result<TestReport, Error>
where P: AsRef<Path>, System: Debug + Default,

Run the system under test (SUT) using the abstract events obtained from TLA+ traces. Traces are generated using ModelatorRuntime::traces, To interpret abstract events an EventRunner needs to be created, as well as StateHandler and ActionHandler to be implemented for abstract states and actions you want to handle.

§Example
use modelator::{EventRunner, ActionHandler, StateHandler};
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;

// In order to drive your SUT, we could define two abstract states,
// that contain the state of the variables `a` and `b`.
#[derive(Debug, Clone, Deserialize, PartialEq)]
struct A {
    a: u64,
}
#[derive(Debug, Clone, Deserialize, PartialEq)]
struct B {
    b: u64,
}

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

// We define StateHandlers that are able to initialize your SUT from
// these abstract states, as well as to read them at any point in time.
impl StateHandler<A> for NumberSystem {
    fn init(&mut self, state: A) {
        self.a = state.a
    }
    fn read(&self) -> A {
        A { a: self.a }
    }
}
impl StateHandler<B> for NumberSystem {
    fn init(&mut self, state: B) {
        self.b = state.b
    }
    fn read(&self) -> B {
        B { b: self.b }
    }
}

// We define also an action handler that processes abstract actions
impl ActionHandler<Action> for NumberSystem {
    type Outcome = String;

    fn handle(&mut self, action: Action) -> Self::Outcome {
        let result_to_outcome = |res| match res {
            Ok(()) => "OK".to_string(),
            Err(s) => s
        };
        match action {
            Action::None => "OK".to_string(),
            Action::IncreaseA => result_to_outcome(self.increase_a(1)),
            Action::IncreaseB => result_to_outcome(self.increase_b(2))
        }
    }
}

// To run your system against a TLA+ test, just point to the corresponding TLA+ files.
fn main() {
    let tla_tests_file_path = "tests/integration/resource/NumbersAMaxBMaxTest.tla";
    let tla_config_file_path = "tests/integration/resource/Numbers.cfg";
    let runtime = modelator::ModelatorRuntime::default();
     
    // We create a system under test
    let mut system = NumberSystem::default();

    // We construct a runner, and tell which which states and actions it should process.
    let mut runner = EventRunner::new()
        .with_state::<A>()
        .with_state::<B>()
        .with_action::<Action>();

    // run your system against the events produced from TLA+ tests.
    let result = runtime.run_tla_events(tla_tests_file_path, tla_config_file_path, &mut system, &mut runner);
    // At each step of a test, the state of your system is being checked
    // against the state that the TLA+ model expects
    assert!(result.is_ok());
    // You can also check the final state of your system, if you want.
    assert_eq!(system.a, 6);
    assert_eq!(system.b, 6);
    assert_eq!(system.sum, 12);
    assert_eq!(system.prod, 36);
}

Trait Implementations§

Source§

impl Clone for ModelatorRuntime

Source§

fn clone(&self) -> ModelatorRuntime

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ModelatorRuntime

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ModelatorRuntime

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,