blob: a3c53ec9d5b4a0d946342a9c5e0afed45802ce7b [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");
116 roundtrip("'static");
David Tolnay8d109342017-12-25 18:24:45 -0500117 roundtrip("'\\u{10__FFFF}'");
118 roundtrip("\"\\u{10_F0FF__}foo\\u{1_0_0_0__}\"");
David Tolnaye5806852017-06-01 12:49:20 -0700119}
120
121#[test]
122fn fail() {
123 fn fail(p: &str) {
Alex Crichtonf3888432018-05-16 09:11:05 -0700124 if let Ok(s) = p.parse::<TokenStream>() {
125 panic!("should have failed to parse: {}\n{:#?}", p, s);
David Tolnaye5806852017-06-01 12:49:20 -0700126 }
127 }
128 fail("1x");
129 fail("1u80");
130 fail("1f320");
131 fail("' static");
David Tolnaya13d1422018-03-31 21:27:48 +0200132 fail("r#1");
133 fail("r#_");
David Tolnaye5806852017-06-01 12:49:20 -0700134}
Nika Layzellf8d5f212017-12-11 14:07:02 -0500135
David Tolnay1ebe3972018-01-02 20:14:20 -0800136#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500137#[test]
138fn span_test() {
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700139 use proc_macro2::TokenTree;
140
Nika Layzellf8d5f212017-12-11 14:07:02 -0500141 fn check_spans(p: &str, mut lines: &[(usize, usize, usize, usize)]) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500142 let ts = p.parse::<TokenStream>().unwrap();
143 check_spans_internal(ts, &mut lines);
144 }
145
David Tolnayb28f38a2018-03-31 22:02:29 +0200146 fn check_spans_internal(ts: TokenStream, lines: &mut &[(usize, usize, usize, usize)]) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500147 for i in ts {
148 if let Some((&(sline, scol, eline, ecol), rest)) = lines.split_first() {
149 *lines = rest;
150
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700151 let start = i.span().start();
Nika Layzellf8d5f212017-12-11 14:07:02 -0500152 assert_eq!(start.line, sline, "sline did not match for {}", i);
153 assert_eq!(start.column, scol, "scol did not match for {}", i);
154
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700155 let end = i.span().end();
Nika Layzellf8d5f212017-12-11 14:07:02 -0500156 assert_eq!(end.line, eline, "eline did not match for {}", i);
157 assert_eq!(end.column, ecol, "ecol did not match for {}", i);
158
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700159 match i {
160 TokenTree::Group(ref g) => {
161 check_spans_internal(g.stream().clone(), lines);
162 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500163 _ => {}
164 }
165 }
166 }
167 }
168
David Tolnayb28f38a2018-03-31 22:02:29 +0200169 check_spans(
170 "\
Nika Layzellf8d5f212017-12-11 14:07:02 -0500171/// This is a document comment
172testing 123
173{
174 testing 234
David Tolnayb28f38a2018-03-31 22:02:29 +0200175}",
176 &[
Alex Crichton1eb96a02018-04-04 13:07:35 -0700177 (1, 0, 1, 30), // #
178 (1, 0, 1, 30), // [ ... ]
179 (1, 0, 1, 30), // doc
180 (1, 0, 1, 30), // =
181 (1, 0, 1, 30), // "This is..."
182 (2, 0, 2, 7), // testing
183 (2, 8, 2, 11), // 123
184 (3, 0, 5, 1), // { ... }
185 (4, 2, 4, 9), // testing
186 (4, 10, 4, 13), // 234
David Tolnayb28f38a2018-03-31 22:02:29 +0200187 ],
188 );
Nika Layzellf8d5f212017-12-11 14:07:02 -0500189}
190
David Tolnay1ebe3972018-01-02 20:14:20 -0800191#[cfg(procmacro2_semver_exempt)]
David Tolnayd66ecf62018-01-02 20:05:42 -0800192#[cfg(not(feature = "nightly"))]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500193#[test]
194fn default_span() {
195 let start = Span::call_site().start();
196 assert_eq!(start.line, 1);
197 assert_eq!(start.column, 0);
198 let end = Span::call_site().end();
199 assert_eq!(end.line, 1);
200 assert_eq!(end.column, 0);
201 let source_file = Span::call_site().source_file();
Nika Layzellfb783e32017-12-30 14:58:27 -0500202 assert_eq!(source_file.path().to_string(), "<unspecified>");
Nika Layzellf8d5f212017-12-11 14:07:02 -0500203 assert!(!source_file.is_real());
204}
205
David Tolnay1ebe3972018-01-02 20:14:20 -0800206#[cfg(procmacro2_semver_exempt)]
Nika Layzellddea1562017-12-11 14:25:35 -0500207#[test]
208fn span_join() {
David Tolnayb28f38a2018-03-31 22:02:29 +0200209 let source1 = "aaa\nbbb"
210 .parse::<TokenStream>()
211 .unwrap()
212 .into_iter()
213 .collect::<Vec<_>>();
214 let source2 = "ccc\nddd"
215 .parse::<TokenStream>()
216 .unwrap()
217 .into_iter()
218 .collect::<Vec<_>>();
Nika Layzellddea1562017-12-11 14:25:35 -0500219
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700220 assert!(source1[0].span().source_file() != source2[0].span().source_file());
David Tolnayb28f38a2018-03-31 22:02:29 +0200221 assert_eq!(
222 source1[0].span().source_file(),
223 source1[1].span().source_file()
224 );
Nika Layzellddea1562017-12-11 14:25:35 -0500225
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700226 let joined1 = source1[0].span().join(source1[1].span());
227 let joined2 = source1[0].span().join(source2[0].span());
Nika Layzellddea1562017-12-11 14:25:35 -0500228 assert!(joined1.is_some());
229 assert!(joined2.is_none());
230
231 let start = joined1.unwrap().start();
232 let end = joined1.unwrap().end();
233 assert_eq!(start.line, 1);
234 assert_eq!(start.column, 0);
235 assert_eq!(end.line, 2);
236 assert_eq!(end.column, 3);
237
David Tolnayb28f38a2018-03-31 22:02:29 +0200238 assert_eq!(
239 joined1.unwrap().source_file(),
240 source1[0].span().source_file()
241 );
Nika Layzellddea1562017-12-11 14:25:35 -0500242}
Alex Crichton8c030332018-01-16 08:07:36 -0800243
244#[test]
245fn no_panic() {
246 let s = str::from_utf8(b"b\'\xc2\x86 \x00\x00\x00^\"").unwrap();
247 assert!(s.parse::<proc_macro2::TokenStream>().is_err());
248}
249
Alex Crichtonf7df57c2018-01-21 21:05:11 -0800250#[test]
David Tolnay639e4ba2018-03-31 21:10:55 +0200251fn tricky_doc_comment() {
Alex Crichtonf7df57c2018-01-21 21:05:11 -0800252 let stream = "/**/".parse::<proc_macro2::TokenStream>().unwrap();
253 let tokens = stream.into_iter().collect::<Vec<_>>();
254 assert!(tokens.is_empty(), "not empty -- {:?}", tokens);
Alex Crichtond7904e52018-01-23 11:08:45 -0800255
256 let stream = "/// doc".parse::<proc_macro2::TokenStream>().unwrap();
257 let tokens = stream.into_iter().collect::<Vec<_>>();
Alex Crichton1eb96a02018-04-04 13:07:35 -0700258 assert!(tokens.len() == 2, "not length 2 -- {:?}", tokens);
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700259 match tokens[0] {
Alex Crichtonf3888432018-05-16 09:11:05 -0700260 proc_macro2::TokenTree::Punct(ref tt) => assert_eq!(tt.as_char(), '#'),
Alex Crichtond7904e52018-01-23 11:08:45 -0800261 _ => panic!("wrong token {:?}", tokens[0]),
262 }
Alex Crichton1eb96a02018-04-04 13:07:35 -0700263 let mut tokens = match tokens[1] {
264 proc_macro2::TokenTree::Group(ref tt) => {
265 assert_eq!(tt.delimiter(), proc_macro2::Delimiter::Bracket);
266 tt.stream().into_iter()
267 }
268 _ => panic!("wrong token {:?}", tokens[0]),
269 };
270
271 match tokens.next().unwrap() {
Alex Crichtonf3888432018-05-16 09:11:05 -0700272 proc_macro2::TokenTree::Ident(ref tt) => assert_eq!(tt.to_string(), "doc"),
Alex Crichton1eb96a02018-04-04 13:07:35 -0700273 t => panic!("wrong token {:?}", t),
274 }
275 match tokens.next().unwrap() {
Alex Crichtonf3888432018-05-16 09:11:05 -0700276 proc_macro2::TokenTree::Punct(ref tt) => assert_eq!(tt.as_char(), '='),
Alex Crichton1eb96a02018-04-04 13:07:35 -0700277 t => panic!("wrong token {:?}", t),
278 }
279 match tokens.next().unwrap() {
280 proc_macro2::TokenTree::Literal(ref tt) => {
281 assert_eq!(tt.to_string(), "\" doc\"");
282 }
283 t => panic!("wrong token {:?}", t),
284 }
285 assert!(tokens.next().is_none());
286
287 let stream = "//! doc".parse::<proc_macro2::TokenStream>().unwrap();
288 let tokens = stream.into_iter().collect::<Vec<_>>();
289 assert!(tokens.len() == 3, "not length 3 -- {:?}", tokens);
Alex Crichtonf7df57c2018-01-21 21:05:11 -0800290}
291
David Tolnaya13d1422018-03-31 21:27:48 +0200292#[test]
David Tolnay3a592ad2018-04-22 21:20:24 -0700293fn op_before_comment() {
294 let mut tts = TokenStream::from_str("~// comment").unwrap().into_iter();
295 match tts.next().unwrap() {
Alex Crichtonf3888432018-05-16 09:11:05 -0700296 TokenTree::Punct(tt) => {
297 assert_eq!(tt.as_char(), '~');
David Tolnay3a592ad2018-04-22 21:20:24 -0700298 assert_eq!(tt.spacing(), Spacing::Alone);
299 }
300 wrong => panic!("wrong token {:?}", wrong),
301 }
302}
303
304#[test]
David Tolnaya13d1422018-03-31 21:27:48 +0200305fn raw_identifier() {
306 let mut tts = TokenStream::from_str("r#dyn").unwrap().into_iter();
307 match tts.next().unwrap() {
Alex Crichtonf3888432018-05-16 09:11:05 -0700308 TokenTree::Ident(raw) => assert_eq!("r#dyn", raw.to_string()),
David Tolnaya13d1422018-03-31 21:27:48 +0200309 wrong => panic!("wrong token {:?}", wrong),
310 }
311 assert!(tts.next().is_none());
312}
David Tolnay034205f2018-04-22 16:45:28 -0700313
314#[test]
315fn test_debug() {
316 let tts = TokenStream::from_str("[a + 1]").unwrap();
317
318 #[cfg(not(procmacro2_semver_exempt))]
319 let expected = "\
320TokenStream [
321 Group {
322 delimiter: Bracket,
323 stream: TokenStream [
Alex Crichtonf3888432018-05-16 09:11:05 -0700324 Ident {
325 sym: a,
326 raw: false
David Tolnay034205f2018-04-22 16:45:28 -0700327 },
Alex Crichtonf3888432018-05-16 09:11:05 -0700328 Punct {
David Tolnay034205f2018-04-22 16:45:28 -0700329 op: '+',
330 spacing: Alone
331 },
332 Literal {
333 lit: 1
334 }
335 ]
336 }
337]\
338 ";
339
340 #[cfg(procmacro2_semver_exempt)]
341 let expected = "\
342TokenStream [
343 Group {
344 delimiter: Bracket,
345 stream: TokenStream [
Alex Crichtonf3888432018-05-16 09:11:05 -0700346 Ident {
David Tolnay034205f2018-04-22 16:45:28 -0700347 sym: a,
Alex Crichtonf3888432018-05-16 09:11:05 -0700348 span: bytes(2..3),
349 raw: false
David Tolnay034205f2018-04-22 16:45:28 -0700350 },
Alex Crichtonf3888432018-05-16 09:11:05 -0700351 Punct {
David Tolnay034205f2018-04-22 16:45:28 -0700352 op: '+',
353 spacing: Alone,
354 span: bytes(4..5)
355 },
356 Literal {
357 lit: 1,
358 span: bytes(6..7)
359 }
360 ],
361 span: bytes(1..8)
362 }
363]\
364 ";
365
366 assert_eq!(expected, format!("{:#?}", tts));
367}