1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
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 };
}
|