quint_connect/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod driver;
4mod logger;
5mod trace;
6mod value;
7
8// public for macro use
9#[doc(hidden)]
10pub mod runner;
11
12pub use driver::{Config, Driver, Path, Result, State, Step};
13
14/// Generates a test that runs multiple random traces by simulating a Quint specification.
15///
16/// This attribute macro transforms a function into a Rust test that generates traces using
17/// `quint run` in simulation mode. The function should return a [`Driver`] implementation
18/// that will be used to replay the generated traces.
19///
20/// # Attributes
21///
22/// - **`spec`** (required): Path to the Quint specification file
23/// - **`main`**: Name of the main module to run (defaults to Quint's default)
24/// - **`init`**: Name of the init action (defaults to Quint's default)
25/// - **`step`**: Name of the step action (defaults to Quint's default)
26/// - **`max_samples`**: Maximum number of traces to generate (defaults to 100)
27/// - **`max_steps`**: Maximum number of steps per trace (defaults to Quint's default)
28/// - **`seed`**: Random seed for reproducibility (defaults to random)
29///
30/// # Examples
31///
32/// Basic usage:
33///
34/// ```rust
35/// use quint_connect::*;
36/// # #[derive(Default)]
37/// # struct MyDriver;
38/// # impl Driver for MyDriver {
39/// #     type State = ();
40/// #     fn step(&mut self, _step: &Step) -> Result { Ok(()) }
41/// # }
42///
43/// #[quint_run(spec = "spec.qnt")]
44/// fn test_simulation() -> impl Driver {
45///     MyDriver::default()
46/// }
47/// ```
48///
49/// With custom configuration:
50///
51/// ```rust
52/// use quint_connect::*;
53/// # #[derive(Default)]
54/// # struct MyDriver;
55/// # impl Driver for MyDriver {
56/// #     type State = ();
57/// #     fn step(&mut self, _step: &Step) -> Result { Ok(()) }
58/// # }
59///
60/// #[quint_run(
61///     spec = "spec.qnt",
62///     main = "simulation",
63///     init = "myInit",
64///     max_samples = 50,
65///     max_steps = 100
66/// )]
67/// fn test_custom() -> impl Driver {
68///     MyDriver::default()
69/// }
70/// ```
71pub use quint_connect_macros::quint_run;
72
73/// Generates a test that runs traces from a specific Quint test.
74///
75/// This attribute macro transforms a function into a Rust test that generates traces using
76/// `quint test`. The function should return a [`Driver`] implementation that will be used
77/// to replay the generated traces.
78///
79/// # Attributes
80///
81/// - **`spec`** (required): Path to the Quint specification file
82/// - **`test`** (required): Name of the Quint test to run
83/// - **`main`**: Name of the main module containing the test (defaults to Quint's default)
84/// - **`max_samples`**: Maximum number of test runs (defaults to 100)
85/// - **`seed`**: Random seed for reproducibility (defaults to random)
86///
87/// # Examples
88///
89/// Basic usage:
90///
91/// ```rust
92/// use quint_connect::*;
93/// # #[derive(Default)]
94/// # struct MyDriver;
95/// # impl Driver for MyDriver {
96/// #     type State = ();
97/// #     fn step(&mut self, _step: &Step) -> Result { Ok(()) }
98/// # }
99///
100/// #[quint_test(spec = "spec.qnt", test = "myTest")]
101/// fn test_my_test() -> impl Driver {
102///     MyDriver::default()
103/// }
104/// ```
105///
106/// With custom configuration:
107///
108/// ```rust
109/// use quint_connect::*;
110/// # #[derive(Default)]
111/// # struct MyDriver;
112/// # impl Driver for MyDriver {
113/// #     type State = ();
114/// #     fn step(&mut self, _step: &Step) -> Result { Ok(()) }
115/// # }
116///
117/// #[quint_test(
118///     spec = "spec.qnt",
119///     test = "happyPathTest",
120///     main = "tests",
121///     max_samples = 10
122/// )]
123/// fn test_happy_path() -> impl Driver {
124///     MyDriver::default()
125/// }
126/// ```
127pub use quint_connect_macros::quint_test;
128
129/// Pattern-matches on action names and extracts nondeterministic picks from a [`Step`].
130///
131/// This macro simplifies the implementation of [`Driver::step`] by providing a convenient
132/// syntax for matching action names and extracting their parameters.
133///
134/// # Syntax
135///
136/// ```text
137/// switch!(step {
138///     action_name,                            // No parameters, calls self.action_name()
139///     action_name(param),                     // Required parameter
140///     action_name(param: Type),               // Required parameter with explicit type
141///     action_name(param?),                    // Optional parameter (Option<_>)
142///     action_name(param: Type?),              // Optional parameter with explicit type
143///     action_name(p1, p2: Type, p3?) => expr, // Custom handler expression
144///     _ => expr,                              // Catch-all for unmatched actions
145/// })
146/// ```
147///
148/// # Parameter Extraction
149///
150/// Parameters are extracted by name and deserialized using [`serde::Deserialize`]. The
151/// parameter name in the pattern must match the variable name in the Quint specification.
152///
153/// - **Required parameters** (e.g., `param` or `param: Type`): Will fail if the parameter
154///   is missing.
155/// - **Optional parameters** (e.g., `param?` or `param: Type?`): Produces an `Option<Type>`,
156///   with `None` if the parameter is missing.
157///
158/// # Handler Expressions
159///
160/// Each case can have a handler expression after `=>`:
161///
162/// - If no handler is provided, the macro generates a call to `self.action_name(params...)`.
163/// - With a handler, you can provide custom logic, including blocks of code.
164///
165/// # Catch-All Pattern
166///
167/// The `_` pattern matches any action name that doesn't match previous cases. It requires
168/// a handler expression. If no catch-all is provided, the macro generates an error for
169/// unmatched actions.
170///
171/// # Examples
172///
173/// Basic usage with implicit handlers:
174///
175/// ```rust
176/// use quint_connect::*;
177/// # struct MyDriver;
178/// # impl MyDriver {
179/// #     fn init(&mut self) {}
180/// #     fn increment(&mut self, amount: i64) {}
181/// # }
182///
183/// impl Driver for MyDriver {
184///     type State = ();
185///
186///     fn step(&mut self, step: &Step) -> Result {
187///         switch!(step {
188///             init,                    // Calls self.init()
189///             increment(amount),       // Calls self.increment(amount)
190///         })
191///     }
192/// }
193/// ```
194///
195/// Using optional parameters:
196///
197/// ```rust
198/// use quint_connect::*;
199/// # struct MyDriver;
200/// # impl MyDriver {
201/// #     fn set_value(&mut self, x: i64, y: Option<i64>) {}
202/// # }
203///
204/// impl Driver for MyDriver {
205///     type State = ();
206///
207///     fn step(&mut self, step: &Step) -> Result {
208///         switch!(step {
209///             setValue(x, y?) => self.set_value(x, y),
210///         })
211///     }
212/// }
213/// ```
214///
215/// Using custom handlers:
216///
217/// ```rust
218/// use quint_connect::*;
219/// # struct MyDriver { value: i64 }
220///
221/// impl Driver for MyDriver {
222///     type State = ();
223///
224///     fn step(&mut self, step: &Step) -> Result {
225///         switch!(step {
226///             init => {
227///                 self.value = 0;
228///             },
229///             add(amount: i64) => {
230///                 self.value += amount;
231///             },
232///             _ => {
233///                 // Handle unknown actions
234///             }
235///         })
236///     }
237/// }
238/// ```
239pub use quint_connect_macros::switch;