Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,068 changes: 558 additions & 510 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = ["derive", "lib", "examples-with-runner"]
resolver = "2"

[workspace.package]
version = "0.16.4"
version = "0.17.0"
authors = ["Antonio Yang <yanganto@gmail.com>"]
edition = "2021"
description = "A library that helps you run tests with conditions"
Expand Down
55 changes: 54 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ the test runner will treat it as the test in Rust and also provide the same summ

The `runtime` feature should be enabled and include as normal dependency( not dev-dependencies).
```toml
test-with = { version = "0.16.4", features = ["runtime"] }
test-with = { version = "0.17.0", features = ["runtime"] }
```

Create an example with the following runtime macros (`test_with::runner!`, `#[test_with::module]`, `#[test_with::runtime_env()]`).
Expand Down Expand Up @@ -309,6 +309,59 @@ mod custom_mod {
}
```

or you can run the test case only when one of the network interface ip is in a CIDR with
`runtime_ip_in`. It requires the `ip` feature (with the `runtime` feature) if default features
are disabled.
```rust
test_with::runner!(ip);

#[test_with::module]
mod ip {
// Only run when one of the interface ip is in 192.168.1.0/24
#[test_with::runtime_ip_in(192.168.1.0/24)]
fn test_works() {
assert!(true);
}
}
```

or you can run the test case depending on the public ip with `runtime_public_ip` (run when the
public ip can be got), `runtime_public_ip_in` (run when the public ip is in a CIDR) and
`runtime_public_ip_is` (run when the public ip is exactly the expected ip). They default to check
the public ip with `https://ip.me`, and it can be overridden with an `ip_check_site` string
literal. They require the `ip` feature (with the `runtime` feature) if default features are
disabled.
```rust
test_with::runner!(ip);

#[test_with::module]
mod ip {
// Only run when the public ip can be got from https://ip.me
#[test_with::runtime_public_ip]
fn test_works() {
assert!(true);
}

// Override the check site (url has to be a string literal)
#[test_with::runtime_public_ip(ip_check_site = "https://ifconfig.me/ip")]
fn test_works_with_other_site() {
assert!(true);
}

// Only run when the public ip is in 1.2.3.0/24
#[test_with::runtime_public_ip_in(1.2.3.0/24)]
fn test_works_in_cidr() {
assert!(true);
}

// Only run when the public ip is exactly 1.2.3.4
#[test_with::runtime_public_ip_is(1.2.3.4)]
fn test_works_is() {
assert!(true);
}
}
```

