miden_assembly_syntax/testing/
mod.rs

1#[cfg(test)]
2mod context;
3mod pattern;
4
5#[cfg(test)]
6pub use self::context::SyntaxTestContext;
7pub use self::pattern::Pattern;
8
9/// Create a [Pattern::Regex] from the given input
10#[macro_export]
11macro_rules! regex {
12    ($source:literal) => {
13        $crate::testing::Pattern::regex($source)
14    };
15
16    ($source:expr) => {
17        $crate::testing::Pattern::regex($source)
18    };
19}
20
21/// Construct an [`::alloc::sync::Arc<miden_core::debuginfo::SourceFile>`] from a string literal or
22/// expression, such that emitted diagnostics reference the file and line on which the source file
23/// was constructed.
24#[macro_export]
25macro_rules! source_file {
26    ($context:expr, $source:literal) => {
27        $context.source_manager().load(
28            $crate::debuginfo::SourceLanguage::Masm,
29            concat!("test", line!()).into(),
30            $source.to_string(),
31        )
32    };
33    ($context:expr, $source:expr) => {
34        $context.source_manager().load(
35            $crate::debuginfo::SourceLanguage::Masm,
36            concat!("test", line!()).into(),
37            $source.to_string(),
38        )
39    };
40}
41
42/// Assert that the given diagnostic/error value, when rendered to stdout,
43/// contains the given pattern
44#[macro_export]
45macro_rules! assert_diagnostic {
46    ($diagnostic:expr, $expected:literal) => {{
47        let actual = format!(
48            "{}",
49            $crate::diagnostics::reporting::PrintDiagnostic::new_without_color($diagnostic)
50        );
51        $crate::testing::Pattern::from($expected).assert_match(actual);
52    }};
53
54    ($diagnostic:expr, $expected:expr) => {{
55        let actual = format!(
56            "{}",
57            $crate::diagnostics::reporting::PrintDiagnostic::new_without_color($diagnostic)
58        );
59        $crate::testing::Pattern::from($expected).assert_match(actual);
60    }};
61}
62
63/// Like [assert_diagnostic], but matches each non-empty line of the rendered output to a
64/// corresponding pattern.
65///
66/// So if the output has 3 lines, the second of which is empty, and you provide 2 patterns, the
67/// assertion passes if the first line matches the first pattern, and the third line matches the
68/// second pattern - the second line is ignored because it is empty.
69#[macro_export]
70macro_rules! assert_diagnostic_lines {
71    ($diagnostic:expr, $($expected_lines:expr),+) => {{
72        let full_output = format!("{}", $crate::diagnostics::reporting::PrintDiagnostic::new_without_color($diagnostic));
73        let lines: Vec<_> = full_output.lines().filter(|l| !l.trim().is_empty()).collect();
74        let patterns = [$($crate::testing::Pattern::from($expected_lines)),*];
75        if lines.len() != patterns.len() {
76            panic!(
77                "expected {} lines, but got {}:\n{}",
78                patterns.len(),
79                lines.len(),
80                full_output
81            );
82        }
83        let lines_and_patterns = lines.into_iter().zip(patterns.into_iter());
84        for (actual_line, expected_pattern) in lines_and_patterns {
85            expected_pattern.assert_match_with_context(actual_line, &full_output);
86        }
87    }};
88}
89
90#[macro_export]
91macro_rules! parse_module {
92    ($context:expr, $path:literal, $source:expr) => {{
93        let path = $crate::LibraryPath::new($path).expect("invalid library path");
94        let source_file = $context.source_manager().load(
95            $crate::debuginfo::SourceLanguage::Masm,
96            concat!("test", line!()).into(),
97            ::alloc::string::String::from($source),
98        );
99        $crate::ast::Module::parse(path, $crate::ast::ModuleKind::Library, source_file)
100            .expect("failed to parse module")
101    }};
102}