0

I'm trying to write tests for nom parsers that provide better messages when they fail.

I have a macro similar to assert_eq! called assert_parses_to! that I want to provide a user-friendly display string when the parser fails:

#[macro_export]
macro_rules! assert_parses_to {
    ($parser:ident, $input:expr, $expectation:expr) => {
        match (&$parser($input), &$expectation) {
            (Err(candidate_error), expectation_val) => {
                panic!(
                    "Failed to parse the candidate\n\
                    {}",
                    convert_error($input, *candidate_error)
                );
            }
            (Ok(candidate_val), expectation_val) => {
                if !(*candidate_val == *expectation_val) {
                    panic!(
                        "Failed to parse to expected value\n\
                        Got:      {:?}\n\
                        Expected: {:?}",
                        candidate_val, expectation_val
                    )
                }
            }
        }
    };
}

However, when trying to compile, I get this error:

error[E0308]: mismatched types
   --> src/parser/tests.rs:27:43
    |
27  |                       convert_error($input, *candidate_error)
    |                       -------------         ^^^^^^^^^^^^^^^^ expected struct `VerboseError`, found enum `nom::Err`
    |                       |
    |                       arguments to this function are incorrect
    |
   ::: src/parser/ansi_2016/lexical.rs:237:9
    |
237 | /         assert_parses_to!(
238 | |             regular_identifier,
239 | |             "identifier ",
240 | |             (
...   |
246 | |             )
247 | |         )
    | |_________- in this macro invocation
    |
    = note: expected struct `VerboseError<&str>`
                 found enum `nom::Err<VerboseError<&str>>`

I'm assuming that I need to modify the match statement to extract the VerboseError from the error, but I haven't figured out how.

I'm new to rust and nom - any help appreciated!

Jay
  • 2,861
  • 3
  • 29
  • 51

1 Answers1

0

Resolved by matching on the inner value of the Err enum:

#[macro_export]
macro_rules! assert_parses_to {
    ($parser:ident, $input:expr, $expectation:expr) => {
        match ($parser($input), $expectation) {

            // Deeper match here
            (Err(::nom::Err::Error(e) | ::nom::Err::Failure(e)), _) => {
                panic!("{}", ::nom::error::convert_error($input, e));
            }

            (Err(e), _) => {
                panic!("Failed to parse {:?}", e)
            }
            (Ok(candidate_val), expected_val) => {
                if !(candidate_val == expected_val) {
                    panic!(
                        "Failed to parse to expected value\n\
                        Got:      {:?}\n\
                        Expected: {:?}",
                        candidate_val, expected_val
                    )
                }
            }
        }
    };
}
Jay
  • 2,861
  • 3
  • 29
  • 51