There are two ways to setup mock service in the test runner, one is by `struct` and the other is by `type`.
```rust
test_with::runner!(test_with_mock);
Expand Down
3 changes: 2 additions & 1 deletion derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = [ "full" ] }
syn = { version = "3.0", features = [ "full" ] }
regex = { version = "1" }

reqwest = { version = "0.13", features = ["blocking"], optional = true }
Expand All @@ -39,6 +39,7 @@ runtime = []
net = ["http", "icmp"]
http = ["reqwest"]
icmp = ["ping"]
ip = []

resource = ["sysinfo", "byte-unit", "num_cpus"]
user = ["uzers"]
Expand Down
2 changes: 2 additions & 0 deletions derive/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub(crate) fn runtime_env(attr: TokenStream, stream: TokenStream) -> TokenStream
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());
Expand Down Expand Up @@ -147,6 +148,7 @@ pub(crate) fn runtime_no_env(attr: TokenStream, stream: TokenStream) -> TokenStr
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());
Expand Down
1 change: 1 addition & 0 deletions derive/src/executable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub(crate) fn runtime_executable(attr: TokenStream, stream: TokenStream) -> Toke
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());
Expand Down
2 changes: 2 additions & 0 deletions derive/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub(crate) fn runtime_file(attr: TokenStream, stream: TokenStream) -> TokenStrea
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());
Expand Down Expand Up @@ -135,6 +136,7 @@ pub(crate) fn runtime_path(attr: TokenStream, stream: TokenStream) -> TokenStrea
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());
Expand Down
2 changes: 2 additions & 0 deletions derive/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub(crate) fn runtime_http(attr: TokenStream, stream: TokenStream) -> TokenStrea
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());
Expand Down Expand Up @@ -135,6 +136,7 @@ pub(crate) fn runtime_https(attr: TokenStream, stream: TokenStream) -> TokenStre
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());
Expand Down
9 changes: 5 additions & 4 deletions derive/src/icmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub(crate) fn check_icmp_condition(attr_str: String) -> (bool, String) {
let mut missing_ips = vec![];
for ip in ips.iter() {
if let Ok(addr) = ip.parse::<IpAddr>() {
if ping::ping(addr, None, None, None, None, None).is_err() {
if ping::Ping::new(addr).send().is_err() {
missing_ips.push(ip.to_string());
}
} else {
Expand All @@ -37,6 +37,7 @@ pub(crate) fn runtime_icmp(attr: TokenStream, stream: TokenStream) -> TokenStrea
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());
Expand All @@ -46,7 +47,7 @@ pub(crate) fn runtime_icmp(attr: TokenStream, stream: TokenStream) -> TokenStrea
async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
let mut missing_ips = vec![];
#(
if test_with::ping::ping(#ips.parse().expect("ip address is invalid"), None, None, None, None, None).is_err() {
if test_with::ping::Ping::new(#ips.parse().expect("ip address is invalid")).send().is_err() {
missing_ips.push(#ips);
}
)*
Expand All @@ -64,7 +65,7 @@ pub(crate) fn runtime_icmp(attr: TokenStream, stream: TokenStream) -> TokenStrea
async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
let mut missing_ips = vec![];
#(
if test_with::ping::ping(#ips.parse().expect("ip address is invalid"), None, None, None, None, None).is_err() {
if test_with::ping::Ping::new(#ips.parse().expect("ip address is invalid")).send().is_err() {
missing_ips.push(#ips);
}
)*
Expand All @@ -85,7 +86,7 @@ pub(crate) fn runtime_icmp(attr: TokenStream, stream: TokenStream) -> TokenStrea
fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
let mut missing_ips = vec![];
#(
if test_with::ping::ping(#ips.parse().expect("ip address is invalid"), None, None, None, None, None).is_err() {
if test_with::ping::Ping::new(#ips.parse().expect("ip address is invalid")).send().is_err() {
missing_ips.push(#ips);
}
)*
Expand Down
126 changes: 124 additions & 2 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ mod icmp;
mod resource;
#[cfg(feature = "runtime")]
mod runtime;
#[cfg(all(feature = "runtime", feature = "ip"))]
mod runtime_ip;

mod socket;
#[cfg(feature = "timezone")]
mod timezone;
Expand Down Expand Up @@ -477,6 +480,123 @@ pub fn runtime_icmp(attr: TokenStream, stream: TokenStream) -> TokenStream {
icmp::runtime_icmp(attr, stream)
}

/// Run test case when the example running and one of the interface ip is in the CIDR.
///```rust
/// // write as example in examples/*rs
/// test_with::runner!(ip);
/// #[test_with::module]
/// mod ip {
/// // Only works when one of the interface ip is in 192.168.1.0/24
/// #[test_with::runtime_ip_in(192.168.1.0/24)]
/// fn test_works() {
/// assert!(true);
/// }
/// }
#[cfg(all(not(feature = "runtime"), feature = "ip"))]
#[proc_macro_attribute]
pub fn runtime_ip_in(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}

#[cfg(all(feature = "runtime", feature = "ip"))]
#[proc_macro_attribute]
pub fn runtime_ip_in(attr: TokenStream, stream: TokenStream) -> TokenStream {
runtime_ip::runtime_ip_in(attr, stream)
}

