Macro proc_macro_utils::assert_expansion
source · macro_rules! assert_expansion { ($macro:ident!($($input:tt)*)$(.$fn:ident())?, { $($rhs:tt)* }) => { ... }; ($macro:ident![$($input:tt)*]$(.$fn:ident())?, { $($rhs:tt)* }) => { ... }; ($macro:ident!{$($input:tt)*}$(.$fn:ident())?, { $($rhs:tt)* }) => { ... }; (#[derive($macro:ident)]$item:item$(.$fn:ident())?$(,)? { $($rhs:tt)* }) => { ... }; (#[$macro:ident]$item:item$(.$fn:ident())?$(,)? { $($rhs:tt)* }) => { ... }; (#[$macro:ident = $input:expr]$item:item$(.$fn:ident())?$(,)? { $($rhs:tt)* }) => { ... }; (#[$macro:ident($($input:tt)*)]$item:item$(.$fn:ident())?$(,)? { $($rhs:tt)* }) => { ... }; ($macro:ident($({$($input:tt)*}),+$(,)?)$(.$fn:ident())?, {$($rhs:tt)*}) => { ... }; }
Available on crate feature
parser
only.Expand description
Allows simple unit testing of proc macro implementations.
This macro only works with functions taking proc_macro2::TokenStream
due
to the proc_macro
api not being available in unit tests. This can be
achieved either by manually creating a seperate function:
ⓘ
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
#[proc_macro]
pub fn actual_macro(input: TokenStream) -> TokenStream {
macro_impl(input.into()).into()
}
fn macro_impl(input: TokenStream2) -> TokenStream2 {
// ...
}
or use a crate like manyhow
:
ⓘ
use proc_macro2::TokenStream as TokenStream2;
#[manyhow(impl_fn)] // generates `fn actual_macro_impl`
pub fn actual_macro(input: TokenStream2) -> TokenStream2 {
// ...
}
Function like macros
// Dummy attribute macro impl
fn macro_impl(input: TokenStream) -> TokenStream {
quote!(#input)
}
fn macro_impl_result(input: TokenStream) -> Result<TokenStream, ()> {
Ok(quote!(#input))
}
assert_expansion!(
macro_impl!(something test),
{ something test }
);
assert_expansion!(
macro_impl![1, 2, 3],
{ 1, 2, 3 }
);
assert_expansion!(
macro_impl!{ braced },
{ braced }
);
// adding a single function call (without arguments) is also allowed e.g. `unwrap()`
assert_expansion!(
macro_impl_result!(result).unwrap(),
{ result }
);
Derive macros
// Dummy derive macro impl
fn macro_impl(item: TokenStream) -> TokenStream {
quote!(#item)
}
fn macro_impl_result(item: TokenStream) -> Result<TokenStream, ()> {
Ok(quote!(#item))
}
assert_expansion!(
#[derive(macro_impl)]
struct A; // the comma after items is optional
{ struct A; }
);
assert_expansion!(
#[derive(macro_impl)]
struct A {}
{ struct A {} }
);
// adding a single function call (without arguments) is also allowed e.g. `unwrap()`
assert_expansion!(
#[derive(macro_impl_result)]
struct A {}.unwrap()
{ struct A {} }
);
// alternatively the proc_macro syntax is compatible
assert_expansion!(
macro_impl!{ struct A {} },
{ struct A {} }
);
Attribute macros
// Dummy attribute macro impl
fn macro_impl(input: TokenStream, item: TokenStream) -> TokenStream {
quote!(#input, #item)
}
fn macro_impl_result(input: TokenStream, item: TokenStream) -> Result<TokenStream, ()> {
Ok(quote!(#input, #item))
}
assert_expansion!(
#[macro_impl]
struct A;
{ , struct A; }
);
assert_expansion!(
#[macro_impl = "hello"]
fn test() { }, // the comma after items is optional
{ "hello", fn test() {} }
);
assert_expansion!(
#[macro_impl(a = 10)]
impl Hello for World {},
{ a = 10, impl Hello for World {} }
);
// adding a single function call (without arguments) is also allowed e.g. `unwrap()`
assert_expansion!(
#[macro_impl_result(a = 10)]
impl Hello for World {}.unwrap(),
{ a = 10, impl Hello for World {} }
);
Generic usage
On top of the normal macro inputs a generic input is also supported.
fn macro_impl(first: TokenStream, second: TokenStream, third: TokenStream) -> TokenStream {
quote!(#first, #second, #third)
}
fn macro_impl_result(first: TokenStream, second: TokenStream, third: TokenStream) -> Result<TokenStream, ()> {
Ok(quote!(#first, #second, #third))
}
assert_expansion!(
macro_impl({ 1 }, { something }, { ":)" }),
{ 1, something, ":)" }
);
// adding a single function call (without arguments) is also allowed e.g. `unwrap()`
assert_expansion!(
macro_impl_result({ 1 }, { something }, { ":)" }).unwrap(),
{ 1, something, ":)" }
);