diff --git a/rstest/Cargo.toml b/rstest/Cargo.toml index 2a12f7d..d237283 100644 --- a/rstest/Cargo.toml +++ b/rstest/Cargo.toml @@ -14,12 +14,16 @@ readme = "README.md" repository = "https://github.com/la10736/rstest" version = "0.14.0" +[features] +async-timeout = ["dep:futures", "dep:futures-timer", "rstest_macros/async-timeout"] +default = ["async-timeout"] + [lib] [dependencies] -futures = "0.3.15" -futures-timer = "3.0.2" -rstest_macros = {version = "0.14.0", path = "../rstest_macros"} +futures = {version = "0.3.15", optional = true} +futures-timer = {version = "3.0.2", optional = true} +rstest_macros = {version = "0.14.0", path = "../rstest_macros", default-features = false} [dev-dependencies] actix-rt = "2.2.0" diff --git a/rstest/src/timeout.rs b/rstest/src/timeout.rs index ffc4732..07edc3e 100644 --- a/rstest/src/timeout.rs +++ b/rstest/src/timeout.rs @@ -1,6 +1,8 @@ use std::{sync::mpsc, time::Duration}; +#[cfg(feature = "async-timeout")] use futures::{select, Future, FutureExt}; +#[cfg(feature = "async-timeout")] use futures_timer::Delay; pub fn execute_with_timeout_sync T + Send + 'static>( @@ -14,6 +16,7 @@ pub fn execute_with_timeout_sync T + Send + 'stati .unwrap_or_else(|_| panic!("Timeout {:?} expired", timeout)) } +#[cfg(feature = "async-timeout")] pub async fn execute_with_timeout_async, F: Fn() -> Fut>( code: F, timeout: Duration, @@ -29,6 +32,7 @@ pub async fn execute_with_timeout_async, F: Fn() -> F #[cfg(test)] mod tests { use super::*; + #[cfg(feature = "async-timeout")] mod async_version { use super::*; diff --git a/rstest_macros/Cargo.toml b/rstest_macros/Cargo.toml index 0f43da9..f276738 100644 --- a/rstest_macros/Cargo.toml +++ b/rstest_macros/Cargo.toml @@ -16,7 +16,9 @@ version = "0.14.0" [lib] proc-macro = true -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +async-timeout = ["rstest/async-timeout"] +default = ["async-timeout"] [dependencies] cfg-if = "1.0.0" @@ -28,7 +30,7 @@ syn = {version = "1.0.72", features = ["full", "parsing", "extra-traits", "visit actix-rt = "2.2.0" async-std = {version = "1.9.0", features = ["attributes"]} pretty_assertions = "1.0.0" -rstest = {version = "0.14.0", path = "../rstest"} +rstest = {version = "0.14.0", path = "../rstest", default-features = false} rstest_reuse = {version = "0.3.0", path = "../rstest_reuse"} rstest_test = {version = "0.7.0", path = "../rstest_test"} diff --git a/rstest_macros/src/parse/mod.rs b/rstest_macros/src/parse/mod.rs index 9f57b89..20dbda8 100644 --- a/rstest_macros/src/parse/mod.rs +++ b/rstest_macros/src/parse/mod.rs @@ -3,7 +3,7 @@ use syn::{ parse::{Parse, ParseStream}, parse_quote, punctuated::Punctuated, - token::{self, Paren}, + token::{self, Async, Paren}, visit_mut::VisitMut, FnArg, Ident, ItemFn, Token, }; @@ -573,6 +573,23 @@ impl CheckTimeoutAttributesFunction { pub(crate) fn take(self) -> Result<(), ErrorsVec> { self.0 } + + fn check_if_can_implement_timeous<'a, 'b, 'c>( + &self, + timeouts: &'c [&'a syn::Attribute], + asyncness: Option<&'b Async>, + ) -> Option { + if cfg!(feature = "async-timeout") || timeouts.is_empty() { + None + } else { + asyncness.map(|a| { + syn::Error::new( + a.span, + "Enable async-timeout feature to use timeout in async tests", + ) + }) + } + } } impl Default for CheckTimeoutAttributesFunction { @@ -583,13 +600,22 @@ impl Default for CheckTimeoutAttributesFunction { impl VisitMut for CheckTimeoutAttributesFunction { fn visit_item_fn_mut(&mut self, node: &mut ItemFn) { - let errors = node + let timeouts = node .attrs .iter() .filter(|&a| attr_is(a, "timeout")) - .map(|attr| attr.parse_args::()) + .collect::>(); + let mut errors = timeouts + .iter() + .map(|&attr| attr.parse_args::()) .filter_map(Result::err) .collect::>(); + + if let Some(e) = + self.check_if_can_implement_timeous(timeouts.as_slice(), node.sig.asyncness.as_ref()) + { + errors.push(e); + } if !errors.is_empty() { *self = Self(Err(errors.into())); } diff --git a/rstest_macros/src/parse/rstest.rs b/rstest_macros/src/parse/rstest.rs index f661713..bb2051d 100644 --- a/rstest_macros/src/parse/rstest.rs +++ b/rstest_macros/src/parse/rstest.rs @@ -301,6 +301,39 @@ mod test { assert_eq!(2, errors.len()); } + #[cfg(feature = "async-timeout")] + #[test] + fn should_parse_async_timeout() { + let mut item_fn = r#" + #[timeout(Duration::from_millis(20))] + async fn test_fn(#[case] arg: u32) { + } + "# + .ast(); + + let mut info = RsTestInfo::default(); + + info.extend_with_function_attrs(&mut item_fn).unwrap(); + } + + #[cfg(not(feature = "async-timeout"))] + #[test] + fn should_return_error_for_async_timeout() { + let mut item_fn = r#" + #[timeout(Duration::from_millis(20))] + async fn test_fn(#[case] arg: u32) { + } + "# + .ast(); + + let mut info = RsTestInfo::default(); + + let errors = info.extend_with_function_attrs(&mut item_fn).unwrap_err(); + + assert_eq!(1, errors.len()); + assert!(format!("{:?}", errors).contains("async-timeout feature")) + } + fn parse_rstest>(rstest_data: S) -> RsTestInfo { parse_meta(rstest_data) }