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