flagrant-macros 0.0.2

CLI powered feature-flagging
Documentation
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, FnArg, ItemFn};

struct Args {
   should_fail: bool
}

fn parse_args(attr_args: syn::AttributeArgs) -> syn::Result<Args> {
    let mut should_fail = false;
    for arg in attr_args {
        match arg {
            syn::NestedMeta::Meta(syn::Meta::NameValue(namevalue))
                if namevalue.path.is_ident("should_fail") => {
                    should_fail = match namevalue.lit {
                        syn::Lit::Bool(litbool) => litbool.value,
                        _ => {
                            return Err(syn::Error::new_spanned(
                                namevalue,
                                "expected `true` or `false`",
                            ))
                        }
                    };
                },
            other => {
                return Err(syn::Error::new_spanned(
                    other,
                    "expected `should_fail = true | false`",
                ))
            }

        }
    }
    Ok(Args { should_fail })
}

#[proc_macro_attribute]
pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);
    let input = parse_macro_input!(item as ItemFn);

    let function_name = input.sig.ident.clone();
    let arguments = input.sig.inputs;
    let return_type = input.sig.output.clone();

    let block = &input.block;
    let migrate = if let Some(FnArg::Typed(arg)) = arguments.first() {
        let name = arg.pat.clone().into_token_stream();
        quote! { flagrant::db::migrate(&#name, semver::Version::parse("0.0.1").unwrap()).await.unwrap(); }
    } else {
        quote! {}
    };
    let should_fail = if parse_args(args).unwrap().should_fail {
        quote! {
            #[should_panic]
        }
    } else {
        quote! { }
    };

    quote! {
        #[sqlx::test]
        #should_fail
        async fn #function_name(#arguments) #return_type {
            #migrate
            #block
        }
    }.into()
}