diff --git a/crates/libtest2-harness/src/case.rs b/crates/libtest2-harness/src/case.rs index 5662d06..2e7c0a1 100644 --- a/crates/libtest2-harness/src/case.rs +++ b/crates/libtest2-harness/src/case.rs @@ -15,6 +15,44 @@ pub trait Case: Send + Sync + 'static { fn run(&self, state: &TestContext) -> Result<(), RunError>; } +impl Case for Box { + fn name(&self) -> &str { + self.as_ref().name() + } + fn kind(&self) -> TestKind { + self.as_ref().kind() + } + fn source(&self) -> Option<&Source> { + self.as_ref().source() + } + fn exclusive(&self, state: &TestContext) -> bool { + self.as_ref().exclusive(state) + } + + fn run(&self, state: &TestContext) -> Result<(), RunError> { + self.as_ref().run(state) + } +} + +impl Case for std::sync::Arc { + fn name(&self) -> &str { + self.as_ref().name() + } + fn kind(&self) -> TestKind { + self.as_ref().kind() + } + fn source(&self) -> Option<&Source> { + self.as_ref().source() + } + fn exclusive(&self, state: &TestContext) -> bool { + self.as_ref().exclusive(state) + } + + fn run(&self, state: &TestContext) -> Result<(), RunError> { + self.as_ref().run(state) + } +} + /// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html) /// conventions. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/crates/libtest2/examples/tidy.rs b/crates/libtest2/examples/tidy.rs index 752c85d..ee26502 100644 --- a/crates/libtest2/examples/tidy.rs +++ b/crates/libtest2/examples/tidy.rs @@ -1,3 +1,6 @@ +use std::borrow::Cow; + +use libtest2::Case; use libtest2::FnCase; use libtest2::RunError; use libtest2::RunResult; @@ -23,8 +26,8 @@ fn main() -> std::io::Result<()> { /// Creates one test for each `.rs` file in the current directory or /// sub-directories of the current directory. -fn collect_tests() -> std::io::Result> { - fn visit_dir(path: &std::path::Path, tests: &mut Vec) -> std::io::Result<()> { +fn collect_tests() -> std::io::Result>> { + fn visit_dir(path: &std::path::Path, tests: &mut Vec>) -> std::io::Result<()> { let current_dir = std::env::current_dir()?; for entry in std::fs::read_dir(path)? { let entry = entry?; @@ -44,8 +47,8 @@ fn collect_tests() -> std::io::Result> { .to_string_lossy() .into_owned(); - let test = FnCase::test(name, move |_| check_file(&path)); - tests.push(test); + let test = FnCase::test(Cow::Owned(name), move |_| check_file(&path)); + tests.push(Box::new(test)); } } else if file_type.is_dir() { // Handle directories diff --git a/crates/libtest2/src/case.rs b/crates/libtest2/src/case.rs index 079e45b..8fb14e1 100644 --- a/crates/libtest2/src/case.rs +++ b/crates/libtest2/src/case.rs @@ -27,25 +27,24 @@ impl Case for DynCase { } } -pub struct FnCase { - name: String, - #[allow(clippy::type_complexity)] - runner: Box RunResult + Send + Sync>, +pub struct FnCase { + name: std::borrow::Cow<'static, str>, + runner: R, } -impl FnCase { - pub fn test( - name: impl Into, - runner: impl Fn(&TestContext) -> RunResult + Send + Sync + 'static, - ) -> Self { - Self { - name: name.into(), - runner: Box::new(runner), - } +impl FnCase +where + R: Fn(&TestContext) -> RunResult + Send + Sync + 'static, +{ + pub const fn test(name: std::borrow::Cow<'static, str>, runner: R) -> Self { + Self { name, runner } } } -impl Case for FnCase { +impl Case for FnCase +where + R: Fn(&TestContext) -> RunResult + Send + Sync + 'static, +{ fn name(&self) -> &str { &self.name } diff --git a/crates/libtest2/src/lib.rs b/crates/libtest2/src/lib.rs index 900cae8..a39aefc 100644 --- a/crates/libtest2/src/lib.rs +++ b/crates/libtest2/src/lib.rs @@ -55,7 +55,6 @@ mod macros; pub mod _private { pub use distributed_list::push; pub use distributed_list::DistributedList; - pub use libtest2_harness::Case; pub use libtest2_harness::Source; pub use libtest2_harness::TestKind; @@ -67,6 +66,7 @@ pub mod _private { pub use case::main; pub use case::FnCase; +pub use libtest2_harness::Case; pub use libtest2_harness::IntoRunResult; pub use libtest2_harness::RunError; pub use libtest2_harness::RunResult; diff --git a/crates/libtest2/src/macros.rs b/crates/libtest2/src/macros.rs index aa3b852..8991fb6 100644 --- a/crates/libtest2/src/macros.rs +++ b/crates/libtest2/src/macros.rs @@ -30,39 +30,27 @@ macro_rules! _parse_ignore { #[allow(clippy::crate_in_macro_def)] // accessing item defined by `_main_parse` macro_rules! _test_parse { (#[test] $(#[$($attr:tt)*])* fn $name:ident $($item:tt)*) => { - #[allow(non_camel_case_types)] - struct $name; - - impl $crate::_private::Case for $name { - fn name(&self) -> &str { - $crate::_private::push!(crate::TESTS, _: $crate::_private::DynCase = $crate::_private::DynCase(&$name)); - - stringify!($name) - } - fn kind(&self) -> $crate::_private::TestKind { - Default::default() - } - fn source(&self) -> Option<&$crate::_private::Source> { - None - } - fn exclusive(&self, _: &$crate::TestContext) -> bool { - false - } - - fn run(&self, context: &$crate::TestContext) -> $crate::RunResult { - fn run $($item)* - - $( - match $crate::_private::parse_ignore!($($attr)*) { - ::std::option::Option::None => context.ignore()?, - ::std::option::Option::Some(reason) => context.ignore_for(reason)?, + const _: () = { + $crate::_private::push!( + crate::TESTS, + _: $crate::_private::DynCase = $crate::_private::DynCase(&$crate::FnCase::test( + ::std::borrow::Cow::Borrowed(stringify!($name)), + |context| { + $( + match $crate::_private::parse_ignore!($($attr)*) { + ::std::option::Option::None => context.ignore()?, + ::std::option::Option::Some(reason) => context.ignore_for(reason)?, + } + )* + + use $crate::IntoRunResult; + let result = $name(context); + IntoRunResult::into_run_result(result) } - )* + )) + ); + }; - use $crate::IntoRunResult; - let result = run(context); - IntoRunResult::into_run_result(result) - } - } + fn $name $($item)* }; }