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