use {
nom::{bytes::complete::tag, sequence::tuple, IResult},
nom_tracer::*,
};
fn parse_ab(input: &str) -> IResult<&str, (&str, &str)> {
tuple((tag("a"), tag("b")))(input)
}
#[test]
fn test_tr_function_always_works() {
let result = tr("test_tag", Some("context"), "test_parser", parse_ab)("ab");
assert!(result.is_ok());
assert_eq!(result, Ok(("", ("a", "b"))));
}
#[cfg(feature = "trace")]
mod trace_tests {
use super::*;
#[test]
fn test_simple_trace() {
let result = trace!(parse_ab)("ab");
assert!(result.is_ok());
let trace = get_trace!().unwrap();
assert!(trace.contains("test_simple_trace"));
assert!(trace.contains("-> Ok"));
}
#[test]
fn test_trace_with_tag() {
let result = trace!(custom_tag, parse_ab)("ab");
assert!(result.is_ok());
let trace = get_trace!(custom_tag).unwrap();
assert!(trace.contains("test_trace_with_tag"));
assert!(trace.contains("-> Ok"));
}
#[test]
fn test_trace_with_context() {
let result = trace!("custom_context", parse_ab)("ab");
assert!(result.is_ok());
let trace = get_trace!().unwrap();
assert!(trace.contains("test_trace_with_context"));
assert!(trace.contains("custom_context"));
assert!(trace.contains("-> Ok"));
}
#[test]
fn test_activate_deactivate_reset() {
activate_trace!();
let result = trace!(parse_ab)("ab");
assert!(result.is_ok());
assert!(!get_trace!().unwrap().is_empty());
deactivate_trace!();
let result = trace!(parse_ab)("ab");
assert!(result.is_ok());
assert_eq!(
get_trace!(),
get_trace!(),
"Trace should not change after deactivation"
);
activate_trace!();
reset_trace!();
assert!(
get_trace!().unwrap().is_empty(),
"Trace should be empty after reset"
);
let result = trace!(parse_ab)("ab");
assert!(result.is_ok());
assert!(
!get_trace!().unwrap().is_empty(),
"Trace should not be empty after new parsing"
);
}
}
#[cfg(all(feature = "trace", feature = "trace-context"))]
mod trace_context_tests {
use {
super::*,
nom::error::{ErrorKind, VerboseError, VerboseErrorKind},
};
#[test]
fn test_context_addition() {
let mut parser = tr(
DEFAULT_TAG,
Some("context"),
"test_parser",
tag::<_, _, VerboseError<_>>("hello"),
);
let result = parser("world");
assert!(result.is_err());
if let Err(nom::Err::Error(e)) = result {
assert_eq!(e.errors.len(), 2);
assert_eq!(e.errors[1].1, VerboseErrorKind::Context("context"));
assert_eq!(e.errors[0].1, VerboseErrorKind::Nom(ErrorKind::Tag));
} else {
panic!("Expected Err(nom::Err::Error)");
}
}
}
#[cfg(all(feature = "trace", feature = "trace-silencing"))]
mod trace_silencing_tests {
use super::*;
#[test]
fn test_silence_tree() {
fn outer_parser(input: &str) -> IResult<&str, (&str, &str)> {
trace!("outer", tuple((tag("a"), silence_tree!("inner", tag("b")))))(input)
}
let result = outer_parser("ab");
assert!(result.is_ok());
let trace = get_trace!().unwrap();
assert!(trace.contains("outer"));
assert!(!trace.contains("inner"));
}
}
#[cfg(not(feature = "trace"))]
mod no_trace_tests {
use super::*;
#[test]
fn test_trace_macros_do_nothing() {
let result = trace!(parse_ab)("ab");
assert!(result.is_ok());
activate_trace!();
deactivate_trace!();
reset_trace!();
assert!(get_trace!().is_none());
}
#[cfg(feature = "trace-context")]
#[test]
fn test_context_addition_without_trace() {
use nom::error::{ErrorKind, VerboseError};
let mut parser = tr(
DEFAULT_TAG,
Some("context"),
"test_parser",
tag::<_, _, VerboseError<_>>("hello"),
);
let result = parser("world");
assert!(result.is_err());
if let Err(nom::Err::Error(e)) = result {
assert_eq!(e.errors.len(), 2);
assert_eq!(e.errors[1].1, VerboseErrorKind::Context("context"));
assert_eq!(e.errors[0].1, VerboseErrorKind::Nom(ErrorKind::Tag));
} else {
panic!("Expected Err(nom::Err::Error)");
}
}
}