1 use crate::*;
2 use std::fmt::{Debug, Display};
3
4
5 #[track_caller]
assert_parse_ok_eq<T: PartialEq + Debug + Display>( input: &str, result: Result<T, ParseError>, expected: T, parse_method: &str, )6 pub(crate) fn assert_parse_ok_eq<T: PartialEq + Debug + Display>(
7 input: &str,
8 result: Result<T, ParseError>,
9 expected: T,
10 parse_method: &str,
11 ) {
12 match result {
13 Ok(actual) if actual == expected => {
14 if actual.to_string() != input {
15 panic!(
16 "formatting does not yield original input `{}`: {:?}",
17 input,
18 actual,
19 );
20 }
21 }
22 Ok(actual) => {
23 panic!(
24 "unexpected parsing result (with `{}`) for `{}`:\nactual: {:?}\nexpected: {:?}",
25 parse_method,
26 input,
27 actual,
28 expected,
29 );
30 }
31 Err(e) => {
32 panic!(
33 "expected `{}` to be parsed (with `{}`) successfully, but it failed: {:?}",
34 input,
35 parse_method,
36 e,
37 );
38 }
39 }
40 }
41
42 // This is not ideal, but to perform this check we need `proc-macro2`. So we
43 // just don't do anything if that feature is not enabled.
44 #[cfg(not(feature = "proc-macro2"))]
assert_roundtrip<T>(_: T, _: &str)45 pub(crate) fn assert_roundtrip<T>(_: T, _: &str) {}
46
47 #[cfg(feature = "proc-macro2")]
48 #[track_caller]
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,49 pub(crate) fn assert_roundtrip<T>(ours: T, input: &str)
50 where
51 T: std::convert::TryFrom<proc_macro2::Literal> + fmt::Debug + PartialEq + Clone,
52 proc_macro2::Literal: From<T>,
53 <T as std::convert::TryFrom<proc_macro2::Literal>>::Error: std::fmt::Display,
54 {
55 let pm_lit = input.parse::<proc_macro2::Literal>()
56 .expect("failed to parse input as proc_macro2::Literal");
57 let t_name = std::any::type_name::<T>();
58
59 // Unfortunately, `proc_macro2::Literal` does not implement `PartialEq`, so
60 // this is the next best thing.
61 if proc_macro2::Literal::from(ours.clone()).to_string() != pm_lit.to_string() {
62 panic!(
63 "Converting {} to proc_macro2::Literal has unexpected result:\
64 \nconverted: {:?}\nexpected: {:?}",
65 t_name,
66 proc_macro2::Literal::from(ours),
67 pm_lit,
68 );
69 }
70
71 match T::try_from(pm_lit) {
72 Err(e) => {
73 panic!("Trying to convert proc_macro2::Literal to {} results in error: {}", t_name, e);
74 }
75 Ok(res) => {
76 if res != ours {
77 panic!(
78 "Converting proc_macro2::Literal to {} has unexpected result:\
79 \nactual: {:?}\nexpected: {:?}",
80 t_name,
81 res,
82 ours,
83 );
84 }
85 }
86 }
87 }
88
89 macro_rules! assert_err {
90 ($ty:ident, $input:literal, $kind:ident, $( $span:tt )+ ) => {
91 assert_err_single!($ty::parse($input), $kind, $($span)+);
92 assert_err_single!($crate::Literal::parse($input), $kind, $($span)+);
93 };
94 }
95
96 macro_rules! assert_err_single {
97 ($expr:expr, $kind:ident, $( $span:tt )+ ) => {
98 let res = $expr;
99 let err = match res {
100 Err(e) => e,
101 Ok(v) => panic!(
102 "Expected `{}` to return an error, but it returned Ok({:?})",
103 stringify!($expr),
104 v,
105 ),
106 };
107 if err.kind != $crate::err::ParseErrorKind::$kind {
108 panic!(
109 "Expected error kind {} for `{}` but got {:?}",
110 stringify!($kind),
111 stringify!($expr),
112 err.kind,
113 )
114 }
115 let expected_span = assert_err_single!(@span $($span)+);
116 if err.span != expected_span {
117 panic!(
118 "Expected error span {:?} for `{}` but got {:?}",
119 expected_span,
120 stringify!($expr),
121 err.span,
122 )
123 }
124 };
125 (@span $start:literal .. $end:literal) => { Some($start .. $end) };
126 (@span $at:literal) => { Some($at.. $at + 1) };
127 (@span None) => { None };
128 }
129