xref: /third_party/rust/crates/quote/tests/test.rs (revision e31f0860)
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
9extern crate proc_macro;
10
11use std::borrow::Cow;
12use std::collections::BTreeSet;
13
14use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream};
15use quote::{format_ident, quote, quote_spanned, TokenStreamExt};
16
17struct X;
18
19impl quote::ToTokens for X {
20    fn to_tokens(&self, tokens: &mut TokenStream) {
21        tokens.append(Ident::new("X", Span::call_site()));
22    }
23}
24
25#[test]
26fn 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]
47fn 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]
69fn 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]
79fn 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]
90fn 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]
111fn 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]
166fn 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]
191fn 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]
205fn 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]
221fn 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]
229fn 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]
237fn test_interpolated_literal() {
238    macro_rules! m {
239        ($literal:literal) => {
240            quote!($literal)
241        };
242    }
243
244    let tokens = m!(1);
245    let expected = "1";
246    assert_eq!(expected, tokens.to_string());
247
248    let tokens = m!(-1);
249    let expected = "- 1";
250    assert_eq!(expected, tokens.to_string());
251
252    let tokens = m!(true);
253    let expected = "true";
254    assert_eq!(expected, tokens.to_string());
255
256    let tokens = m!(-true);
257    let expected = "- true";
258    assert_eq!(expected, tokens.to_string());
259}
260
261#[test]
262fn test_ident() {
263    let foo = Ident::new("Foo", Span::call_site());
264    let bar = Ident::new(&format!("Bar{}", 7), Span::call_site());
265    let tokens = quote!(struct #foo; enum #bar {});
266    let expected = "struct Foo ; enum Bar7 { }";
267    assert_eq!(expected, tokens.to_string());
268}
269
270#[test]
271fn test_underscore() {
272    let tokens = quote!(let _;);
273    let expected = "let _ ;";
274    assert_eq!(expected, tokens.to_string());
275}
276
277#[test]
278fn test_duplicate() {
279    let ch = 'x';
280
281    let tokens = quote!(#ch #ch);
282
283    let expected = "'x' 'x'";
284    assert_eq!(expected, tokens.to_string());
285}
286
287#[test]
288fn test_fancy_repetition() {
289    let foo = vec!["a", "b"];
290    let bar = vec![true, false];
291
292    let tokens = quote! {
293        #(#foo: #bar),*
294    };
295
296    let expected = r#""a" : true , "b" : false"#;
297    assert_eq!(expected, tokens.to_string());
298}
299
300#[test]
301fn test_nested_fancy_repetition() {
302    let nested = vec![vec!['a', 'b', 'c'], vec!['x', 'y', 'z']];
303
304    let tokens = quote! {
305        #(
306            #(#nested)*
307        ),*
308    };
309
310    let expected = "'a' 'b' 'c' , 'x' 'y' 'z'";
311    assert_eq!(expected, tokens.to_string());
312}
313
314#[test]
315fn test_duplicate_name_repetition() {
316    let foo = &["a", "b"];
317
318    let tokens = quote! {
319        #(#foo: #foo),*
320        #(#foo: #foo),*
321    };
322
323    let expected = r#""a" : "a" , "b" : "b" "a" : "a" , "b" : "b""#;
324    assert_eq!(expected, tokens.to_string());
325}
326
327#[test]
328fn test_duplicate_name_repetition_no_copy() {
329    let foo = vec!["a".to_owned(), "b".to_owned()];
330
331    let tokens = quote! {
332        #(#foo: #foo),*
333    };
334
335    let expected = r#""a" : "a" , "b" : "b""#;
336    assert_eq!(expected, tokens.to_string());
337}
338
339#[test]
340fn test_btreeset_repetition() {
341    let mut set = BTreeSet::new();
342    set.insert("a".to_owned());
343    set.insert("b".to_owned());
344
345    let tokens = quote! {
346        #(#set: #set),*
347    };
348
349    let expected = r#""a" : "a" , "b" : "b""#;
350    assert_eq!(expected, tokens.to_string());
351}
352
353#[test]
354fn test_variable_name_conflict() {
355    // The implementation of `#(...),*` uses the variable `_i` but it should be
356    // fine, if a little confusing when debugging.
357    let _i = vec!['a', 'b'];
358    let tokens = quote! { #(#_i),* };
359    let expected = "'a' , 'b'";
360    assert_eq!(expected, tokens.to_string());
361}
362
363#[test]
364fn test_nonrep_in_repetition() {
365    let rep = vec!["a", "b"];
366    let nonrep = "c";
367
368    let tokens = quote! {
369        #(#rep #rep : #nonrep #nonrep),*
370    };
371
372    let expected = r#""a" "a" : "c" "c" , "b" "b" : "c" "c""#;
373    assert_eq!(expected, tokens.to_string());
374}
375
376#[test]
377fn test_empty_quote() {
378    let tokens = quote!();
379    assert_eq!("", tokens.to_string());
380}
381
382#[test]
383fn test_box_str() {
384    let b = "str".to_owned().into_boxed_str();
385    let tokens = quote! { #b };
386    assert_eq!("\"str\"", tokens.to_string());
387}
388
389#[test]
390fn test_cow() {
391    let owned: Cow<Ident> = Cow::Owned(Ident::new("owned", Span::call_site()));
392
393    let ident = Ident::new("borrowed", Span::call_site());
394    let borrowed = Cow::Borrowed(&ident);
395
396    let tokens = quote! { #owned #borrowed };
397    assert_eq!("owned borrowed", tokens.to_string());
398}
399
400#[test]
401fn test_closure() {
402    fn field_i(i: usize) -> Ident {
403        format_ident!("__field{}", i)
404    }
405
406    let fields = (0usize..3)
407        .map(field_i as fn(_) -> _)
408        .map(|var| quote! { #var });
409
410    let tokens = quote! { #(#fields)* };
411    assert_eq!("__field0 __field1 __field2", tokens.to_string());
412}
413
414#[test]
415fn test_append_tokens() {
416    let mut a = quote!(a);
417    let b = quote!(b);
418    a.append_all(b);
419    assert_eq!("a b", a.to_string());
420}
421
422#[test]
423fn test_format_ident() {
424    let id0 = format_ident!("Aa");
425    let id1 = format_ident!("Hello{x}", x = id0);
426    let id2 = format_ident!("Hello{x}", x = 5usize);
427    let id3 = format_ident!("Hello{}_{x}", id0, x = 10usize);
428    let id4 = format_ident!("Aa", span = Span::call_site());
429    let id5 = format_ident!("Hello{}", Cow::Borrowed("World"));
430
431    assert_eq!(id0, "Aa");
432    assert_eq!(id1, "HelloAa");
433    assert_eq!(id2, "Hello5");
434    assert_eq!(id3, "HelloAa_10");
435    assert_eq!(id4, "Aa");
436    assert_eq!(id5, "HelloWorld");
437}
438
439#[test]
440fn test_format_ident_strip_raw() {
441    let id = format_ident!("r#struct");
442    let my_id = format_ident!("MyId{}", id);
443    let raw_my_id = format_ident!("r#MyId{}", id);
444
445    assert_eq!(id, "r#struct");
446    assert_eq!(my_id, "MyIdstruct");
447    assert_eq!(raw_my_id, "r#MyIdstruct");
448}
449
450#[test]
451fn test_outer_line_comment() {
452    let tokens = quote! {
453        /// doc
454    };
455    let expected = "# [doc = r\" doc\"]";
456    assert_eq!(expected, tokens.to_string());
457}
458
459#[test]
460fn test_inner_line_comment() {
461    let tokens = quote! {
462        //! doc
463    };
464    let expected = "# ! [doc = r\" doc\"]";
465    assert_eq!(expected, tokens.to_string());
466}
467
468#[test]
469fn test_outer_block_comment() {
470    let tokens = quote! {
471        /** doc */
472    };
473    let expected = "# [doc = r\" doc \"]";
474    assert_eq!(expected, tokens.to_string());
475}
476
477#[test]
478fn test_inner_block_comment() {
479    let tokens = quote! {
480        /*! doc */
481    };
482    let expected = "# ! [doc = r\" doc \"]";
483    assert_eq!(expected, tokens.to_string());
484}
485
486#[test]
487fn test_outer_attr() {
488    let tokens = quote! {
489        #[inline]
490    };
491    let expected = "# [inline]";
492    assert_eq!(expected, tokens.to_string());
493}
494
495#[test]
496fn test_inner_attr() {
497    let tokens = quote! {
498        #![no_std]
499    };
500    let expected = "# ! [no_std]";
501    assert_eq!(expected, tokens.to_string());
502}
503
504// https://github.com/dtolnay/quote/issues/130
505#[test]
506fn test_star_after_repetition() {
507    let c = vec!['0', '1'];
508    let tokens = quote! {
509        #(
510            f(#c);
511        )*
512        *out = None;
513    };
514    let expected = "f ('0') ; f ('1') ; * out = None ;";
515    assert_eq!(expected, tokens.to_string());
516}
517
518#[test]
519fn test_quote_raw_id() {
520    let id = quote!(r#raw_id);
521    assert_eq!(id.to_string(), "r#raw_id");
522}
523
524#[test]
525fn test_type_inference_for_span() {
526    trait CallSite {
527        fn get() -> Self;
528    }
529
530    impl CallSite for Span {
531        fn get() -> Self {
532            Span::call_site()
533        }
534    }
535
536    let span = Span::call_site();
537    let _ = quote_spanned!(span=> ...);
538
539    let delim_span = Group::new(Delimiter::Parenthesis, TokenStream::new()).delim_span();
540    let _ = quote_spanned!(delim_span=> ...);
541
542    let inferred = CallSite::get();
543    let _ = quote_spanned!(inferred=> ...);
544
545    if false {
546        let proc_macro_span = proc_macro::Span::call_site();
547        let _ = quote_spanned!(proc_macro_span.into()=> ...);
548    }
549}
550