diff --git a/Cargo.toml b/Cargo.toml index 7f5fad0..48379ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-with" -version = "0.10.2" +version = "0.10.3" authors = ["Antonio Yang "] edition = "2021" license = "MIT" diff --git a/examples/runner/examples/test.rs b/examples/runner/examples/test.rs index e1c9a07..f4cfffc 100644 --- a/examples/runner/examples/test.rs +++ b/examples/runner/examples/test.rs @@ -69,4 +69,12 @@ mod net { fn https_test_works() { assert!(true); } + #[test_with::runtime_icmp(193.194.195.196)] + fn test_ignored_with_non_existing_host() { + panic!("should be ignored with non existing host") + } + #[test_with::runtime_tcp(8.8.8.8:53)] + fn test_works_with_domain_name_server() { + assert!(true); + } } diff --git a/src/lib.rs b/src/lib.rs index 2ab368b..39295b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -886,6 +886,72 @@ fn check_icmp_condition(attr_str: String) -> (bool, String) { (missing_ips.is_empty(), ignore_msg) } +/// Run test case when the server online. +/// Please make sure the role of test case runner have capability to open socket +///```rust +/// // write as example in exmaples/*rs +/// test_with::runner!(icmp); +/// #[test_with::module] +/// mod icmp { +/// // 193.194.195.196 is offline +/// #[test_with::runtime_icmp(193.194.195.196)] +/// fn test_ignored_with_non_existing_host() { +/// panic!("should be ignored with non existing host") +/// } +/// } +#[cfg(not(feature = "runtime"))] +#[proc_macro_attribute] +#[proc_macro_error] +pub fn runtime_icmp(_attr: TokenStream, _stream: TokenStream) -> TokenStream { + panic!("should be used with runtime feature") +} + +#[cfg(all(feature = "runtime", feature = "icmp"))] +#[proc_macro_attribute] +#[proc_macro_error] +pub fn runtime_icmp(attr: TokenStream, stream: TokenStream) -> TokenStream { + let attr_str = attr.to_string().replace(' ', ""); + let ips: 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.to_string()), + proc_macro2::Span::call_site(), + ); + quote::quote! { + fn #check_ident() -> Result<(), libtest_with::Failed> { + + let mut missing_ips = vec![]; + #( + if libtest_with::ping::ping(#ips, None, None, None, None, None).is_err() { + missing_ips.push(#ips); + } + )* + match missing_ips.len() { + 0 => #ident(), + 1 => return Err( + format!("{}because {} not response", + libtest_with::RUNTIME_IGNORE_PREFIX, missing_ips[0] + ).into()), + _ => return Err( + format!("{}because following ips not response: \n{}\n", + libtest_with::RUNTIME_IGNORE_PREFIX, missing_ips.join(", ") + ).into()), + } + Ok(()) + } + + #(#attrs)* + #vis #sig #block + } + .into() +} + /// Run test case when socket connected /// /// ``` @@ -944,6 +1010,71 @@ fn check_tcp_condition(attr_str: String) -> (bool, String) { (missing_sockets.is_empty(), ignore_msg) } +/// Run test case when socket connected +///```rust +/// // write as example in exmaples/*rs +/// test_with::runner!(tcp); +/// #[test_with::module] +/// mod tcp { +/// // Google DNS is online +/// #[test_with::runtime_tcp(8.8.8.8:53)] +/// fn test_works_with_DNS_server() { +/// assert!(true); +/// } +/// } +#[cfg(not(feature = "runtime"))] +#[proc_macro_attribute] +#[proc_macro_error] +pub fn runtime_tcp(_attr: TokenStream, _stream: TokenStream) -> TokenStream { + panic!("should be used with runtime feature") +} + +#[cfg(all(feature = "runtime"))] +#[proc_macro_attribute] +#[proc_macro_error] +pub fn runtime_tcp(attr: TokenStream, stream: TokenStream) -> TokenStream { + let attr_str = attr.to_string().replace(' ', ""); + let sockets: 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.to_string()), + proc_macro2::Span::call_site(), + ); + quote::quote! { + fn #check_ident() -> Result<(), libtest_with::Failed> { + + let mut missing_sockets = vec![]; + #( + if std::net::TcpStream::connect(#sockets).is_err() { + missing_sockets.push(#sockets); + } + )* + match missing_sockets.len() { + 0 => #ident(), + 1 => return Err( + format!("{}because {} not response", + libtest_with::RUNTIME_IGNORE_PREFIX, missing_sockets[0] + ).into()), + _ => return Err( + format!("{}because following sockets not response: \n{}\n", + libtest_with::RUNTIME_IGNORE_PREFIX, missing_sockets.join(", ") + ).into()), + } + Ok(()) + } + + #(#attrs)* + #vis #sig #block + } + .into() +} + /// Run test case when runner is root /// /// ```