/// Run test case when the example running and the public ip can be got.
/// The default check site is `https://ip.me`, and can be overridden with `ip_check_site=<url>`.
///```rust
/// // write as example in examples/*rs
/// test_with::runner!(ip);
/// #[test_with::module]
/// mod ip {
/// // Only works when the public ip can be got from https://ip.me
/// #[test_with::runtime_public_ip]
/// fn test_works() {
/// assert!(true);
/// }
///
/// // Or override the check site (url has to be a string literal)
/// #[test_with::runtime_public_ip(ip_check_site = "https://ipinfo.io/ip")]
/// fn test_works_with_other_site() {
/// assert!(true);
/// }
/// }
#[cfg(all(not(feature = "runtime"), feature = "ip"))]
#[proc_macro_attribute]
pub fn runtime_public_ip(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}

#[cfg(all(feature = "runtime", feature = "ip"))]
#[proc_macro_attribute]
pub fn runtime_public_ip(attr: TokenStream, stream: TokenStream) -> TokenStream {
runtime_ip::runtime_public_ip(attr, stream)
}

/// Run test case when the example running and the public ip is in the CIDR.
/// The default check site is `https://ip.me`, and can be overridden with `ip_check_site=<url>`.
///```rust
/// // write as example in examples/*rs
/// test_with::runner!(ip);
/// #[test_with::module]
/// mod ip {
/// // Only works when the public ip is in 1.2.3.0/24
/// #[test_with::runtime_public_ip_in(1.2.3.0/24)]
/// fn test_works() {
/// assert!(true);
/// }
///
/// // Or override the check site (url has to be a string literal)
/// #[test_with::runtime_public_ip_in(1.2.3.0/24, ip_check_site = "https://ipinfo.io/ip")]
/// fn test_works_with_other_site() {
/// assert!(true);
/// }
/// }
#[cfg(all(not(feature = "runtime"), feature = "ip"))]
#[proc_macro_attribute]
pub fn runtime_public_ip_in(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}

#[cfg(all(feature = "runtime", feature = "ip"))]
#[proc_macro_attribute]
pub fn runtime_public_ip_in(attr: TokenStream, stream: TokenStream) -> TokenStream {
runtime_ip::runtime_public_ip_in(attr, stream)
}

/// Run test case when the example running and the public ip is exactly the expected ip.
/// The default check site is `https://ip.me`, and can be overridden with `ip_check_site=<url>`.
///```rust
/// // write as example in examples/*rs
/// test_with::runner!(ip);
/// #[test_with::module]
/// mod ip {
/// // Only works when the public ip is 1.2.3.4
/// #[test_with::runtime_public_ip_is(1.2.3.4)]
/// fn test_works() {
/// assert!(true);
/// }
///
/// // Or override the check site (url has to be a string literal)
/// #[test_with::runtime_public_ip_is(1.2.3.4, ip_check_site = "https://ipinfo.io/ip")]
/// fn test_works_with_other_site() {
/// assert!(true);
/// }
/// }
#[cfg(all(not(feature = "runtime"), feature = "ip"))]
#[proc_macro_attribute]
pub fn runtime_public_ip_is(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}

#[cfg(all(feature = "runtime", feature = "ip"))]
#[proc_macro_attribute]
pub fn runtime_public_ip_is(attr: TokenStream, stream: TokenStream) -> TokenStream {
runtime_ip::runtime_public_ip_is(attr, stream)
}

/// Run test case when socket connected
///
/// ```
Expand Down Expand Up @@ -554,7 +674,7 @@ pub fn runtime_tcp(attr: TokenStream, stream: TokenStream) -> TokenStream {
/// }
/// ```
#[proc_macro_attribute]
#[cfg(all(feature = "user"))]
#[cfg(feature = "user")]
pub fn root(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
Expand Down Expand Up @@ -609,7 +729,7 @@ pub fn runtime_root(attr: TokenStream, stream: TokenStream) -> TokenStream {
/// }
/// ```
#[proc_macro_attribute]
#[cfg(all(feature = "user"))]
#[cfg(feature = "user")]
pub fn group(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
Expand Down Expand Up @@ -872,6 +992,7 @@ pub fn runtime_swap(attr: TokenStream, stream: TokenStream) -> TokenStream {
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());
Expand Down Expand Up @@ -1192,6 +1313,7 @@ pub fn runtime_ignore_if(attr: TokenStream, stream: TokenStream) -> TokenStream
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());
Expand Down
Loading