test-with-derive 0.16.1

A library that helps you run tests with conditions
Documentation
#[cfg(feature = "runtime")]
use proc_macro::TokenStream;
#[cfg(feature = "runtime")]
use syn::{parse_macro_input, ItemFn, ReturnType};

pub(crate) fn check_http_condition(attr_str: String) -> (bool, String) {
    let links: Vec<&str> = attr_str.split(',').collect();
    let mut missing_links = vec![];
    let client = reqwest::blocking::Client::new();
    for link in links.iter() {
        if client.head(format!("http://{link}")).send().is_err() {
            missing_links.push(format!("http://{link:}"));
        }
    }
    let ignore_msg = if missing_links.len() == 1 {
        format!("because {} not response", missing_links[0])
    } else {
        format!(
            "because following links not response: \n{}\n",
            missing_links.join("\n")
        )
    };
    (missing_links.is_empty(), ignore_msg)
}

pub(crate) fn check_https_condition(attr_str: String) -> (bool, String) {
    let links: Vec<&str> = attr_str.split(',').collect();
    let mut missing_links = vec![];
    let client = reqwest::blocking::Client::new();
    for link in links.iter() {
        if client.head(format!("https://{link}")).send().is_err() {
            missing_links.push(format!("https://{link:}"));
        }
    }
    let ignore_msg = if missing_links.len() == 1 {
        format!("because {} not response", missing_links[0])
    } else {
        format!(
            "because following links not response: \n{}\n",
            missing_links.join("\n")
        )
    };
    (missing_links.is_empty(), ignore_msg)
}

#[cfg(feature = "runtime")]
pub(crate) fn runtime_http(attr: TokenStream, stream: TokenStream) -> TokenStream {
    let attr_str = attr.to_string().replace(' ', "");
    let links: Vec<&str> = attr_str.split(',').collect();
    let ItemFn {
        attrs,
        vis,
        sig,
        block,
    } = parse_macro_input!(stream as ItemFn);
    let syn::Signature { ident, .. } = sig.clone();
    let check_ident = syn::Ident::new(&format!("_check_{ident}"), proc_macro2::Span::call_site());
    let check_fn = match (&sig.asyncness, &sig.output) {
        (Some(_), ReturnType::Default) => quote::quote! {
            async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
                let mut missing_links = vec![];
                let client = test_with::reqwest::Client::new();
                #(
                    if client.head(&format!("http://{}", #links)).send().await.is_err() {
                        missing_links.push(format!("http://{}", #links));
                    }
                )*
                match missing_links.len() {
                    0 => {
                        #ident().await;
                        Ok(test_with::Completion::Completed)
                    },
                    1 => Ok(test_with::Completion::ignored_with(format!("because {} not response", missing_links[0]))),
                    _ => Ok(test_with::Completion::ignored_with(format!("because following links not response: \n{}\n", missing_links.join(", ")))),
                }
            }
        },
        (Some(_), ReturnType::Type(_, _)) => quote::quote! {
            async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
                let mut missing_links = vec![];
                let client = test_with::reqwest::Client::new();
                #(
                    if client.head(&format!("http://{}", #links)).send().await.is_err() {
                        missing_links.push(format!("http://{}", #links));
                    }
                )*
                match missing_links.len() {
                    0 => {
                        if let Err(e) = #ident().await {
                            Err(format!("{e:?}").into())
                        } else {
                            Ok(test_with::Completion::Completed)
                        }
                    },
                    1 => Ok(test_with::Completion::ignored_with(format!("because {} not response", missing_links[0]))),
                    _ => Ok(test_with::Completion::ignored_with(format!("because following links not response: \n{}\n", missing_links.join(", ")))),
                }
            }
        },
        (None, _) => quote::quote! {
            fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
                let mut missing_links = vec![];
                let client = test_with::reqwest::blocking::Client::new();
                #(
                    if client.head(&format!("http://{}", #links)).send().is_err() {
                        missing_links.push(format!("http://{}", #links));
                    }
                )*
                match missing_links.len() {
                    0 => {
                        #ident();
                        Ok(test_with::Completion::Completed)
                    },
                    1 => Ok(test_with::Completion::ignored_with(format!("because {} not response", missing_links[0]))),
                    _ => Ok(test_with::Completion::ignored_with(format!("because following links not response: \n{}\n", missing_links.join(", ")))),
                }
            }
        },
    };

    quote::quote! {
            #check_fn
            #(#attrs)*
            #vis #sig #block
    }
    .into()
}

#[cfg(feature = "runtime")]
pub(crate) fn runtime_https(attr: TokenStream, stream: TokenStream) -> TokenStream {
    let attr_str = attr.to_string().replace(' ', "");
    let links: Vec<&str> = attr_str.split(',').collect();
    let ItemFn {
        attrs,
        vis,
        sig,
        block,
    } = parse_macro_input!(stream as ItemFn);
    let syn::Signature { ident, .. } = sig.clone();
    let check_ident = syn::Ident::new(&format!("_check_{ident}"), proc_macro2::Span::call_site());

    let check_fn = match (&sig.asyncness, &sig.output) {
        (Some(_), ReturnType::Default) => quote::quote! {
            async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
                let mut missing_links = vec![];
                let client = test_with::reqwest::Client::new();
                #(
                    if client.head(&format!("https://{}", #links)).send().await.is_err() {
                        missing_links.push(format!("https://{}", #links));
                    }
                )*
                match missing_links.len() {
                    0 => {
                        #ident().await;
                        Ok(test_with::Completion::Completed)
                    },
                    1 => Ok(test_with::Completion::ignored_with(format!("because {} not response", missing_links[0]))),
                    _ => Ok(test_with::Completion::ignored_with(format!("because following links not response: \n{}\n", missing_links.join(", ")))),
                }
            }
        },
        (Some(_), ReturnType::Type(_, _)) => quote::quote! {
            async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
                let mut missing_links = vec![];
                let client = test_with::reqwest::Client::new();
                #(
                    if client.head(&format!("https://{}", #links)).send().await.is_err() {
                        missing_links.push(format!("https://{}", #links));
                    }
                )*
                match missing_links.len() {
                    0 => {
                        if let Err(e) = #ident().await {
                            Err(format!("{e:?}").into())
                        } else {
                            Ok(test_with::Completion::Completed)
                        }
                    },
                    1 => Ok(test_with::Completion::ignored_with(format!("because {} not response", missing_links[0]))),
                    _ => Ok(test_with::Completion::ignored_with(format!("because following links not response: \n{}\n", missing_links.join(", ")))),
                }
            }
        },
        (None, _) => quote::quote! {
            fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
                let mut missing_links = vec![];
                let client = test_with::reqwest::blocking::Client::new();
                #(
                    if client.head(&format!("https://{}", #links)).send().is_err() {
                        missing_links.push(format!("https://{}", #links));
                    }
                )*
                match missing_links.len() {
                    0 => {
                        #ident();
                        Ok(test_with::Completion::Completed)
                    },
                    1 => Ok(test_with::Completion::ignored_with(format!("because {} not response", missing_links[0]))),
                    _ => Ok(test_with::Completion::ignored_with(format!("because following links not response: \n{}\n", missing_links.join(", ")))),
                }
            }
        },
    };

    quote::quote! {
            #check_fn
            #(#attrs)*
            #vis #sig #block
    }
    .into()
}