1#[macro_export]
28macro_rules! assert_parse {
29 ($atomset: path, $ty: ty, $str: literal, $expected: literal) => {
30 {
31 let source_text = $str;
32 let bump = ::bumpalo::Bump::default();
33 let lexer = css_lexer::Lexer::new(&$atomset, &source_text);
34 let mut parser = $crate::Parser::new(&bump, &source_text, lexer);
35 let result = parser.parse_entirely::<$ty>().with_trivia();
36 if !result.errors.is_empty() {
37 panic!("\n\nParse failed. ({:?}) saw error {:?}", source_text, result.errors[0]);
38 }
39 let mut actual = ::bumpalo::collections::String::new_in(&bump);
40 {
41 let mut write_sink = $crate::CursorWriteSink::new(&source_text, &mut actual);
42 let mut ordered_sink = $crate::CursorOrderedSink::new(&bump, &mut write_sink);
43 use $crate::ToCursors;
44 result.to_cursors(&mut ordered_sink);
45 }
46 if $expected.trim() != actual.trim() {
47 panic!("\n\nParse failed: did not match expected output:\n\n parser input: {:?}\n parser output: {:?}\n expected: {:?}\n", source_text, actual, $expected);
48 }
49 }
50 };
51 ($atomset: path, $ty: ty, $str: literal) => {
52 assert_parse!($atomset, $ty, $str, _);
53 };
54 ($atomset: path, $ty: ty, $str: literal, |$node: ident| $body: expr) => {
55 {
56 let source_text = $str;
57 let bump = ::bumpalo::Bump::default();
58 let lexer = css_lexer::Lexer::new(&$atomset, &source_text);
59 let mut parser = $crate::Parser::new(&bump, &source_text, lexer);
60 let result = parser.parse_entirely::<$ty>().with_trivia();
61 if !result.errors.is_empty() {
62 panic!("\n\nParse failed. ({:?}) saw error {:?}", source_text, result.errors[0]);
63 }
64 let mut actual = ::bumpalo::collections::String::new_in(&bump);
65 {
66 let mut write_sink = $crate::CursorWriteSink::new(&source_text, &mut actual);
67 let mut ordered_sink = $crate::CursorOrderedSink::new(&bump, &mut write_sink);
68 use $crate::ToCursors;
69 result.to_cursors(&mut ordered_sink);
70 }
71 if source_text.trim() != actual.trim() {
72 panic!("\n\nParse failed: did not match expected format:\n\n parser input: {:?}\n parser output: {:?}\n", source_text, actual);
73 }
74 let $node = result.output.expect("parse succeeded");
75 $body
76 }
77 };
78 ($atomset: path, $ty: ty, $str: literal, $($ast: pat)+) => {
79 {
80 let source_text = $str;
81 let bump = ::bumpalo::Bump::default();
82 let lexer = css_lexer::Lexer::new(&$atomset, &source_text);
83 let mut parser = $crate::Parser::new(&bump, &source_text, lexer);
84 if !parser.peek::<$ty>() {
85 panic!("\n\nParse failed because Type didn't peek!\n\n parser input: {:?}\n", source_text);
86 }
87 let result = parser.parse_entirely::<$ty>().with_trivia();
88 if !result.errors.is_empty() {
89 panic!("\n\nParse failed. ({:?}) saw error {:?}", source_text, result.errors[0]);
90 }
91 let mut actual = ::bumpalo::collections::String::new_in(&bump);
92 {
93 let mut write_sink = $crate::CursorWriteSink::new(&source_text, &mut actual);
94 let mut ordered_sink = $crate::CursorOrderedSink::new(&bump, &mut write_sink);
95 use $crate::ToCursors;
96 result.to_cursors(&mut ordered_sink);
97 }
98 if source_text.trim() != actual.trim() {
99 panic!("\n\nParse failed: did not match expected format:\n\n parser input: {:?}\n parser output: {:?}\n", source_text, actual);
100 }
101 #[allow(clippy::redundant_pattern_matching)] if !matches!(result.output, Some($($ast)|+)) {
103 panic!(
104 "\n\nParse succeeded but struct did not match given match pattern:\n\n input: {:?}\n match pattern: {}\n parsed struct: {:#?}\n",
105 source_text,
106 stringify!($($ast)|+),
107 result.output.unwrap(),
108 );
109 }
110 }
111 };
112}
113#[cfg(test)]
114pub(crate) use assert_parse;
115
116#[macro_export]
128macro_rules! assert_parse_error {
129 ($atomset: path, $ty: ty, $str: literal) => {
130 let source_text = $str;
131 let bump = ::bumpalo::Bump::default();
132 let lexer = css_lexer::Lexer::new(&$atomset, source_text);
133 let mut parser = $crate::Parser::new(&bump, source_text, lexer);
134 if !parser.peek::<$ty>() {
135 panic!("\n\n.\n\nPeek returned false, please don't use `assert_parse_error` - use `assert_peek_false` instead: {:?}", source_text);
136 }
137 let result = parser.parse::<$ty>();
138 if parser.at_end() {
139 if let Ok(result) = result {
140 let mut actual = ::bumpalo::collections::String::new_in(&bump);
141 {
142 let mut write_sink = $crate::CursorWriteSink::new(&source_text, &mut actual);
143 let mut ordered_sink = $crate::CursorOrderedSink::new(&bump, &mut write_sink);
144 use $crate::ToCursors;
145 result.to_cursors(&mut ordered_sink);
146 }
147 panic!("\n\nExpected errors but it passed without error.\n\n parser input: {:?}\n parser output: {:?}\n expected: (Error)", source_text, actual);
148 }
149 }
150 };
151}
152#[cfg(test)]
153pub(crate) use assert_parse_error;
154
155#[macro_export]
165macro_rules! assert_peek_false {
166 ($atomset: path, $ty: ty, $str: literal) => {
167 let source_text = $str;
168 let bump = ::bumpalo::Bump::default();
169 let lexer = css_lexer::Lexer::new(&$atomset, source_text);
170 let mut parser = $crate::Parser::new(&bump, source_text, lexer);
171 if parser.peek::<$ty>() {
172 panic!("\n\n.\n\nPeek returned true! You might want `assert_parse_error` instead: {:?}", source_text);
173 }
174 let result = parser.parse::<$ty>();
175 if parser.at_end() {
176 if let Ok(result) = result {
177 let mut actual = ::bumpalo::collections::String::new_in(&bump);
178 {
179 let mut write_sink = $crate::CursorWriteSink::new(&source_text, &mut actual);
180 let mut ordered_sink = $crate::CursorOrderedSink::new(&bump, &mut write_sink);
181 use $crate::ToCursors;
182 result.to_cursors(&mut ordered_sink);
183 }
184 panic!("\n\nExpected errors but it passed without error.\n\n parser input: {:?}\n parser output: {:?}\n expected: (Error)", source_text, actual);
185 }
186 }
187 };
188}
189#[cfg(test)]
190pub(crate) use assert_peek_false;
191
192#[macro_export]
206macro_rules! assert_parse_span {
207 ($atomset: path, $ty: ty, $str: literal) => {
208 let expected = $str;
209 let source_text = expected.lines().find(|line| !line.trim().is_empty()).unwrap_or("");
210 let bump = ::bumpalo::Bump::default();
211 let lexer = css_lexer::Lexer::new(&$atomset, source_text);
212 let mut parser = $crate::Parser::new(&bump, source_text, lexer);
213 let result = parser.parse::<$ty>();
214 match result {
215 Ok(result) => {
216 use $crate::ToSpan;
217 let span = result.to_span();
218 let indent = &source_text[0..span.start().into()];
219 if indent.trim().len() > 0 {
220 panic!(
221 "\n\nParse on {}:{} succeeded but has non-whitespace leading text: {}\n",
222 file!(),
223 line!(),
224 indent
225 );
226 }
227 let actual = format!("\n{}{}\n{}{}\n", indent, source_text, indent, "^".repeat(span.len() as usize));
228 if expected.trim() != actual.trim() {
229 panic!(
230 "\n\nParse on {}:{} succeeded but span ({}) differs:\n\n expected: {}\n actual: {}\n",
231 file!(),
232 line!(),
233 span,
234 expected,
235 actual,
236 );
237 }
238 }
239 Err(err) => {
240 panic!("\n\nParse on {}:{} failed. ({:?}) saw error {:?}", file!(), line!(), source_text, err);
241 }
242 }
243 };
244}
245#[cfg(test)]
246pub(crate) use assert_parse_span;