1 use crate::Literal;
2
3
4 #[test]
empty()5 fn empty() {
6 assert_err!(Literal, "", Empty, None);
7 }
8
9 #[test]
invalid_literals()10 fn invalid_literals() {
11 assert_err_single!(Literal::parse("."), InvalidLiteral, None);
12 assert_err_single!(Literal::parse("+"), InvalidLiteral, None);
13 assert_err_single!(Literal::parse("-"), InvalidLiteral, None);
14 assert_err_single!(Literal::parse("e"), InvalidLiteral, None);
15 assert_err_single!(Literal::parse("e8"), InvalidLiteral, None);
16 assert_err_single!(Literal::parse("f32"), InvalidLiteral, None);
17 assert_err_single!(Literal::parse("foo"), InvalidLiteral, None);
18 assert_err_single!(Literal::parse("inf"), InvalidLiteral, None);
19 assert_err_single!(Literal::parse("nan"), InvalidLiteral, None);
20 assert_err_single!(Literal::parse("NaN"), InvalidLiteral, None);
21 assert_err_single!(Literal::parse("NAN"), InvalidLiteral, None);
22 assert_err_single!(Literal::parse("_2.7"), InvalidLiteral, None);
23 assert_err_single!(Literal::parse(".5"), InvalidLiteral, None);
24 }
25
26 #[test]
misc()27 fn misc() {
28 assert_err_single!(Literal::parse("0x44.5"), UnexpectedChar, 4..6);
29 assert_err_single!(Literal::parse("a"), InvalidLiteral, None);
30 assert_err_single!(Literal::parse(";"), InvalidLiteral, None);
31 assert_err_single!(Literal::parse("0;"), UnexpectedChar, 1);
32 assert_err_single!(Literal::parse(" 0"), InvalidLiteral, None);
33 assert_err_single!(Literal::parse("0 "), UnexpectedChar, 1);
34 assert_err_single!(Literal::parse("_"), InvalidLiteral, None);
35 assert_err_single!(Literal::parse("_3"), InvalidLiteral, None);
36 assert_err_single!(Literal::parse("a_123"), InvalidLiteral, None);
37 assert_err_single!(Literal::parse("B_123"), InvalidLiteral, None);
38 }
39
40 macro_rules! assert_no_panic {
41 ($input:expr) => {
42 let arr = $input;
43 let input = std::str::from_utf8(&arr).expect("not unicode");
44 let res = std::panic::catch_unwind(move || {
45 let _ = Literal::parse(input);
46 let _ = crate::BoolLit::parse(input);
47 let _ = crate::IntegerLit::parse(input);
48 let _ = crate::FloatLit::parse(input);
49 let _ = crate::CharLit::parse(input);
50 let _ = crate::StringLit::parse(input);
51 let _ = crate::ByteLit::parse(input);
52 let _ = crate::ByteStringLit::parse(input);
53 });
54
55 if let Err(e) = res {
56 println!("\n!!! panic for: {:?}", input);
57 std::panic::resume_unwind(e);
58 }
59 };
60 }
61
62 #[test]
63 #[ignore]
never_panic_up_to_3()64 fn never_panic_up_to_3() {
65 for a in 0..128 {
66 assert_no_panic!([a]);
67 for b in 0..128 {
68 assert_no_panic!([a, b]);
69 for c in 0..128 {
70 assert_no_panic!([a, b, c]);
71 }
72 }
73 }
74 }
75
76 // This test takes super long in debug mode, but in release mode it's fine.
77 #[test]
78 #[ignore]
never_panic_len_4()79 fn never_panic_len_4() {
80 for a in 0..128 {
81 for b in 0..128 {
82 for c in 0..128 {
83 for d in 0..128 {
84 assert_no_panic!([a, b, c, d]);
85 }
86 }
87 }
88 }
89 }
90
91 #[cfg(feature = "proc-macro2")]
92 #[test]
proc_macro()93 fn proc_macro() {
94 use std::convert::TryFrom;
95 use proc_macro2::{
96 self as pm2, TokenTree, Group, TokenStream, Delimiter, Spacing, Punct, Span, Ident,
97 };
98 use crate::{
99 BoolLit, ByteLit, ByteStringLit, CharLit, FloatLit, IntegerLit, StringLit, err::TokenKind
100 };
101
102
103 macro_rules! assert_invalid_token {
104 ($input:expr, expected: $expected:path, actual: $actual:path $(,)?) => {
105 let err = $input.unwrap_err();
106 if err.expected != $expected {
107 panic!(
108 "err.expected was expected to be {:?}, but is {:?}",
109 $expected,
110 err.expected,
111 );
112 }
113 if err.actual != $actual {
114 panic!("err.actual was expected to be {:?}, but is {:?}", $actual, err.actual);
115 }
116 };
117 }
118
119
120 let pm_u16_lit = pm2::Literal::u16_suffixed(2700);
121 let pm_i16_lit = pm2::Literal::i16_unsuffixed(3912);
122 let pm_f32_lit = pm2::Literal::f32_unsuffixed(3.14);
123 let pm_f64_lit = pm2::Literal::f64_suffixed(99.3);
124 let pm_string_lit = pm2::Literal::string("hello ");
125 let pm_bytestr_lit = pm2::Literal::byte_string(b"hello \nfoxxo");
126 let pm_char_lit = pm2::Literal::character('');
127
128 let u16_lit = Literal::parse("2700u16".to_string()).unwrap();
129 let i16_lit = Literal::parse("3912".to_string()).unwrap();
130 let f32_lit = Literal::parse("3.14".to_string()).unwrap();
131 let f64_lit = Literal::parse("99.3f64".to_string()).unwrap();
132 let string_lit = Literal::parse(r#""hello ""#.to_string()).unwrap();
133 let bytestr_lit = Literal::parse(r#"b"hello \nfoxxo""#.to_string()).unwrap();
134 let char_lit = Literal::parse("''".to_string()).unwrap();
135
136 assert_eq!(Literal::from(&pm_u16_lit), u16_lit);
137 assert_eq!(Literal::from(&pm_i16_lit), i16_lit);
138 assert_eq!(Literal::from(&pm_f32_lit), f32_lit);
139 assert_eq!(Literal::from(&pm_f64_lit), f64_lit);
140 assert_eq!(Literal::from(&pm_string_lit), string_lit);
141 assert_eq!(Literal::from(&pm_bytestr_lit), bytestr_lit);
142 assert_eq!(Literal::from(&pm_char_lit), char_lit);
143
144
145 let group = TokenTree::from(Group::new(Delimiter::Brace, TokenStream::new()));
146 let punct = TokenTree::from(Punct::new(':', Spacing::Alone));
147 let ident = TokenTree::from(Ident::new("peter", Span::call_site()));
148
149 assert_eq!(
150 Literal::try_from(TokenTree::Literal(pm2::Literal::string("hello "))).unwrap(),
151 Literal::String(StringLit::parse(r#""hello ""#.to_string()).unwrap()),
152 );
153 assert_invalid_token!(
154 Literal::try_from(punct.clone()),
155 expected: TokenKind::Literal,
156 actual: TokenKind::Punct,
157 );
158 assert_invalid_token!(
159 Literal::try_from(group.clone()),
160 expected: TokenKind::Literal,
161 actual: TokenKind::Group,
162 );
163 assert_invalid_token!(
164 Literal::try_from(ident.clone()),
165 expected: TokenKind::Literal,
166 actual: TokenKind::Ident,
167 );
168
169
170 assert_eq!(Literal::from(IntegerLit::try_from(pm_u16_lit.clone()).unwrap()), u16_lit);
171 assert_eq!(Literal::from(IntegerLit::try_from(pm_i16_lit.clone()).unwrap()), i16_lit);
172 assert_eq!(Literal::from(FloatLit::try_from(pm_f32_lit.clone()).unwrap()), f32_lit);
173 assert_eq!(Literal::from(FloatLit::try_from(pm_f64_lit.clone()).unwrap()), f64_lit);
174 assert_eq!(Literal::from(StringLit::try_from(pm_string_lit.clone()).unwrap()), string_lit);
175 assert_eq!(
176 Literal::from(ByteStringLit::try_from(pm_bytestr_lit.clone()).unwrap()),
177 bytestr_lit,
178 );
179 assert_eq!(Literal::from(CharLit::try_from(pm_char_lit.clone()).unwrap()), char_lit);
180
181 assert_invalid_token!(
182 StringLit::try_from(pm_u16_lit.clone()),
183 expected: TokenKind::StringLit,
184 actual: TokenKind::IntegerLit,
185 );
186 assert_invalid_token!(
187 StringLit::try_from(pm_f32_lit.clone()),
188 expected: TokenKind::StringLit,
189 actual: TokenKind::FloatLit,
190 );
191 assert_invalid_token!(
192 ByteLit::try_from(pm_bytestr_lit.clone()),
193 expected: TokenKind::ByteLit,
194 actual: TokenKind::ByteStringLit,
195 );
196 assert_invalid_token!(
197 ByteLit::try_from(pm_i16_lit.clone()),
198 expected: TokenKind::ByteLit,
199 actual: TokenKind::IntegerLit,
200 );
201 assert_invalid_token!(
202 IntegerLit::try_from(pm_string_lit.clone()),
203 expected: TokenKind::IntegerLit,
204 actual: TokenKind::StringLit,
205 );
206 assert_invalid_token!(
207 IntegerLit::try_from(pm_char_lit.clone()),
208 expected: TokenKind::IntegerLit,
209 actual: TokenKind::CharLit,
210 );
211
212
213 assert_eq!(
214 Literal::from(IntegerLit::try_from(TokenTree::from(pm_u16_lit.clone())).unwrap()),
215 u16_lit,
216 );
217 assert_eq!(
218 Literal::from(IntegerLit::try_from(TokenTree::from(pm_i16_lit.clone())).unwrap()),
219 i16_lit,
220 );
221 assert_eq!(
222 Literal::from(FloatLit::try_from(TokenTree::from(pm_f32_lit.clone())).unwrap()),
223 f32_lit,
224 );
225 assert_eq!(
226 Literal::from(FloatLit::try_from(TokenTree::from(pm_f64_lit.clone())).unwrap()),
227 f64_lit,
228 );
229 assert_eq!(
230 Literal::from(StringLit::try_from(TokenTree::from(pm_string_lit.clone())).unwrap()),
231 string_lit,
232 );
233 assert_eq!(
234 Literal::from(ByteStringLit::try_from(TokenTree::from(pm_bytestr_lit.clone())).unwrap()),
235 bytestr_lit,
236 );
237 assert_eq!(
238 Literal::from(CharLit::try_from(TokenTree::from(pm_char_lit.clone())).unwrap()),
239 char_lit,
240 );
241
242 assert_invalid_token!(
243 StringLit::try_from(TokenTree::from(pm_u16_lit.clone())),
244 expected: TokenKind::StringLit,
245 actual: TokenKind::IntegerLit,
246 );
247 assert_invalid_token!(
248 StringLit::try_from(TokenTree::from(pm_f32_lit.clone())),
249 expected: TokenKind::StringLit,
250 actual: TokenKind::FloatLit,
251 );
252 assert_invalid_token!(
253 BoolLit::try_from(TokenTree::from(pm_bytestr_lit.clone())),
254 expected: TokenKind::BoolLit,
255 actual: TokenKind::ByteStringLit,
256 );
257 assert_invalid_token!(
258 BoolLit::try_from(TokenTree::from(pm_i16_lit.clone())),
259 expected: TokenKind::BoolLit,
260 actual: TokenKind::IntegerLit,
261 );
262 assert_invalid_token!(
263 IntegerLit::try_from(TokenTree::from(pm_string_lit.clone())),
264 expected: TokenKind::IntegerLit,
265 actual: TokenKind::StringLit,
266 );
267 assert_invalid_token!(
268 IntegerLit::try_from(TokenTree::from(pm_char_lit.clone())),
269 expected: TokenKind::IntegerLit,
270 actual: TokenKind::CharLit,
271 );
272
273 assert_invalid_token!(
274 StringLit::try_from(TokenTree::from(group)),
275 expected: TokenKind::StringLit,
276 actual: TokenKind::Group,
277 );
278 assert_invalid_token!(
279 BoolLit::try_from(TokenTree::from(punct)),
280 expected: TokenKind::BoolLit,
281 actual: TokenKind::Punct,
282 );
283 assert_invalid_token!(
284 FloatLit::try_from(TokenTree::from(ident)),
285 expected: TokenKind::FloatLit,
286 actual: TokenKind::Ident,
287 );
288 }
289
290 #[cfg(feature = "proc-macro2")]
291 #[test]
bool_try_from_tt()292 fn bool_try_from_tt() {
293 use std::convert::TryFrom;
294 use proc_macro2::{Ident, Span, TokenTree};
295 use crate::BoolLit;
296
297
298 let ident = |s: &str| Ident::new(s, Span::call_site());
299
300 assert_eq!(BoolLit::try_from(TokenTree::Ident(ident("true"))).unwrap(), BoolLit::True);
301 assert_eq!(BoolLit::try_from(TokenTree::Ident(ident("false"))).unwrap(), BoolLit::False);
302
303 assert!(BoolLit::try_from(TokenTree::Ident(ident("falsex"))).is_err());
304 assert!(BoolLit::try_from(TokenTree::Ident(ident("_false"))).is_err());
305 assert!(BoolLit::try_from(TokenTree::Ident(ident("False"))).is_err());
306 assert!(BoolLit::try_from(TokenTree::Ident(ident("True"))).is_err());
307 assert!(BoolLit::try_from(TokenTree::Ident(ident("ltrue"))).is_err());
308
309
310 assert_eq!(
311 Literal::try_from(TokenTree::Ident(ident("true"))).unwrap(),
312 Literal::Bool(BoolLit::True),
313 );
314 assert_eq!(
315 Literal::try_from(TokenTree::Ident(ident("false"))).unwrap(),
316 Literal::Bool(BoolLit::False),
317 );
318
319 assert!(Literal::try_from(TokenTree::Ident(ident("falsex"))).is_err());
320 assert!(Literal::try_from(TokenTree::Ident(ident("_false"))).is_err());
321 assert!(Literal::try_from(TokenTree::Ident(ident("False"))).is_err());
322 assert!(Literal::try_from(TokenTree::Ident(ident("True"))).is_err());
323 assert!(Literal::try_from(TokenTree::Ident(ident("ltrue"))).is_err());
324 }
325
326 #[cfg(feature = "proc-macro2")]
327 #[test]
invalid_token_display()328 fn invalid_token_display() {
329 use crate::{InvalidToken, err::TokenKind};
330
331 let span = crate::err::Span::Two(proc_macro2::Span::call_site());
332 assert_eq!(
333 InvalidToken {
334 actual: TokenKind::StringLit,
335 expected: TokenKind::FloatLit,
336 span,
337 }.to_string(),
338 r#"expected a float literal (e.g. `3.14`), but found a string literal (e.g. "Ferris")"#,
339 );
340
341 assert_eq!(
342 InvalidToken {
343 actual: TokenKind::Punct,
344 expected: TokenKind::Literal,
345 span,
346 }.to_string(),
347 r#"expected a literal, but found a punctuation character"#,
348 );
349 }
350