blob: 673a35f9bb7cb17145cdb2895d902b3a021ab101 [file] [log] [blame]
David Tolnaye5806852017-06-01 12:49:20 -07001extern crate proc_macro2;
2
David Tolnaya13d1422018-03-31 21:27:48 +02003use std::str::{self, FromStr};
Alex Crichton8c030332018-01-16 08:07:36 -08004
Alex Crichtonf3888432018-05-16 09:11:05 -07005use proc_macro2::{Literal, Spacing, Span, Ident, TokenStream, TokenTree};
David Tolnaye5806852017-06-01 12:49:20 -07006
7#[test]
David Tolnay489c6422018-04-07 08:37:28 -07008fn terms() {
Alex Crichtonf3888432018-05-16 09:11:05 -07009 assert_eq!(Ident::new("String", Span::call_site()).to_string(), "String");
10 assert_eq!(Ident::new("fn", Span::call_site()).to_string(), "fn");
11 assert_eq!(Ident::new("_", Span::call_site()).to_string(), "_");
David Tolnay489c6422018-04-07 08:37:28 -070012}
13
14#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070015#[cfg(procmacro2_semver_exempt)]
David Tolnay489c6422018-04-07 08:37:28 -070016fn raw_terms() {
David Tolnay48ea5042018-04-23 19:17:35 -070017 assert_eq!(
Alex Crichtonf3888432018-05-16 09:11:05 -070018 Ident::new_raw("String", Span::call_site()).to_string(),
David Tolnay48ea5042018-04-23 19:17:35 -070019 "r#String"
20 );
Alex Crichtonf3888432018-05-16 09:11:05 -070021 assert_eq!(Ident::new_raw("fn", Span::call_site()).to_string(), "r#fn");
22 assert_eq!(Ident::new_raw("_", Span::call_site()).to_string(), "r#_");
David Tolnay489c6422018-04-07 08:37:28 -070023}
24
25#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070026#[should_panic(expected = "Ident is not allowed to be empty; use Option<Ident>")]
David Tolnay489c6422018-04-07 08:37:28 -070027fn term_empty() {
Alex Crichtonf3888432018-05-16 09:11:05 -070028 Ident::new("", Span::call_site());
David Tolnay489c6422018-04-07 08:37:28 -070029}
30
31#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070032#[should_panic(expected = "Ident cannot be a number; use Literal instead")]
David Tolnay489c6422018-04-07 08:37:28 -070033fn term_number() {
Alex Crichtonf3888432018-05-16 09:11:05 -070034 Ident::new("255", Span::call_site());
David Tolnay489c6422018-04-07 08:37:28 -070035}
36
37#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070038#[should_panic(expected = "\"a#\" is not a valid Ident")]
David Tolnay489c6422018-04-07 08:37:28 -070039fn term_invalid() {
Alex Crichtonf3888432018-05-16 09:11:05 -070040 Ident::new("a#", Span::call_site());
David Tolnay489c6422018-04-07 08:37:28 -070041}
42
43#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070044#[should_panic(expected = "not a valid Ident")]
David Tolnay489c6422018-04-07 08:37:28 -070045fn raw_term_empty() {
Alex Crichtonf3888432018-05-16 09:11:05 -070046 Ident::new("r#", Span::call_site());
David Tolnay489c6422018-04-07 08:37:28 -070047}
48
49#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070050#[should_panic(expected = "not a valid Ident")]
David Tolnay489c6422018-04-07 08:37:28 -070051fn raw_term_number() {
Alex Crichtonf3888432018-05-16 09:11:05 -070052 Ident::new("r#255", Span::call_site());
David Tolnay489c6422018-04-07 08:37:28 -070053}
54
55#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070056#[should_panic(expected = "\"r#a#\" is not a valid Ident")]
David Tolnay489c6422018-04-07 08:37:28 -070057fn raw_term_invalid() {
Alex Crichtonf3888432018-05-16 09:11:05 -070058 Ident::new("r#a#", Span::call_site());
David Tolnay489c6422018-04-07 08:37:28 -070059}
60
61#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070062#[should_panic(expected = "not a valid Ident")]
David Tolnay489c6422018-04-07 08:37:28 -070063fn lifetime_empty() {
Alex Crichtonf3888432018-05-16 09:11:05 -070064 Ident::new("'", Span::call_site());
David Tolnay489c6422018-04-07 08:37:28 -070065}
66
67#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070068#[should_panic(expected = "not a valid Ident")]
David Tolnay489c6422018-04-07 08:37:28 -070069fn lifetime_number() {
Alex Crichtonf3888432018-05-16 09:11:05 -070070 Ident::new("'255", Span::call_site());
David Tolnay489c6422018-04-07 08:37:28 -070071}
72
73#[test]
Alex Crichtonf3888432018-05-16 09:11:05 -070074#[should_panic(expected = r#""\'a#" is not a valid Ident"#)]
David Tolnay489c6422018-04-07 08:37:28 -070075fn lifetime_invalid() {
Alex Crichtonf3888432018-05-16 09:11:05 -070076 Ident::new("'a#", Span::call_site());
David Tolnaye5806852017-06-01 12:49:20 -070077}
78
79#[test]
80fn literals() {
Alex Crichton1a7f7622017-07-05 17:47:15 -070081 assert_eq!(Literal::string("foo").to_string(), "\"foo\"");
82 assert_eq!(Literal::string("\"").to_string(), "\"\\\"\"");
Alex Crichtonaf5bad42018-03-27 14:45:10 -070083 assert_eq!(Literal::f32_unsuffixed(10.0).to_string(), "10.0");
David Tolnaye5806852017-06-01 12:49:20 -070084}
85
86#[test]
87fn roundtrip() {
88 fn roundtrip(p: &str) {
89 println!("parse: {}", p);
90 let s = p.parse::<TokenStream>().unwrap().to_string();
91 println!("first: {}", s);
92 let s2 = s.to_string().parse::<TokenStream>().unwrap().to_string();
93 assert_eq!(s, s2);
94 }
95 roundtrip("a");
96 roundtrip("<<");
97 roundtrip("<<=");
David Tolnayb28f38a2018-03-31 22:02:29 +020098 roundtrip(
99 "
David Tolnaye5806852017-06-01 12:49:20 -0700100 1
101 1.0
102 1f32
103 2f64
104 1usize
105 4isize
106 4e10
107 1_000
108 1_0i32
109 8u8
110 9
111 0
112 0xffffffffffffffffffffffffffffffff
David Tolnayb28f38a2018-03-31 22:02:29 +0200113 ",
114 );
David Tolnaye5806852017-06-01 12:49:20 -0700115 roundtrip("'a");
Alex Crichtonf5479a92018-05-17 10:56:26 -0700116 roundtrip("'_");
David Tolnaye5806852017-06-01 12:49:20 -0700117 roundtrip("'static");
David Tolnay8d109342017-12-25 18:24:45 -0500118 roundtrip("'\\u{10__FFFF}'");
119 roundtrip("\"\\u{10_F0FF__}foo\\u{1_0_0_0__}\"");
David Tolnaye5806852017-06-01 12:49:20 -0700120}
121
122#[test]
123fn fail() {
124 fn fail(p: &str) {
Alex Crichtonf3888432018-05-16 09:11:05 -0700125 if let Ok(s) = p.parse::<TokenStream>() {
126 panic!("should have failed to parse: {}\n{:#?}", p, s);
David Tolnaye5806852017-06-01 12:49:20 -0700127 }
128 }
129 fail("1x");
130 fail("1u80");
131 fail("1f320");
132 fail("' static");
David Tolnaya13d1422018-03-31 21:27:48 +0200133 fail("r#1");
134 fail("r#_");
David Tolnaye5806852017-06-01 12:49:20 -0700135}
Nika Layzellf8d5f212017-12-11 14:07:02 -0500136
David Tolnay1ebe3972018-01-02 20:14:20 -0800137#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500138#[test]
139fn span_test() {
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700140 use proc_macro2::TokenTree;
141
Nika Layzellf8d5f212017-12-11 14:07:02 -0500142 fn check_spans(p: &str, mut lines: &[(usize, usize, usize, usize)]) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500143 let ts = p.parse::<TokenStream>().unwrap();
144 check_spans_internal(ts, &mut lines);
145 }
146
David Tolnayb28f38a2018-03-31 22:02:29 +0200147 fn check_spans_internal(ts: TokenStream, lines: &mut &[(usize, usize, usize, usize)]) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500148 for i in ts {
149 if let Some((&(sline, scol, eline, ecol), rest)) = lines.split_first() {
150 *lines = rest;
151
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700152 let start = i.span().start();
Nika Layzellf8d5f212017-12-11 14:07:02 -0500153 assert_eq!(start.line, sline, "sline did not match for {}", i);
154 assert_eq!(start.column, scol, "scol did not match for {}", i);
155
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700156 let end = i.span().end();
Nika Layzellf8d5f212017-12-11 14:07:02 -0500157 assert_eq!(end.line, eline, "eline did not match for {}", i);
158 assert_eq!(end.column, ecol, "ecol did not match for {}", i);
159
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700160 match i {
161 TokenTree::Group(ref g) => {
162 check_spans_internal(g.stream().clone(), lines);
163 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500164 _ => {}
165 }
166 }
167 }
168 }
169
David Tolnayb28f38a2018-03-31 22:02:29 +0200170 check_spans(
171 "\
Nika Layzellf8d5f212017-12-11 14:07:02 -0500172/// This is a document comment
173testing 123
174{
175 testing 234
David Tolnayb28f38a2018-03-31 22:02:29 +0200176}",
177 &[
Alex Crichton1eb96a02018-04-04 13:07:35 -0700178 (1, 0, 1, 30), // #
179 (1, 0, 1, 30), // [ ... ]
180 (1, 0, 1, 30), // doc
181 (1, 0, 1, 30), // =
182 (1, 0, 1, 30), // "This is..."
183 (2, 0, 2, 7), // testing
184 (2, 8, 2, 11), // 123
185 (3, 0, 5, 1), // { ... }
186 (4, 2, 4, 9), // testing
187 (4, 10, 4, 13), // 234
David Tolnayb28f38a2018-03-31 22:02:29 +0200188 ],
189 );
Nika Layzellf8d5f212017-12-11 14:07:02 -0500190}
191
David Tolnay1ebe3972018-01-02 20:14:20 -0800192#[cfg(procmacro2_semver_exempt)]
David Tolnayd66ecf62018-01-02 20:05:42 -0800193#[cfg(not(feature = "nightly"))]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500194#[test]
195fn default_span() {
196 let start = Span::call_site().start();
197 assert_eq!(start.line, 1);
198 assert_eq!(start.column, 0);
199 let end = Span::call_site().end();
200 assert_eq!(end.line, 1);
201 assert_eq!(end.column, 0);
202 let source_file = Span::call_site().source_file();
Nika Layzellfb783e32017-12-30 14:58:27 -0500203 assert_eq!(source_file.path().to_string(), "<unspecified>");
Nika Layzellf8d5f212017-12-11 14:07:02 -0500204 assert!(!source_file.is_real());
205}
206
David Tolnay1ebe3972018-01-02 20:14:20 -0800207#[cfg(procmacro2_semver_exempt)]
Nika Layzellddea1562017-12-11 14:25:35 -0500208#[test]
209fn span_join() {
David Tolnayb28f38a2018-03-31 22:02:29 +0200210 let source1 = "aaa\nbbb"
211 .parse::<TokenStream>()
212 .unwrap()
213 .into_iter()
214 .collect::<Vec<_>>();
215 let source2 = "ccc\nddd"
216 .parse::<TokenStream>()
217 .unwrap()
218 .into_iter()
219 .collect::<Vec<_>>();
Nika Layzellddea1562017-12-11 14:25:35 -0500220
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700221 assert!(source1[0].span().source_file() != source2[0].span().source_file());
David Tolnayb28f38a2018-03-31 22:02:29 +0200222 assert_eq!(
223 source1[0].span().source_file(),
224 source1[1].span().source_file()
225 );
Nika Layzellddea1562017-12-11 14:25:35 -0500226
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700227 let joined1 = source1[0].span().join(source1[1].span());
228 let joined2 = source1[0].span().join(source2[0].span());
Nika Layzellddea1562017-12-11 14:25:35 -0500229 assert!(joined1.is_some());
230 assert!(joined2.is_none());
231
232 let start = joined1.unwrap().start();
233 let end = joined1.unwrap().end();
234 assert_eq!(start.line, 1);
235 assert_eq!(start.column, 0);
236 assert_eq!(end.line, 2);
237 assert_eq!(end.column, 3);
238
David Tolnayb28f38a2018-03-31 22:02:29 +0200239 assert_eq!(
240 joined1.unwrap().source_file(),
241 source1[0].span().source_file()
242 );
Nika Layzellddea1562017-12-11 14:25:35 -0500243}
Alex Crichton8c030332018-01-16 08:07:36 -0800244
245#[test]
246fn no_panic() {
247 let s = str::from_utf8(b"b\'\xc2\x86 \x00\x00\x00^\"").unwrap();
248 assert!(s.parse::<proc_macro2::TokenStream>().is_err());
249}
250
Alex Crichtonf7df57c2018-01-21 21:05:11 -0800251#[test]
David Tolnay639e4ba2018-03-31 21:10:55 +0200252fn tricky_doc_comment() {
Alex Crichtonf7df57c2018-01-21 21:05:11 -0800253 let stream = "/**/".parse::<proc_macro2::TokenStream>().unwrap();
254 let tokens = stream.into_iter().collect::<Vec<_>>();
255 assert!(tokens.is_empty(), "not empty -- {:?}", tokens);
Alex Crichtond7904e52018-01-23 11:08:45 -0800256
257 let stream = "/// doc".parse::<proc_macro2::TokenStream>().unwrap();
258 let tokens = stream.into_iter().collect::<Vec<_>>();
Alex Crichton1eb96a02018-04-04 13:07:35 -0700259 assert!(tokens.len() == 2, "not length 2 -- {:?}", tokens);
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700260 match tokens[0] {
Alex Crichtonf3888432018-05-16 09:11:05 -0700261 proc_macro2::TokenTree::Punct(ref tt) => assert_eq!(tt.as_char(), '#'),
Alex Crichtond7904e52018-01-23 11:08:45 -0800262 _ => panic!("wrong token {:?}", tokens[0]),
263 }
Alex Crichton1eb96a02018-04-04 13:07:35 -0700264 let mut tokens = match tokens[1] {
265 proc_macro2::TokenTree::Group(ref tt) => {
266 assert_eq!(tt.delimiter(), proc_macro2::Delimiter::Bracket);
267 tt.stream().into_iter()
268 }
269 _ => panic!("wrong token {:?}", tokens[0]),
270 };
271
272 match tokens.next().unwrap() {
Alex Crichtonf3888432018-05-16 09:11:05 -0700273 proc_macro2::TokenTree::Ident(ref tt) => assert_eq!(tt.to_string(), "doc"),
Alex Crichton1eb96a02018-04-04 13:07:35 -0700274 t => panic!("wrong token {:?}", t),
275 }
276 match tokens.next().unwrap() {
Alex Crichtonf3888432018-05-16 09:11:05 -0700277 proc_macro2::TokenTree::Punct(ref tt) => assert_eq!(tt.as_char(), '='),
Alex Crichton1eb96a02018-04-04 13:07:35 -0700278 t => panic!("wrong token {:?}", t),
279 }
280 match tokens.next().unwrap() {
281 proc_macro2::TokenTree::Literal(ref tt) => {
282 assert_eq!(tt.to_string(), "\" doc\"");
283 }
284 t => panic!("wrong token {:?}", t),
285 }
286 assert!(tokens.next().is_none());
287
288 let stream = "//! doc".parse::<proc_macro2::TokenStream>().unwrap();
289 let tokens = stream.into_iter().collect::<Vec<_>>();
290 assert!(tokens.len() == 3, "not length 3 -- {:?}", tokens);
Alex Crichtonf7df57c2018-01-21 21:05:11 -0800291}
292
David Tolnaya13d1422018-03-31 21:27:48 +0200293#[test]
David Tolnay3a592ad2018-04-22 21:20:24 -0700294fn op_before_comment() {
295 let mut tts = TokenStream::from_str("~// comment").unwrap().into_iter();
296 match tts.next().unwrap() {
Alex Crichtonf3888432018-05-16 09:11:05 -0700297 TokenTree::Punct(tt) => {
298 assert_eq!(tt.as_char(), '~');
David Tolnay3a592ad2018-04-22 21:20:24 -0700299 assert_eq!(tt.spacing(), Spacing::Alone);
300 }
301 wrong => panic!("wrong token {:?}", wrong),
302 }
303}
304
305#[test]
David Tolnaya13d1422018-03-31 21:27:48 +0200306fn raw_identifier() {
307 let mut tts = TokenStream::from_str("r#dyn").unwrap().into_iter();
308 match tts.next().unwrap() {
Alex Crichtonf3888432018-05-16 09:11:05 -0700309 TokenTree::Ident(raw) => assert_eq!("r#dyn", raw.to_string()),
David Tolnaya13d1422018-03-31 21:27:48 +0200310 wrong => panic!("wrong token {:?}", wrong),
311 }
312 assert!(tts.next().is_none());
313}
David Tolnay034205f2018-04-22 16:45:28 -0700314
315#[test]
316fn test_debug() {
317 let tts = TokenStream::from_str("[a + 1]").unwrap();
318
319 #[cfg(not(procmacro2_semver_exempt))]
320 let expected = "\
321TokenStream [
322 Group {
323 delimiter: Bracket,
324 stream: TokenStream [
Alex Crichtonf3888432018-05-16 09:11:05 -0700325 Ident {
326 sym: a,
327 raw: false
David Tolnay034205f2018-04-22 16:45:28 -0700328 },
Alex Crichtonf3888432018-05-16 09:11:05 -0700329 Punct {
David Tolnay034205f2018-04-22 16:45:28 -0700330 op: '+',
331 spacing: Alone
332 },
333 Literal {
334 lit: 1
335 }
336 ]
337 }
338]\
339 ";
340
341 #[cfg(procmacro2_semver_exempt)]
342 let expected = "\
343TokenStream [
344 Group {
345 delimiter: Bracket,
346 stream: TokenStream [
Alex Crichtonf3888432018-05-16 09:11:05 -0700347 Ident {
David Tolnay034205f2018-04-22 16:45:28 -0700348 sym: a,
Alex Crichtonf3888432018-05-16 09:11:05 -0700349 span: bytes(2..3),
350 raw: false
David Tolnay034205f2018-04-22 16:45:28 -0700351 },
Alex Crichtonf3888432018-05-16 09:11:05 -0700352 Punct {
David Tolnay034205f2018-04-22 16:45:28 -0700353 op: '+',
354 spacing: Alone,
355 span: bytes(4..5)
356 },
357 Literal {
358 lit: 1,
359 span: bytes(6..7)
360 }
361 ],
362 span: bytes(1..8)
363 }
364]\
365 ";
366
367 assert_eq!(expected, format!("{:#?}", tts));
368}