use proc_macro2::TokenStream;
use syn::{DeriveInput, File};
use crate::parse::args::parse_macro_args;
use crate::util::error_sink::ErrorSink;
macro_rules! assert_expansion_eq {
(@unless []: $($x:tt)*) => {
$($x)*
};
(@unless [true $($marker:tt)?]: $($x:tt)*) => {};
($(@no_doctest $([$nodoc:tt])?)? $name:ident: $(($($args:tt)*))? { $($input:tt)* } => { $($output:tt)* }) => {
mod $name {
assert_expansion_eq!(@unless [$(true $($nodoc)?)?]:
#[doc = "```"]
#[doc = concat!("#[::verty::versioned", $("(", stringify!($($args)*), ")",)? "]")]
#[doc = stringify!($($input)*)]
#[doc = "```"]
mod doctest {}
);
#[test]
fn run() {
let _args = ::proc_macro2::TokenStream::new();
$(let _args = ::quote::quote! {
$($args)*
};)?
let input = ::quote::quote! {
$($input)*
};
let control = ::syn::parse_quote! {
$($output)*
};
$crate::tests::_assert_expansion_ok_eq(_args, input, control);
}
}
};
}
#[track_caller]
fn _assert_expansion_ok_eq(args: TokenStream, input: TokenStream, control: File) {
assert!(
control.shebang.is_none() && control.attrs.is_empty(),
"invalid control tokens"
);
let args = ErrorSink::new()
.scope(|errs| parse_macro_args(args, errs))
.expect("malformed test (invalid MacroArgs)");
let input = syn::parse2::<DeriveInput>(input).expect("malformed test (invalid DeriveInput)");
let output = crate::process::type_::versioned(args, input);
let output = output.expect("proc macro expansion failed").print();
let output_str = output.to_string();
let output = syn::parse2::<File>(output).unwrap_or_else(|e| {
panic!("Expansion wasn't valid code ({:?}): {}", e, output_str);
});
assert!(
output.shebang.is_none() && output.attrs.is_empty(),
"Invalid output: emitted file-start-exclusive tokens"
);
if output.items != control.items {
let output_display = prettyplease::unparse(&output);
let control_display = prettyplease::unparse(&control);
let diff = diff::lines(&control_display, &output_display)
.into_iter()
.map(|res| match res {
diff::Result::Left(l) => format!("-{l}"),
diff::Result::Right(r) => format!("+{r}"),
diff::Result::Both(l, _) => format!(" {l}"),
})
.collect::<Vec<_>>()
.join("\n");
let diff_title = "Diff (after prettifying)";
eprintln!(
"=== {diff_title} ===\n{diff}\n===={}====",
"=".repeat(diff_title.len())
);
assert_eq!(output.items, control.items);
}
assert_eq!(output.items, control.items);
}
macro_rules! assert_expansion_error {
($name:ident: $(($($args:tt)*))? { $($input:tt)* } => $error:literal) => {
mod $name {
#[test]
fn run() {
let _args = ::proc_macro2::TokenStream::new();
$(let _args = ::quote::quote! {
$($args)*
};)?
let input = ::quote::quote! {
$($input)*
};
let control = $error;
$crate::tests::_assert_expansion_error(_args, input, control);
}
}
};
}
#[track_caller]
fn _assert_expansion_error(args: TokenStream, input: TokenStream, control: &'static str) {
let args = ErrorSink::new()
.scope(|errs| parse_macro_args(args, errs))
.expect("malformed test (invalid MacroArgs)");
let input = syn::parse2::<DeriveInput>(input).expect("malformed test (invalid DeriveInput)");
let output = crate::process::type_::versioned(args, input);
let error = match output {
Ok(_) => panic!("proc macro expansion didn't fail"),
Err(e) => e.to_string(),
};
assert_eq!(error, control);
}
mod ver_struct_union;
mod ver_enum;