1 #![allow(
2 clippy::disallowed_names,
3 clippy::let_underscore_untyped,
4 clippy::shadow_unrelated,
5 clippy::unseparated_literal_suffix,
6 clippy::used_underscore_binding
7 )]
8
9 extern crate proc_macro;
10
11 use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream};
12 use quote::{format_ident, quote, quote_spanned, TokenStreamExt};
13 use std::borrow::Cow;
14 use std::collections::BTreeSet;
15 use std::ffi::{CStr, CString};
16
17 struct X;
18
19 impl quote::ToTokens for X {
to_tokens(&self, tokens: &mut TokenStream)20 fn to_tokens(&self, tokens: &mut TokenStream) {
21 tokens.append(Ident::new("X", Span::call_site()));
22 }
23 }
24
25 #[test]
test_quote_impl()26 fn test_quote_impl() {
27 let tokens = quote! {
28 impl<'a, T: ToTokens> ToTokens for &'a T {
29 fn to_tokens(&self, tokens: &mut TokenStream) {
30 (**self).to_tokens(tokens)
31 }
32 }
33 };
34
35 let expected = concat!(
36 "impl < 'a , T : ToTokens > ToTokens for & 'a T { ",
37 "fn to_tokens (& self , tokens : & mut TokenStream) { ",
38 "(* * self) . to_tokens (tokens) ",
39 "} ",
40 "}"
41 );
42
43 assert_eq!(expected, tokens.to_string());
44 }
45
46 #[test]
test_quote_spanned_impl()47 fn test_quote_spanned_impl() {
48 let span = Span::call_site();
49 let tokens = quote_spanned! {span=>
50 impl<'a, T: ToTokens> ToTokens for &'a T {
51 fn to_tokens(&self, tokens: &mut TokenStream) {
52 (**self).to_tokens(tokens)
53 }
54 }
55 };
56
57 let expected = concat!(
58 "impl < 'a , T : ToTokens > ToTokens for & 'a T { ",
59 "fn to_tokens (& self , tokens : & mut TokenStream) { ",
60 "(* * self) . to_tokens (tokens) ",
61 "} ",
62 "}"
63 );
64
65 assert_eq!(expected, tokens.to_string());
66 }
67
68 #[test]
test_substitution()69 fn test_substitution() {
70 let x = X;
71 let tokens = quote!(#x <#x> (#x) [#x] {#x});
72
73 let expected = "X < X > (X) [X] { X }";
74
75 assert_eq!(expected, tokens.to_string());
76 }
77
78 #[test]
test_iter()79 fn test_iter() {
80 let primes = &[X, X, X, X];
81
82 assert_eq!("X X X X", quote!(#(#primes)*).to_string());
83
84 assert_eq!("X , X , X , X ,", quote!(#(#primes,)*).to_string());
85
86 assert_eq!("X , X , X , X", quote!(#(#primes),*).to_string());
87 }
88
89 #[test]
test_array()90 fn test_array() {
91 let array: [u8; 40] = [0; 40];
92 let _ = quote!(#(#array #array)*);
93
94 let ref_array: &[u8; 40] = &[0; 40];
95 let _ = quote!(#(#ref_array #ref_array)*);
96
97 let ref_slice: &[u8] = &[0; 40];
98 let _ = quote!(#(#ref_slice #ref_slice)*);
99
100 let array: [X; 2] = [X, X]; // !Copy
101 let _ = quote!(#(#array #array)*);
102
103 let ref_array: &[X; 2] = &[X, X];
104 let _ = quote!(#(#ref_array #ref_array)*);
105
106 let ref_slice: &[X] = &[X, X];
107 let _ = quote!(#(#ref_slice #ref_slice)*);
108 }
109
110 #[test]
test_advanced()111 fn test_advanced() {
112 let generics = quote!( <'a, T> );
113
114 let where_clause = quote!( where T: Serialize );
115
116 let field_ty = quote!(String);
117
118 let item_ty = quote!(Cow<'a, str>);
119
120 let path = quote!(SomeTrait::serialize_with);
121
122 let value = quote!(self.x);
123
124 let tokens = quote! {
125 struct SerializeWith #generics #where_clause {
126 value: &'a #field_ty,
127 phantom: ::std::marker::PhantomData<#item_ty>,
128 }
129
130 impl #generics ::serde::Serialize for SerializeWith #generics #where_clause {
131 fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
132 where S: ::serde::Serializer
133 {
134 #path(self.value, s)
135 }
136 }
137
138 SerializeWith {
139 value: #value,
140 phantom: ::std::marker::PhantomData::<#item_ty>,
141 }
142 };
143
144 let expected = concat!(
145 "struct SerializeWith < 'a , T > where T : Serialize { ",
146 "value : & 'a String , ",
147 "phantom : :: std :: marker :: PhantomData < Cow < 'a , str > > , ",
148 "} ",
149 "impl < 'a , T > :: serde :: Serialize for SerializeWith < 'a , T > where T : Serialize { ",
150 "fn serialize < S > (& self , s : & mut S) -> Result < () , S :: Error > ",
151 "where S : :: serde :: Serializer ",
152 "{ ",
153 "SomeTrait :: serialize_with (self . value , s) ",
154 "} ",
155 "} ",
156 "SerializeWith { ",
157 "value : self . x , ",
158 "phantom : :: std :: marker :: PhantomData :: < Cow < 'a , str > > , ",
159 "}"
160 );
161
162 assert_eq!(expected, tokens.to_string());
163 }
164
165 #[test]
test_integer()166 fn test_integer() {
167 let ii8 = -1i8;
168 let ii16 = -1i16;
169 let ii32 = -1i32;
170 let ii64 = -1i64;
171 let ii128 = -1i128;
172 let iisize = -1isize;
173 let uu8 = 1u8;
174 let uu16 = 1u16;
175 let uu32 = 1u32;
176 let uu64 = 1u64;
177 let uu128 = 1u128;
178 let uusize = 1usize;
179
180 let tokens = quote! {
181 1 1i32 1u256
182 #ii8 #ii16 #ii32 #ii64 #ii128 #iisize
183 #uu8 #uu16 #uu32 #uu64 #uu128 #uusize
184 };
185 let expected =
186 "1 1i32 1u256 - 1i8 - 1i16 - 1i32 - 1i64 - 1i128 - 1isize 1u8 1u16 1u32 1u64 1u128 1usize";
187 assert_eq!(expected, tokens.to_string());
188 }
189
190 #[test]
test_floating()191 fn test_floating() {
192 let e32 = 2.345f32;
193
194 let e64 = 2.345f64;
195
196 let tokens = quote! {
197 #e32
198 #e64
199 };
200 let expected = concat!("2.345f32 2.345f64");
201 assert_eq!(expected, tokens.to_string());
202 }
203
204 #[test]
test_char()205 fn test_char() {
206 let zero = '\u{1}';
207 let pound = '#';
208 let quote = '"';
209 let apost = '\'';
210 let newline = '\n';
211 let heart = '\u{2764}';
212
213 let tokens = quote! {
214 #zero #pound #quote #apost #newline #heart
215 };
216 let expected = "'\\u{1}' '#' '\"' '\\'' '\\n' '\u{2764}'";
217 assert_eq!(expected, tokens.to_string());
218 }
219
220 #[test]
test_str()221 fn test_str() {
222 let s = "\u{1} a 'b \" c";
223 let tokens = quote!(#s);
224 let expected = "\"\\u{1} a 'b \\\" c\"";
225 assert_eq!(expected, tokens.to_string());
226 }
227
228 #[test]
test_string()229 fn test_string() {
230 let s = "\u{1} a 'b \" c".to_string();
231 let tokens = quote!(#s);
232 let expected = "\"\\u{1} a 'b \\\" c\"";
233 assert_eq!(expected, tokens.to_string());
234 }
235
236 #[test]
test_c_str()237 fn test_c_str() {
238 let s = CStr::from_bytes_with_nul(b"\x01 a 'b \" c\0").unwrap();
239 let tokens = quote!(#s);
240 let expected = "c\"\\u{1} a 'b \\\" c\"";
241 assert_eq!(expected, tokens.to_string());
242 }
243
244 #[test]
test_c_string()245 fn test_c_string() {
246 let s = CString::new(&b"\x01 a 'b \" c"[..]).unwrap();
247 let tokens = quote!(#s);
248 let expected = "c\"\\u{1} a 'b \\\" c\"";
249 assert_eq!(expected, tokens.to_string());
250 }
251
252 #[test]
test_interpolated_literal()253 fn test_interpolated_literal() {
254 macro_rules! m {
255 ($literal:literal) => {
256 quote!($literal)
257 };
258 }
259
260 let tokens = m!(1);
261 let expected = "1";
262 assert_eq!(expected, tokens.to_string());
263
264 let tokens = m!(-1);
265 let expected = "- 1";
266 assert_eq!(expected, tokens.to_string());
267
268 let tokens = m!(true);
269 let expected = "true";
270 assert_eq!(expected, tokens.to_string());
271
272 let tokens = m!(-true);
273 let expected = "- true";
274 assert_eq!(expected, tokens.to_string());
275 }
276
277 #[test]
test_ident()278 fn test_ident() {
279 let foo = Ident::new("Foo", Span::call_site());
280 let bar = Ident::new(&format!("Bar{}", 7), Span::call_site());
281 let tokens = quote!(struct #foo; enum #bar {});
282 let expected = "struct Foo ; enum Bar7 { }";
283 assert_eq!(expected, tokens.to_string());
284 }
285
286 #[test]
test_underscore()287 fn test_underscore() {
288 let tokens = quote!(let _;);
289 let expected = "let _ ;";
290 assert_eq!(expected, tokens.to_string());
291 }
292
293 #[test]
test_duplicate()294 fn test_duplicate() {
295 let ch = 'x';
296
297 let tokens = quote!(#ch #ch);
298
299 let expected = "'x' 'x'";
300 assert_eq!(expected, tokens.to_string());
301 }
302
303 #[test]
test_fancy_repetition()304 fn test_fancy_repetition() {
305 let foo = vec!["a", "b"];
306 let bar = vec![true, false];
307
308 let tokens = quote! {
309 #(#foo: #bar),*
310 };
311
312 let expected = r#""a" : true , "b" : false"#;
313 assert_eq!(expected, tokens.to_string());
314 }
315
316 #[test]
test_nested_fancy_repetition()317 fn test_nested_fancy_repetition() {
318 let nested = vec![vec!['a', 'b', 'c'], vec!['x', 'y', 'z']];
319
320 let tokens = quote! {
321 #(
322 #(#nested)*
323 ),*
324 };
325
326 let expected = "'a' 'b' 'c' , 'x' 'y' 'z'";
327 assert_eq!(expected, tokens.to_string());
328 }
329
330 #[test]
test_duplicate_name_repetition()331 fn test_duplicate_name_repetition() {
332 let foo = &["a", "b"];
333
334 let tokens = quote! {
335 #(#foo: #foo),*
336 #(#foo: #foo),*
337 };
338
339 let expected = r#""a" : "a" , "b" : "b" "a" : "a" , "b" : "b""#;
340 assert_eq!(expected, tokens.to_string());
341 }
342
343 #[test]
test_duplicate_name_repetition_no_copy()344 fn test_duplicate_name_repetition_no_copy() {
345 let foo = vec!["a".to_owned(), "b".to_owned()];
346
347 let tokens = quote! {
348 #(#foo: #foo),*
349 };
350
351 let expected = r#""a" : "a" , "b" : "b""#;
352 assert_eq!(expected, tokens.to_string());
353 }
354
355 #[test]
test_btreeset_repetition()356 fn test_btreeset_repetition() {
357 let mut set = BTreeSet::new();
358 set.insert("a".to_owned());
359 set.insert("b".to_owned());
360
361 let tokens = quote! {
362 #(#set: #set),*
363 };
364
365 let expected = r#""a" : "a" , "b" : "b""#;
366 assert_eq!(expected, tokens.to_string());
367 }
368
369 #[test]
test_variable_name_conflict()370 fn test_variable_name_conflict() {
371 // The implementation of `#(...),*` uses the variable `_i` but it should be
372 // fine, if a little confusing when debugging.
373 let _i = vec!['a', 'b'];
374 let tokens = quote! { #(#_i),* };
375 let expected = "'a' , 'b'";
376 assert_eq!(expected, tokens.to_string());
377 }
378
379 #[test]
test_nonrep_in_repetition()380 fn test_nonrep_in_repetition() {
381 let rep = vec!["a", "b"];
382 let nonrep = "c";
383
384 let tokens = quote! {
385 #(#rep #rep : #nonrep #nonrep),*
386 };
387
388 let expected = r#""a" "a" : "c" "c" , "b" "b" : "c" "c""#;
389 assert_eq!(expected, tokens.to_string());
390 }
391
392 #[test]
test_empty_quote()393 fn test_empty_quote() {
394 let tokens = quote!();
395 assert_eq!("", tokens.to_string());
396 }
397
398 #[test]
test_box_str()399 fn test_box_str() {
400 let b = "str".to_owned().into_boxed_str();
401 let tokens = quote! { #b };
402 assert_eq!("\"str\"", tokens.to_string());
403 }
404
405 #[test]
test_cow()406 fn test_cow() {
407 let owned: Cow<Ident> = Cow::Owned(Ident::new("owned", Span::call_site()));
408
409 let ident = Ident::new("borrowed", Span::call_site());
410 let borrowed = Cow::Borrowed(&ident);
411
412 let tokens = quote! { #owned #borrowed };
413 assert_eq!("owned borrowed", tokens.to_string());
414 }
415
416 #[test]
test_closure()417 fn test_closure() {
418 fn field_i(i: usize) -> Ident {
419 format_ident!("__field{}", i)
420 }
421
422 let fields = (0usize..3)
423 .map(field_i as fn(_) -> _)
424 .map(|var| quote! { #var });
425
426 let tokens = quote! { #(#fields)* };
427 assert_eq!("__field0 __field1 __field2", tokens.to_string());
428 }
429
430 #[test]
test_append_tokens()431 fn test_append_tokens() {
432 let mut a = quote!(a);
433 let b = quote!(b);
434 a.append_all(b);
435 assert_eq!("a b", a.to_string());
436 }
437
438 #[test]
test_format_ident()439 fn test_format_ident() {
440 let id0 = format_ident!("Aa");
441 let id1 = format_ident!("Hello{x}", x = id0);
442 let id2 = format_ident!("Hello{x}", x = 5usize);
443 let id3 = format_ident!("Hello{}_{x}", id0, x = 10usize);
444 let id4 = format_ident!("Aa", span = Span::call_site());
445 let id5 = format_ident!("Hello{}", Cow::Borrowed("World"));
446
447 assert_eq!(id0, "Aa");
448 assert_eq!(id1, "HelloAa");
449 assert_eq!(id2, "Hello5");
450 assert_eq!(id3, "HelloAa_10");
451 assert_eq!(id4, "Aa");
452 assert_eq!(id5, "HelloWorld");
453 }
454
455 #[test]
test_format_ident_strip_raw()456 fn test_format_ident_strip_raw() {
457 let id = format_ident!("r#struct");
458 let my_id = format_ident!("MyId{}", id);
459 let raw_my_id = format_ident!("r#MyId{}", id);
460
461 assert_eq!(id, "r#struct");
462 assert_eq!(my_id, "MyIdstruct");
463 assert_eq!(raw_my_id, "r#MyIdstruct");
464 }
465
466 #[test]
test_outer_line_comment()467 fn test_outer_line_comment() {
468 let tokens = quote! {
469 /// doc
470 };
471 let expected = "# [doc = r\" doc\"]";
472 assert_eq!(expected, tokens.to_string());
473 }
474
475 #[test]
test_inner_line_comment()476 fn test_inner_line_comment() {
477 let tokens = quote! {
478 //! doc
479 };
480 let expected = "# ! [doc = r\" doc\"]";
481 assert_eq!(expected, tokens.to_string());
482 }
483
484 #[test]
test_outer_block_comment()485 fn test_outer_block_comment() {
486 let tokens = quote! {
487 /** doc */
488 };
489 let expected = "# [doc = r\" doc \"]";
490 assert_eq!(expected, tokens.to_string());
491 }
492
493 #[test]
test_inner_block_comment()494 fn test_inner_block_comment() {
495 let tokens = quote! {
496 /*! doc */
497 };
498 let expected = "# ! [doc = r\" doc \"]";
499 assert_eq!(expected, tokens.to_string());
500 }
501
502 #[test]
test_outer_attr()503 fn test_outer_attr() {
504 let tokens = quote! {
505 #[inline]
506 };
507 let expected = "# [inline]";
508 assert_eq!(expected, tokens.to_string());
509 }
510
511 #[test]
test_inner_attr()512 fn test_inner_attr() {
513 let tokens = quote! {
514 #![no_std]
515 };
516 let expected = "# ! [no_std]";
517 assert_eq!(expected, tokens.to_string());
518 }
519
520 // https://github.com/dtolnay/quote/issues/130
521 #[test]
test_star_after_repetition()522 fn test_star_after_repetition() {
523 let c = vec!['0', '1'];
524 let tokens = quote! {
525 #(
526 f(#c);
527 )*
528 *out = None;
529 };
530 let expected = "f ('0') ; f ('1') ; * out = None ;";
531 assert_eq!(expected, tokens.to_string());
532 }
533
534 #[test]
test_quote_raw_id()535 fn test_quote_raw_id() {
536 let id = quote!(r#raw_id);
537 assert_eq!(id.to_string(), "r#raw_id");
538 }
539
540 #[test]
test_type_inference_for_span()541 fn test_type_inference_for_span() {
542 trait CallSite {
543 fn get() -> Self;
544 }
545
546 impl CallSite for Span {
547 fn get() -> Self {
548 Span::call_site()
549 }
550 }
551
552 let span = Span::call_site();
553 let _ = quote_spanned!(span=> ...);
554
555 let delim_span = Group::new(Delimiter::Parenthesis, TokenStream::new()).delim_span();
556 let _ = quote_spanned!(delim_span=> ...);
557
558 let inferred = CallSite::get();
559 let _ = quote_spanned!(inferred=> ...);
560
561 if false {
562 let proc_macro_span = proc_macro::Span::call_site();
563 let _ = quote_spanned!(proc_macro_span.into()=> ...);
564 }
565 }
566