use template_quote::quote;
#[test]
fn empty_inline_group_expands_to_nothing() {
let tokens = quote! { #{} };
assert_eq!(tokens.to_string(), "");
}
#[test]
fn empty_inline_group_between_tokens() {
let tokens = quote! { a #{} b };
assert_eq!(tokens.to_string(), "a b");
}
#[test]
fn nonempty_inline_group_still_works() {
let x = 5usize;
let tokens = quote! { #{ x + 1 } };
assert_eq!(tokens.to_string(), "6usize");
}
#[test]
fn boundary_minus_does_not_form_arrow() {
let x = quote!(> z); let s = quote!( a -#x ).to_string();
assert!(!s.contains("->"), "`-` fused with `>` into `->`: {s}");
}
#[test]
fn boundary_colon_does_not_form_triple_colon() {
let p = quote!(::std::vec::Vec); let s = quote!( let x:#p = y; ).to_string();
assert!(!s.contains(":::"), "`:` fused into `:::`: {s}");
}
#[test]
fn boundary_plus_does_not_form_double_plus() {
let x = quote!(+ y); let s = quote!( a +#x ).to_string();
assert!(!s.contains("++"), "`+` fused into `++`: {s}");
}
#[test]
fn boundary_minus_with_number_still_negates() {
let v = 1i32;
assert_eq!(quote!( -#v ).to_string(), "- 1i32");
}
#[test]
fn interp_inside_group_in_for_header() {
let v = [1, 2, 3];
let tokens = quote! {
#(for i in (#v).iter()) { #i }
};
assert_eq!(tokens.to_string(), "1i32 2i32 3i32");
}
#[test]
fn interp_inside_group_in_if_condition() {
let v = [1, 2, 3];
let tokens = quote! {
#(if (#v).len() == 3) { yes }
};
assert_eq!(tokens.to_string(), "yes");
}
#[test]
fn interp_inside_group_in_inline_block() {
let v = [10, 20];
let tokens = quote! {
#(for _i in 0..2) { #{ (#v).len() } }
};
assert_eq!(tokens.to_string(), "2usize 2usize");
}
#[test]
#[allow(unused_mut)] fn pattern_mut_ref_modifiers() {
let tokens = quote! {
#(let (mut a, ref b) = (1i32, 2i32)) { #a #b }
};
assert_eq!(tokens.to_string(), "1i32 2i32");
}
#[test]
fn pattern_leading_absolute_path() {
let tokens = quote! {
#(if let ::core::option::Option::Some(x) = Some(7i32)) { #x }
};
assert_eq!(tokens.to_string(), "7i32");
}
#[test]
fn pattern_nontrailing_rest_slice() {
let arr = [1i32, 2, 3, 4];
let tokens = quote! {
#(let [a, .., b] = arr) { #a #b }
};
assert_eq!(tokens.to_string(), "1i32 4i32");
}
#[test]
fn pattern_leading_rest_tuple() {
let tokens = quote! {
#(let (.., last) = (1i32, 2i32, 3i32)) { #last }
};
assert_eq!(tokens.to_string(), "3i32");
}
#[test]
fn pattern_struct_field_subpattern() {
struct Pair {
a: (i32, i32),
b: i32,
}
let pair = Pair {
a: (1i32, 2i32),
b: 3i32,
};
let tokens = quote! {
#(let Pair { a: (x, y), b } = pair) { #x #y #b }
};
assert_eq!(tokens.to_string(), "1i32 2i32 3i32");
}
#[test]
fn repeat_type_impl_both_borrow_and_totokens() {
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
use std::borrow::Borrow;
struct Both(#[allow(dead_code)] Vec<u8>);
impl Borrow<[u8]> for Both {
fn borrow(&self) -> &[u8] {
&self.0
}
}
impl template_quote::ToTokens for Both {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(Some(TokenTree::Ident(Ident::new(
"Both",
Span::call_site(),
))));
}
}
let both = Both(vec![1, 2, 3]);
let i = 0..3; let tokens = quote! { #(#i #both)* };
assert_eq!(tokens.to_string(), "0i32 Both 1i32 Both 2i32 Both");
}
#[test]
fn hygienic_internal_idents_no_user_collision() {
let __template_quote_stream = 111i32;
let __template_quote_idcnt = 222i32;
let __template_quote_it_0 = 333i32;
let __template_quote_m_0 = 444i32;
let x = [1i32, 2i32, 3i32];
let tokens = quote! { #(#x),* };
assert_eq!(tokens.to_string(), "1i32 , 2i32 , 3i32");
assert_eq!(__template_quote_stream, 111i32);
assert_eq!(__template_quote_idcnt, 222i32);
assert_eq!(__template_quote_it_0, 333i32);
assert_eq!(__template_quote_m_0, 444i32);
let s = quote! { #__template_quote_stream #__template_quote_idcnt };
assert_eq!(s.to_string(), "111i32 222i32");
}
#[test]
fn bare_hash_paren_emits_literal_hash() {
assert_eq!(quote! { a #() b }.to_string(), "a # () b");
assert_eq!(quote! { #(x y) }.to_string(), "# (x y)");
}