Skip to main content

zyn/test/
assert_diagnostic.rs

1/// Asserts that an [`Output`](crate::Output) contains a diagnostic at the given level
2/// whose `Display` output contains the expected substring.
3///
4/// Walks all nested diagnostics (via [`Diagnostic::walk()`](crate::mark::Diagnostic::walk))
5/// to find a match.
6///
7/// # Examples
8///
9/// ```ignore
10/// let output = zyn::Render::render(&my_element, &input);
11/// zyn::assert_diagnostic!(output, zyn::mark::Level::Error, "field not found");
12/// ```
13#[macro_export]
14macro_rules! assert_diagnostic {
15    ($output:expr, $level:expr, $msg:expr) => {{
16        let __output = &$output;
17        let __diag = __output.diagnostic();
18        let __level = $level;
19        let __msg = $msg;
20        let __check =
21            |d: &$crate::Diagnostic| d.level() == __level && d.to_string().contains(__msg);
22        let __found = __check(__diag) || __diag.walk().any(__check);
23        assert!(
24            __found,
25            "no {:?} diagnostic containing {:?}\n\ndiagnostics:\n{}",
26            __level, __msg, __diag,
27        );
28    }};
29}
30
31/// Asserts that an [`Output`](crate::Output) has an error-level diagnostic
32/// containing the given message.
33///
34/// Equivalent to `assert_diagnostic!(output, Level::Error, "msg")`.
35///
36/// # Examples
37///
38/// ```ignore
39/// zyn::assert_compile_error!(output, "missing field");
40/// ```
41#[macro_export]
42macro_rules! assert_compile_error {
43    ($output:expr, $msg:expr) => {
44        $crate::assert_diagnostic!($output, $crate::mark::Level::Error, $msg)
45    };
46}
47
48/// Asserts that an [`Output`](crate::Output) contains an error diagnostic
49/// with the given message.
50#[macro_export]
51macro_rules! assert_diagnostic_error {
52    ($output:expr, $msg:expr) => {
53        $crate::assert_diagnostic!($output, $crate::mark::Level::Error, $msg)
54    };
55}
56
57/// Asserts that an [`Output`](crate::Output) contains a warning diagnostic
58/// with the given message.
59#[macro_export]
60macro_rules! assert_diagnostic_warning {
61    ($output:expr, $msg:expr) => {
62        $crate::assert_diagnostic!($output, $crate::mark::Level::Warning, $msg)
63    };
64}
65
66/// Asserts that an [`Output`](crate::Output) contains a note diagnostic
67/// with the given message.
68#[macro_export]
69macro_rules! assert_diagnostic_note {
70    ($output:expr, $msg:expr) => {
71        $crate::assert_diagnostic!($output, $crate::mark::Level::Note, $msg)
72    };
73}
74
75/// Asserts that an [`Output`](crate::Output) contains a help diagnostic
76/// with the given message.
77#[macro_export]
78macro_rules! assert_diagnostic_help {
79    ($output:expr, $msg:expr) => {
80        $crate::assert_diagnostic!($output, $crate::mark::Level::Help, $msg)
81    };
82}
83
84#[cfg(test)]
85mod tests {
86    use crate::Output;
87    use crate::mark;
88
89    #[test]
90    fn error_diagnostic() {
91        let output = Output::new()
92            .diagnostic(mark::error("field not found"))
93            .build();
94        assert_diagnostic_error!(output, "field not found");
95        assert_compile_error!(output, "field not found");
96    }
97
98    #[test]
99    fn warning_diagnostic() {
100        let output = Output::new()
101            .diagnostic(mark::new().add(mark::warning("unused field")))
102            .build();
103        assert_diagnostic_warning!(output, "unused field");
104    }
105
106    #[test]
107    fn note_diagnostic() {
108        let output = Output::new()
109            .diagnostic(mark::new().add(mark::note("derived from Foo")))
110            .build();
111        assert_diagnostic_note!(output, "derived from Foo");
112    }
113
114    #[test]
115    fn help_diagnostic() {
116        let output = Output::new()
117            .diagnostic(mark::new().add(mark::help("add #[zyn(skip)]")))
118            .build();
119        assert_diagnostic_help!(output, "add #[zyn(skip)]");
120    }
121
122    #[test]
123    #[should_panic(expected = "no")]
124    fn missing_diagnostic() {
125        let output = Output::default();
126        assert_diagnostic_error!(output, "does not exist");
127    }
128
129    #[test]
130    fn nested_diagnostic() {
131        let output = Output::new()
132            .diagnostic(mark::new().add(mark::error("outer").add(mark::help("inner hint"))))
133            .build();
134        assert_diagnostic_help!(output, "inner hint");
135    }
136
137    #[test]
138    #[should_panic(expected = "no")]
139    fn empty_output_has_no_diagnostics() {
140        let output = Output::default();
141        assert_diagnostic_warning!(output, "anything");
142    }
143
144    #[test]
145    fn multiple_errors_same_level() {
146        let output = Output::new()
147            .diagnostic(
148                mark::new()
149                    .add(mark::error("first"))
150                    .add(mark::error("second"))
151                    .add(mark::error("third")),
152            )
153            .build();
154        assert_diagnostic_error!(output, "first");
155        assert_diagnostic_error!(output, "second");
156        assert_diagnostic_error!(output, "third");
157    }
158
159    #[test]
160    fn partial_message_match() {
161        let output = Output::new()
162            .diagnostic(mark::error("field `name` is required"))
163            .build();
164        assert_diagnostic_error!(output, "name");
165        assert_diagnostic_error!(output, "required");
166    }
167
168    #[test]
169    fn all_levels_in_one_output() {
170        let output = Output::new()
171            .diagnostic(
172                mark::new()
173                    .add(mark::error("err"))
174                    .add(mark::warning("warn"))
175                    .add(mark::note("note"))
176                    .add(mark::help("help")),
177            )
178            .build();
179        assert_diagnostic_error!(output, "err");
180        assert_diagnostic_warning!(output, "warn");
181        assert_diagnostic_note!(output, "note");
182        assert_diagnostic_help!(output, "help");
183    }
184
185    #[test]
186    #[should_panic(expected = "no")]
187    fn wrong_level_does_not_match() {
188        let output = Output::new()
189            .diagnostic(mark::warning("just a warning"))
190            .build();
191        assert_diagnostic_error!(output, "just a warning");
192    }
193}