|
1 | 1 | use proc_macro::TokenStream; |
2 | | -use std::env::var; |
| 2 | +use quote::quote; |
| 3 | +use syn::{ |
| 4 | + parse::{Parse, ParseStream}, |
| 5 | + parse_macro_input, ItemFn, LitStr, |
| 6 | +}; |
3 | 7 |
|
| 8 | +struct InputArgs { |
| 9 | + environment_variable: LitStr, |
| 10 | +} |
| 11 | + |
| 12 | +impl Parse for InputArgs { |
| 13 | + fn parse(input: ParseStream) -> syn::Result<Self> { |
| 14 | + let environment_variable = input.parse::<LitStr>()?; |
| 15 | + Ok(Self { |
| 16 | + environment_variable, |
| 17 | + }) |
| 18 | + } |
| 19 | +} |
4 | 20 |
|
5 | | -/// Skip compilation if the environment variable `env_var` is undefined or if its content does not |
6 | | -/// match the provided value. |
7 | 21 | #[proc_macro_attribute] |
8 | | -pub fn needs_env_var(env_var: TokenStream, input: TokenStream) -> TokenStream { |
9 | | - let macro_string = env_var.to_string().replace(" = ", "="); |
10 | | - let mut parts = macro_string.split('='); |
| 22 | +pub fn needs_env_var(attr: TokenStream, item: TokenStream) -> TokenStream { |
| 23 | + let input = parse_macro_input!(item as ItemFn); |
| 24 | + let input_args = parse_macro_input!(attr as InputArgs); |
| 25 | + let environment_variable = input_args.environment_variable.value().replace(" ", ""); |
11 | 26 |
|
12 | | - let var_str = parts.next().expect("macro needs an environment variable name"); |
13 | | - let matches = parts.next(); |
| 27 | + let (env_var, expected_value): (String, Option<String>) = |
| 28 | + match environment_variable.split_once("=") { |
| 29 | + Some((key, value)) => (key.to_string(), Some(value.to_string())), |
| 30 | + None => (environment_variable.clone(), None), |
| 31 | + }; |
14 | 32 |
|
15 | | - let var_content = var(var_str); |
16 | | - let exists = var_content.is_ok(); |
| 33 | + let ItemFn { |
| 34 | + attrs, |
| 35 | + vis, |
| 36 | + sig, |
| 37 | + block, |
| 38 | + } = input; |
17 | 39 |
|
18 | | - if !exists || matches.is_some() && matches != var_content.ok().as_deref() { |
19 | | - println!("\x1b[93mskipped. environment variable: \"{}\" did not match or was not set.\x1b[0m", var_str); |
20 | | - return TokenStream::new(); |
21 | | - } |
22 | | - input |
| 40 | + let expanded = quote! { |
| 41 | + #(#attrs)* #vis #sig { |
| 42 | + match std::env::var(#env_var) { |
| 43 | + Err(_) => {eprintln!("\x1b[93mSkipping test because environment variable {} is not set.\x1b[0m", #env_var); |
| 44 | + return; |
| 45 | + } |
| 46 | + Ok(value) => { |
| 47 | + if value != #expected_value { |
| 48 | + eprintln!("\x1b[93mSkipping test because environment variable {}={}. Expected: {}.\x1b[0m", #env_var, value, #expected_value); |
| 49 | + return; |
| 50 | + } |
| 51 | + } |
| 52 | + }; |
| 53 | + #block |
| 54 | + } |
| 55 | + }; |
| 56 | + |
| 57 | + TokenStream::from(expanded) |
23 | 58 | } |
0 commit comments