| use crate::*; |
| use std::fmt::{Debug, Display}; |
| |
| |
| #[track_caller] |
| pub(crate) fn assert_parse_ok_eq<T: PartialEq + Debug + Display>( |
| input: &str, |
| result: Result<T, ParseError>, |
| expected: T, |
| parse_method: &str, |
| ) { |
| match result { |
| Ok(actual) if actual == expected => { |
| if actual.to_string() != input { |
| panic!( |
| "formatting does not yield original input `{}`: {:?}", |
| input, |
| actual, |
| ); |
| } |
| } |
| Ok(actual) => { |
| panic!( |
| "unexpected parsing result (with `{}`) for `{}`:\nactual: {:?}\nexpected: {:?}", |
| parse_method, |
| input, |
| actual, |
| expected, |
| ); |
| } |
| Err(e) => { |
| panic!( |
| "expected `{}` to be parsed (with `{}`) successfully, but it failed: {:?}", |
| input, |
| parse_method, |
| e, |
| ); |
| } |
| } |
| } |
| |
| // This is not ideal, but to perform this check we need `proc-macro2`. So we |
| // just don't do anything if that feature is not enabled. |
| #[cfg(not(feature = "proc-macro2"))] |
| pub(crate) fn assert_roundtrip<T>(_: T, _: &str) {} |
| |
| #[cfg(feature = "proc-macro2")] |
| #[track_caller] |
| pub(crate) fn assert_roundtrip<T>(ours: T, input: &str) |
| where |
| T: std::convert::TryFrom<proc_macro2::Literal> + fmt::Debug + PartialEq + Clone, |
| proc_macro2::Literal: From<T>, |
| <T as std::convert::TryFrom<proc_macro2::Literal>>::Error: std::fmt::Display, |
| { |
| let pm_lit = input.parse::<proc_macro2::Literal>() |
| .expect("failed to parse input as proc_macro2::Literal"); |
| let t_name = std::any::type_name::<T>(); |
| |
| // Unfortunately, `proc_macro2::Literal` does not implement `PartialEq`, so |
| // this is the next best thing. |
| if proc_macro2::Literal::from(ours.clone()).to_string() != pm_lit.to_string() { |
| panic!( |
| "Converting {} to proc_macro2::Literal has unexpected result:\ |
| \nconverted: {:?}\nexpected: {:?}", |
| t_name, |
| proc_macro2::Literal::from(ours), |
| pm_lit, |
| ); |
| } |
| |
| match T::try_from(pm_lit) { |
| Err(e) => { |
| panic!("Trying to convert proc_macro2::Literal to {} results in error: {}", t_name, e); |
| } |
| Ok(res) => { |
| if res != ours { |
| panic!( |
| "Converting proc_macro2::Literal to {} has unexpected result:\ |
| \nactual: {:?}\nexpected: {:?}", |
| t_name, |
| res, |
| ours, |
| ); |
| } |
| } |
| } |
| } |
| |
| macro_rules! assert_err { |
| ($ty:ident, $input:literal, $kind:ident, $( $span:tt )+ ) => { |
| assert_err_single!($ty::parse($input), $kind, $($span)+); |
| assert_err_single!($crate::Literal::parse($input), $kind, $($span)+); |
| }; |
| } |
| |
| macro_rules! assert_err_single { |
| ($expr:expr, $kind:ident, $( $span:tt )+ ) => { |
| let res = $expr; |
| let err = match res { |
| Err(e) => e, |
| Ok(v) => panic!( |
| "Expected `{}` to return an error, but it returned Ok({:?})", |
| stringify!($expr), |
| v, |
| ), |
| }; |
| if err.kind != $crate::err::ParseErrorKind::$kind { |
| panic!( |
| "Expected error kind {} for `{}` but got {:?}", |
| stringify!($kind), |
| stringify!($expr), |
| err.kind, |
| ) |
| } |
| let expected_span = assert_err_single!(@span $($span)+); |
| if err.span != expected_span { |
| panic!( |
| "Expected error span {:?} for `{}` but got {:?}", |
| expected_span, |
| stringify!($expr), |
| err.span, |
| ) |
| } |
| }; |
| (@span $start:literal .. $end:literal) => { Some($start .. $end) }; |
| (@span $at:literal) => { Some($at.. $at + 1) }; |
| (@span None) => { None }; |
| } |