nom_test_helpers/
lib.rs

1//! Macros for testing `nom` parsers
2//!
3//! Often when I'm testing `nom` parsers, I end up defining a lot of little
4//! macros like this, so I thought I would bundle them all up into a crate
5//! so I didn't have to define them over and over.
6//!
7//! This crate was first created back when nom had the concept of "Done" vs "Finished",
8//! which might seem a little out of place now but I still find it useful when testing.
9//! Basically, macros that test for "Done" check that the parser completed
10//! successfully, while macros that test for "Finished" check that the parser
11//! completed successfully while also asserting that the input is empty.
12//!
13#![deny(missing_docs)] // <- this doesn't appear to check macros?
14
15/// Instead of importing the helper macros individually, this can be
16/// star-imported to get all of them
17pub mod prelude {
18    pub use crate::{
19        assert_done,
20        assert_finished,
21        assert_done_and_eq,
22        assert_finished_and_eq,
23        assert_error,
24        assert_error_and_eq,
25        assert_needed,
26        assert_needs,
27    };
28}
29
30#[macro_export]
31/// This macro checks to make sure that the IResult it is
32/// passed is `Done`. That is, it checks that the parser completed successfully
33/// but doesn't make any assumptions about the remaining input.
34///
35/// # Examples
36///
37/// ```
38/// use nom_test_helpers::assert_done;
39/// use nom::{named, tag};
40///
41/// # fn main() {
42/// named!(abcd<&str, &str>, tag!("abcd"));
43/// let r = abcd("abcd");
44/// assert_done!(r);
45/// # }
46/// ```
47macro_rules! assert_done {
48    ($e:expr $(,)?) => (
49        assert_done!($e, "parser did not complete");
50    );
51    ($e:expr, $($arg:tt)+) => ({
52            if let ::std::result::Result::Ok((_, _)) = $e {
53                assert!(true);
54            } else {
55                assert!(false, $($arg)+);
56            }
57    })
58}
59
60#[cfg(test)]
61mod assert_done_test {
62    use super::prelude::*;
63
64    #[test]
65    fn no_msg() {
66        let result: nom::IResult<&str, &str> = Ok(("foo", "bar"));
67        assert_done!(result);
68    }
69
70    #[test]
71    fn with_msg() {
72        let result: nom::IResult<&str, &str> = Ok(("foo", "bar"));
73        assert_done!(result, "should be done");
74    }
75
76    #[test]
77    #[should_panic]
78    fn panic_no_msg() {
79        let result: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
80        assert_done!(result,);
81    }
82
83    #[test]
84    #[should_panic]
85    fn panic_with_msg() {
86        let result: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
87        assert_done!(result, "should be done");
88    }
89}
90
91#[macro_export]
92/// This does the same thing as `assert_done!`, except that
93/// this also asserts that the input slice is empty
94///
95/// # Examples
96///
97/// ```
98/// use nom_test_helpers::assert_finished;
99///
100/// # fn main() {
101/// let r: nom::IResult<&str, &str> = Ok(("", "efgh"));
102/// assert_finished!(r);
103/// # }
104/// ```
105macro_rules! assert_finished {
106    ($e:expr $(,)?) => {
107        assert_finished!($e, "parser did not complete");
108    };
109    ($e:expr, $($arg:tt)+) => ({
110        if let ::std::result::Result::Ok((i, _)) = $e {
111            assert!(i.is_empty());
112        } else {
113            assert!(false, $($arg)+);
114        }
115    })
116}
117
118#[cfg(test)]
119mod assert_finished_tests {
120    use super::prelude::*;
121
122    #[test]
123    fn no_msg() {
124        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
125        assert_finished!(r);
126    }
127
128    #[test]
129    fn with_msg() {
130        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
131        assert_finished!(r, "should be finished");
132    }
133
134    #[test]
135    #[should_panic]
136    fn panic_ok_no_msg() {
137        let r: nom::IResult<&str, &str> = Ok((" ", "foo"));
138        assert_finished!(r);
139    }
140
141    #[test]
142    #[should_panic]
143    fn panic_ok_with_msg() {
144        let r: nom::IResult<&str, &str> = Ok((" ", "foo"));
145        assert_finished!(r, "should be finished");
146    }
147
148    #[test]
149    #[should_panic]
150    fn panic_err_no_msg() {
151        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
152        assert_finished!(r);
153    }
154
155    #[test]
156    #[should_panic]
157    fn panic_err_with_msg() {
158        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
159        assert_finished!(r, "should be finished");
160    }
161}
162
163#[macro_export]
164/// This checks that the `IResult` is `Done`, and lets you
165/// check that the value returned as the `O` type of the 
166/// `IResult` is equal to the second parameter
167///
168/// # Examples
169///
170/// ```
171/// use nom_test_helpers::assert_done_and_eq;
172///
173/// # fn main() {
174/// let r: nom::IResult<&[u8], &[u8]> = Ok((b"abcd", b"efgh"));
175/// assert_done_and_eq!(r, b"efgh");
176/// # }
177/// ```
178macro_rules! assert_done_and_eq {
179    ($e:expr, $a:expr $(,)?) => {
180        assert_done_and_eq!($e, $a, "parser did not complete");
181    };
182    ($e:expr, $a:expr, $($arg:tt)+) => ({
183        if let ::std::result::Result::Ok((_, o)) = $e {
184            assert_eq!(o, $a);
185        } else {
186            assert!(false, $($arg)+);
187        }
188    });
189}
190
191#[cfg(test)]
192mod assert_done_and_eq_tests {
193    use super::prelude::*;
194
195    #[test]
196    fn no_msg() {
197        let r: nom::IResult<&str, &str> = Ok((" ", "foo"));
198        assert_done_and_eq!(r, "foo");
199    }
200
201    #[test]
202    fn with_msg() {
203        let r: nom::IResult<&str, &str> = Ok((" ", "foo"));
204        assert_done_and_eq!(r, "foo", "should be done");
205    }
206
207    #[test]
208    #[should_panic]
209    fn panic_no_msg() {
210        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
211        assert_done_and_eq!(r, "foo");
212    }
213
214    #[test]
215    #[should_panic]
216    fn panic_with_msg() {
217        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
218        assert_done_and_eq!(r, "foo", "should be done");
219    }
220}
221
222#[macro_export]
223/// Same as `assert_done_and_eq!`, but asserts that
224/// the input slice is empty
225///
226/// # Examples
227///
228/// ```
229/// use nom_test_helpers::assert_finished_and_eq;
230///
231/// # fn main() {
232/// let r: nom::IResult<&str, &str> = Ok(("", "sup"));
233/// assert_finished_and_eq!(r, "sup");
234/// # }
235/// ```
236macro_rules! assert_finished_and_eq {
237    ($r:expr, $o:expr $(,)?) => {
238        assert_finished_and_eq!($r, $o, "parser did not complete");
239    };
240    ($r:expr, $o:expr, $($arg:tt)+) => ({
241        if let ::std::result::Result::Ok((i, o)) = $r {
242            assert!(i.is_empty());
243            assert_eq!(o, $o);
244        } else {
245            assert!(false, $($arg)+);
246        }
247    })
248}
249
250#[cfg(test)]
251mod assert_finished_and_eq_tests {
252    use super::prelude::*;
253
254    #[test]
255    fn no_msg() {
256        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
257        assert_finished_and_eq!(r, "foo");
258    }
259
260    #[test]
261    fn with_msg() {
262        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
263        assert_finished_and_eq!(r, "foo", "should be finished");
264    }
265
266    #[test]
267    #[should_panic]
268    fn panic_ok_no_msg() {
269        let r: nom::IResult<&str, &str> = Ok((" ", "foo"));
270        assert_finished_and_eq!(r, "foo");
271    }
272
273    #[test]
274    #[should_panic]
275    fn panic_ok_with_msg() {
276        let r: nom::IResult<&str, &str> = Ok((" ", "foo"));
277        assert_finished_and_eq!(r, "foo", "should be finished");
278    }
279
280    #[test]
281    #[should_panic]
282    fn panic_err_no_msg() {
283        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
284        assert_finished_and_eq!(r, "foo");
285    }
286
287    #[test]
288    #[should_panic]
289    fn panic_err_with_msg() {
290        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
291        assert_finished_and_eq!(r, "foo", "should be finished");
292    }
293}
294
295#[macro_export]
296/// This asserts that the `IResult` is an `Err`
297/// 
298/// # Examples
299/// 
300/// ```
301/// use nom_test_helpers::assert_error;
302///
303/// # fn main() {
304/// let r: nom::IResult<&[u8], &[u8]> = Err(nom::Err::Error(nom::error::Error::new(&b""[..], nom::error::ErrorKind::Count)));
305/// assert_error!(r);
306/// # }
307macro_rules! assert_error {
308    ($e:expr $(,)?) => {
309        assert_error!($e, "parser did not error");
310    };
311    ($e:expr, $($arg:tt)+) => ({
312        if let ::std::result::Result::Err(_) = $e {
313            assert!(true);
314        } else {
315            assert!(false, $($arg)+);
316        }
317    })
318}
319
320#[cfg(test)]
321mod assert_error_tests {
322    use super::prelude::*;
323
324    #[test]
325    fn no_msg() {
326        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
327        assert_error!(r);
328    }
329
330    #[test]
331    fn with_msg() {
332        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
333        assert_error!(r, "should be an error");
334    }
335
336    #[test]
337    #[should_panic]
338    fn panic_no_msg() {
339        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
340        assert_error!(r);
341    }
342
343    #[test]
344    #[should_panic]
345    fn panic_with_msg() {
346        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
347        assert_error!(r, "should be an error");
348    }
349}
350
351#[macro_export]
352/// This asserts that the `IResult` is an `Err` and that the error
353/// is what is expected
354///
355/// # Examples
356///
357/// ```
358/// use nom_test_helpers::assert_error_and_eq;
359///
360/// # fn main() {
361/// let r: nom::IResult<&[u8], &[u8]> = Err(nom::Err::Error(nom::error::Error::new(&b""[..], nom::error::ErrorKind::Count)));
362/// assert_error_and_eq!(r, nom::Err::Error(nom::error::Error::new(&b""[..], nom::error::ErrorKind::Count)));
363/// # }
364macro_rules! assert_error_and_eq {
365    ($r:expr, $err:expr $(,)?) => {
366        assert_error_and_eq!($r, $err, "parser did not error");
367    };
368    ($r:expr, $err:expr, $($arg:tt)+) => ({
369        if let ::std::result::Result::Err(err) = $r {
370            assert_eq!(err, $err);
371        } else {
372            assert!(false, $($arg)+);
373        }
374    })
375}
376
377#[cfg(test)]
378mod assert_error_and_eq_tests {
379    use super::prelude::*;
380
381    #[test]
382    fn no_msg() {
383        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
384        assert_error_and_eq!(r, nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
385    }
386
387    #[test]
388    fn with_msg() {
389        let r: nom::IResult<&str, &str> = Err(nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
390        assert_error_and_eq!(r, nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)), "should be an error");
391    }
392
393    #[test]
394    #[should_panic]
395    fn panic_no_msg() {
396        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
397        assert_error_and_eq!(r, nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)));
398    }
399
400    #[test]
401    #[should_panic]
402    fn panic_with_msg() {
403        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
404        assert_error_and_eq!(r, nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Count)), "should be an error");
405    }
406}
407
408#[macro_export]
409/// This asserts that the `IResult` is an `Incomplete`
410///
411/// # Examples
412///
413/// ```
414/// use std::num::NonZeroUsize;
415/// use nom_test_helpers::assert_needed;
416/// use nom::Needed;
417///
418/// # fn main() {
419/// let r: nom::IResult<&[u8], &[u8]> = Err(nom::Err::Incomplete(Needed::Size(NonZeroUsize::new(1).unwrap())));
420/// assert_needed!(r);
421/// # }
422/// ```
423macro_rules! assert_needed {
424    ($e:expr $(,)?) => {
425        assert_needed!($e, "parser is not incomplete");
426    };
427    ($e:expr, $($arg:tt)+) => ({
428        if let ::std::result::Result::Err(::nom::Err::Incomplete(..)) = $e {
429            assert!(true);
430        } else {
431            assert!(false, $($arg)+);
432        }
433    })
434}
435
436#[cfg(test)]
437mod assert_needed_tests {
438    use super::prelude::*;
439
440    #[test]
441    fn no_msg() {
442        let r: nom::IResult<&str, &str> = Err(nom::Err::Incomplete(nom::Needed::Unknown));
443        assert_needed!(r);
444    }
445
446    #[test]
447    fn with_msg() {
448        let r: nom::IResult<&str, &str> = Err(nom::Err::Incomplete(nom::Needed::Unknown));
449        assert_needed!(r, "should be Needed");
450    }
451
452    #[test]
453    #[should_panic]
454    fn panic_no_msg() {
455        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
456        assert_needed!(r);
457    }
458
459    #[test]
460    #[should_panic]
461    fn panic_with_msg() {
462        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
463        assert_needed!(r, "should be Needed");
464    }
465}
466
467#[macro_export]
468/// This lets the user specify how much input the parser should need
469///
470/// # Examples
471///
472/// ```
473/// use nom_test_helpers::assert_needs;
474/// use nom::Needed;
475///
476/// # fn main() {
477/// let r: nom::IResult<&[u8], &[u8]> = Err(nom::Err::Incomplete(Needed::Unknown));
478/// assert_needs!(r, ?);
479/// # }
480/// ```
481///
482/// ```
483/// use std::num::NonZeroUsize;
484/// use nom_test_helpers::assert_needs;
485/// use nom::Needed;
486///
487/// # fn main() {
488/// let r: nom::IResult<&[u8], &[u8]> = Err(nom::Err::Incomplete(Needed::Size(NonZeroUsize::new(2).unwrap())));
489/// assert_needs!(r, 2usize);
490/// # }
491/// ```
492macro_rules! assert_needs {
493    ($e:expr, ? $(,)? ) => {
494        if let ::std::result::Result::Err(::nom::Err::Incomplete(e)) = $e {
495            if let ::nom::Needed::Unknown = e {
496                assert!(true);
497            } else {
498                assert!(false, "parser is incomplete, but Needed is known");
499            }
500        } else {
501            assert!(false, "parser is not incomplete");
502        }
503    };
504    ($e:expr, ?, $($arg:tt)+) => {
505        if let ::std::result::Result::Err(::nom::Err::Incomplete(e)) = $e {
506            if let ::nom::Needed::Unknown = e {
507                assert!(true);
508            } else {
509                assert!(false, $($arg)+);
510            }
511        } else {
512            assert!(false, $($arg)+);
513        }
514    };
515
516    ($e:expr, $i:expr $(,)?) => {
517        if let ::std::result::Result::Err(::nom::Err::Incomplete(e)) = $e {
518            if let ::nom::Needed::Size(i) = e {
519                assert_eq!($i, i.into());
520            } else {
521                assert!(false, "parser is incomplete, but Needed is unknown");
522            }
523        } else {
524            assert!(false, "parser is not incomplete");
525        }
526    };
527    ($e:expr, $i:expr, $($arg:tt)+) => ({
528        if let ::std::result::Result::Err(::nom::Err::Incomplete(e)) = $e {
529            if let ::nom::Needed::Size(i) = e {
530                assert_eq!($i, i.into());
531            } else {
532                assert!(false, $($arg)+);
533            }
534        } else {
535            assert!(false, $($arg)+);
536        }
537    });
538}
539
540#[cfg(test)]
541mod assert_needs_tests {
542    use super::prelude::*;
543    use std::num::NonZeroUsize;
544
545    #[test]
546    fn no_msg_size() {
547        let r: nom::IResult<&str, &str> = Err(nom::Err::Incomplete(nom::Needed::Size(NonZeroUsize::new(2).unwrap())));
548        assert_needs!(r, 2usize);
549    }
550
551    #[test]
552    fn no_msg_unknown() {
553        let r: nom::IResult<&str, &str> = Err(nom::Err::Incomplete(nom::Needed::Unknown));
554        assert_needs!(r, ?);
555    }
556
557    #[test]
558    fn with_msg_size() {
559        let r: nom::IResult<&str, &str> = Err(nom::Err::Incomplete(nom::Needed::Size(NonZeroUsize::new(2).unwrap())));
560        assert_needs!(r, 2usize, "should be Needed(2)");
561    }
562
563    #[test]
564    fn with_msg_unknown() {
565        let r: nom::IResult<&str, &str> = Err(nom::Err::Incomplete(nom::Needed::Unknown));
566        assert_needs!(r, ?, "should be Needed(Unknown)");
567    }
568
569    #[test]
570    #[should_panic]
571    fn panic_no_msg_size() {
572        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
573        assert_needs!(r, 2usize);
574    }
575
576    #[test]
577    #[should_panic]
578    fn panic_no_msg_unknown() {
579        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
580        assert_needs!(r, ?);
581    }
582
583    #[test]
584    #[should_panic]
585    fn panic_with_msg_unknown() {
586        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
587        assert_needs!(r, ?, "Should be Needed(Unknown)");
588    }
589
590    #[test]
591    #[should_panic]
592    fn panic_with_msg_size() {
593        let r: nom::IResult<&str, &str> = Ok(("", "foo"));
594        assert_needs!(r, 2usize, "Should be Needed(2)");
595    }
596}