Skip to main content

miden_test_utils/
test_builders.rs

1// MACROS TO BUILD TESTS
2// ================================================================================================
3
4/// Creates a `Vec<u64>` for stack inputs where the first element will be on top of the stack.
5///
6/// This macro handles the reversal required by `StackInputs::try_from_ints`, which reverses
7/// its input internally. With this macro, you can specify stack inputs in intuitive order.
8///
9/// # Example
10///
11/// ```ignore
12/// // Stack will be [a, b, c, d, ...] with 'a' at position 0 (top)
13/// let inputs = stack![a, b, c, d];
14/// let test = build_op_test!("some_op", &inputs);
15/// ```
16///
17/// # Word Helper
18///
19/// To add a Word to the stack with `word[0]` on top, use the `word` helper:
20///
21/// ```ignore
22/// // Stack will be [w[0], w[1], w[2], w[3], ...] with w[0] on top
23/// let inputs = stack![word(my_word), other_value];
24/// ```
25#[macro_export]
26macro_rules! stack {
27    ($($elem:expr),* $(,)?) => {{
28        ::alloc::vec![$($elem as u64),*]
29    }};
30}
31
32/// Returns a Test struct in non debug mode from a string of one or more operations and any
33/// specified stack and advice inputs.
34///
35/// Parameters are expected in the following order:
36/// `source`, `stack_inputs` (optional), `advice_stack` (optional), `merkle_store` (optional)
37///
38/// * `source`: a string of one or more operations, e.g. "push.1 push.2".
39/// * `stack_inputs` (optional): the initial inputs which must be at the top of the stack before
40///   executing the `source`. Stack inputs can be provided independently without any advice inputs.
41/// * `advice_stack` (optional): the initial advice stack values. When provided, `stack_inputs` and
42///   `merkle_store` are also expected.
43/// * `merkle_store` (optional): the initial merkle set values. When provided, `stack_inputs` and
44///   `advice_stack` are also expected.
45#[macro_export]
46macro_rules! build_op_test {
47    ($op_str:expr) => {{
48        let source = format!("
49@locals(4)
50proc truncate_stack
51    loc_storew_be.0 dropw movupw.3
52    sdepth neq.16
53    while.true
54        dropw movupw.3
55        sdepth neq.16
56    end
57    loc_loadw_be.0
58end
59
60begin {} exec.truncate_stack end",
61            $op_str
62        );
63        $crate::build_test!(&source)
64    }};
65    ($op_str:expr, $($tail:tt)+) => {{
66        let source = format!("
67@locals(4)
68proc truncate_stack
69    loc_storew_be.0 dropw movupw.3
70    sdepth neq.16
71    while.true
72        dropw movupw.3
73        sdepth neq.16
74    end
75    loc_loadw_be.0
76end
77
78begin {} exec.truncate_stack end",
79            $op_str
80        );
81        $crate::build_test!(&source, $($tail)+)
82    }};
83}
84
85/// Returns a Test struct in non debug mode from the provided source string, and any specified
86/// stack and advice inputs.
87///
88/// Parameters are expected in the following order:
89/// `source`, `stack_inputs` (optional), `advice_stack` (optional), `merkle_store` (optional)
90///
91/// * `source`: a well-formed source string.
92/// * `stack_inputs` (optional): the initial inputs which must be at the top of the stack before
93///   executing the `source`. Stack inputs can be provided independently without any advice inputs.
94/// * `advice_stack` (optional): the initial advice stack values. When provided, `stack_inputs` and
95///   `merkle_store` are also expected.
96/// * `merkle_store` (optional): the initial merkle set values. When provided, `stack_inputs` and
97///   `advice_stack` are also expected.
98#[macro_export]
99macro_rules! build_test {
100    ($($params:tt)+) => {{
101        $crate::build_test_by_mode!(false, $($params)+)
102    }}
103}
104
105/// Returns a Test struct in debug mode from the provided source string and any specified stack
106/// and advice inputs.
107///
108/// Parameters are expected in the following order:
109/// `source`, `stack_inputs` (optional), `advice_stack` (optional), `merkle_store` (optional)
110///
111/// * `source`: a well-formed source string.
112/// * `stack_inputs` (optional): the initial inputs which must be at the top of the stack before
113///   executing the `source`. Stack inputs can be provided independently without any advice inputs.
114/// * `advice_stack` (optional): the initial advice stack values. When provided, `stack_inputs` and
115///   `merkle_store` are also expected.
116/// * `merkle_store` (optional): the initial merkle set values. When provided, `stack_inputs` and
117///   `advice_stack` are also expected.
118///
119/// NOTE: use `miden_core_lib::tests::build_debug_test` to include the core library in the test.
120#[macro_export]
121macro_rules! build_debug_test {
122    ($($params:tt)+) => {{
123        $crate::build_test_by_mode!(true, $($params)+)
124    }}
125}
126
127/// Returns a Test struct in the specified debug or non-debug mode using the provided source string
128/// and any specified stack and advice inputs.
129///
130/// Parameters start with a boolean flag, `in_debug_mode`, specifying whether the test is built in
131/// debug or non-debug mode. After that, they match the parameters of `build_test` and
132///`build_debug_test` macros.
133///
134/// This macro is an internal test builder, and is not intended to be called directly from tests.
135/// Instead, the build_test and build_debug_test wrappers should be used.
136#[macro_export]
137macro_rules! build_test_by_mode {
138    ($in_debug_mode:expr, $source:expr) => {{
139        let name = format!("test{}", line!());
140        $crate::Test::new(&name, $source, $in_debug_mode)
141    }};
142    ($in_debug_mode:expr, $source:expr, $stack_inputs:expr) => {{
143        use $crate::SourceManager;
144
145        let stack_inputs: ::alloc::vec::Vec<u64> = $stack_inputs.to_vec();
146        let stack_inputs = $crate::StackInputs::try_from_ints(stack_inputs).unwrap();
147        let advice_inputs = $crate::AdviceInputs::default();
148        let name = format!("test{}", line!());
149        let source_manager = ::alloc::sync::Arc::new($crate::DefaultSourceManager::default());
150        let source = source_manager.load(
151            $crate::SourceLanguage::Masm,
152            name.into(),
153            ::alloc::string::String::from($source),
154        );
155
156        $crate::Test {
157            source_manager,
158            source,
159            kernel_source: None,
160            stack_inputs,
161            advice_inputs,
162            in_debug_mode: $in_debug_mode,
163            libraries: ::alloc::vec::Vec::default(),
164            handlers: ::alloc::vec::Vec::new(),
165            add_modules: ::alloc::vec::Vec::default(),
166        }
167    }};
168    ($in_debug_mode:expr, $source:expr, $stack_inputs:expr, $advice_stack:expr) => {{
169        use $crate::SourceManager;
170
171        let stack_inputs: ::alloc::vec::Vec<u64> = $stack_inputs.to_vec();
172        let stack_inputs = $crate::StackInputs::try_from_ints(stack_inputs).unwrap();
173        let stack_values: ::alloc::vec::Vec<u64> = $advice_stack.to_vec();
174        let store = $crate::crypto::MerkleStore::new();
175        let advice_inputs = $crate::AdviceInputs::default()
176            .with_stack_values(stack_values)
177            .unwrap()
178            .with_merkle_store(store);
179        let name = format!("test{}", line!());
180        let source_manager = ::alloc::sync::Arc::new($crate::DefaultSourceManager::default());
181        let source = source_manager.load(
182            $crate::SourceLanguage::Masm,
183            name.into(),
184            ::alloc::string::String::from($source),
185        );
186
187        $crate::Test {
188            source_manager,
189            source,
190            kernel_source: None,
191            stack_inputs,
192            advice_inputs,
193            in_debug_mode: $in_debug_mode,
194            libraries: ::alloc::vec::Vec::default(),
195            handlers: ::alloc::vec::Vec::new(),
196            add_modules: ::alloc::vec::Vec::default(),
197        }
198    }};
199    (
200        $in_debug_mode:expr,
201        $source:expr,
202        $stack_inputs:expr,
203        $advice_stack:expr,
204        $advice_merkle_store:expr
205    ) => {{
206        use $crate::SourceManager;
207
208        let stack_inputs: Vec<u64> = $stack_inputs.to_vec();
209        let stack_inputs = $crate::StackInputs::try_from_ints(stack_inputs).unwrap();
210        let stack_values: Vec<u64> = $advice_stack.to_vec();
211        let advice_inputs = $crate::AdviceInputs::default()
212            .with_stack_values(stack_values)
213            .unwrap()
214            .with_merkle_store($advice_merkle_store);
215        let name = format!("test{}", line!());
216        let source_manager = ::alloc::sync::Arc::new($crate::DefaultSourceManager::default());
217        let source = source_manager.load(
218            $crate::SourceLanguage::Masm,
219            name.into(),
220            ::alloc::string::String::from($source),
221        );
222
223        $crate::Test {
224            source_manager,
225            source,
226            kernel_source: None,
227            stack_inputs,
228            advice_inputs,
229            in_debug_mode: $in_debug_mode,
230            libraries: ::alloc::vec::Vec::default(),
231            handlers: ::alloc::vec::Vec::new(),
232            add_modules: ::alloc::vec::Vec::default(),
233        }
234    }};
235    (
236        $in_debug_mode:expr,
237        $source:expr,
238        $stack_inputs:expr,
239        $advice_stack:expr,
240        $advice_merkle_store:expr,
241        $advice_map:expr
242    ) => {{
243        use $crate::SourceManager;
244
245        let stack_inputs: Vec<u64> = $stack_inputs.to_vec();
246        let stack_inputs = $crate::StackInputs::try_from_ints(stack_inputs).unwrap();
247        let stack_values: Vec<u64> = $advice_stack.to_vec();
248        let advice_inputs = $crate::AdviceInputs::default()
249            .with_stack_values(stack_values)
250            .unwrap()
251            .with_merkle_store($advice_merkle_store)
252            .with_map($advice_map);
253        let name = format!("test{}", line!());
254        let source_manager = ::alloc::sync::Arc::new($crate::DefaultSourceManager::default());
255        let source = source_manager.load(
256            $crate::SourceLanguage::Masm,
257            name.into(),
258            ::alloc::string::String::from($source),
259        );
260
261        $crate::Test {
262            source_manager,
263            source,
264            kernel_source: None,
265            stack_inputs,
266            advice_inputs,
267            in_debug_mode: $in_debug_mode,
268            libraries: ::alloc::vec::Vec::default(),
269            handlers: ::alloc::vec::Vec::new(),
270            add_modules: ::alloc::vec::Vec::default(),
271        }
272    }};
273}