diff --git a/Cargo.lock b/Cargo.lock index 1f19322..851156b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -265,6 +265,7 @@ version = "0.0.1" dependencies = [ "dunce", "escargot", + "libtest-json", "libtest2-harness", "once_cell_polyfill", "pathdiff", diff --git a/crates/libtest2-harness/src/harness.rs b/crates/libtest2-harness/src/harness.rs index 15fa543..41aa93d 100644 --- a/crates/libtest2-harness/src/harness.rs +++ b/crates/libtest2-harness/src/harness.rs @@ -19,67 +19,69 @@ impl Harness { Self { raw, cases: vec![] } } - pub fn case(mut self, case: impl Case + 'static) -> Self { + pub fn case(&mut self, case: impl Case + 'static) { self.cases.push(Box::new(case)); - self } - pub fn cases(mut self, cases: impl IntoIterator) -> Self { + pub fn cases(&mut self, cases: impl IntoIterator) { for case in cases { self.cases.push(Box::new(case)); } - self } - pub fn main(mut self) -> ! { - let start = std::time::Instant::now(); + pub fn main(self) -> ! { + main(self.raw, self.cases) + } +} - let raw = match self.raw { - Ok(raw) => raw, - Err(err) => { - eprintln!("{err}"); - std::process::exit(1) - } - }; - let mut parser = cli::Parser::new(&raw); - let opts = parse(&mut parser).unwrap_or_else(|err| { - eprintln!("{err}"); - std::process::exit(1) - }); +const ERROR_EXIT_CODE: i32 = 101; - #[cfg(feature = "color")] - match opts.color { - libtest_lexarg::ColorConfig::AutoColor => anstream::ColorChoice::Auto, - libtest_lexarg::ColorConfig::AlwaysColor => anstream::ColorChoice::Always, - libtest_lexarg::ColorConfig::NeverColor => anstream::ColorChoice::Never, - } - .write_global(); +fn main(raw: std::io::Result>, mut cases: Vec>) -> ! { + let start = std::time::Instant::now(); - let mut notifier = notifier(&opts).unwrap_or_else(|err| { - eprintln!("{err}"); - std::process::exit(1) - }); - discover(&start, &opts, &mut self.cases, notifier.as_mut()).unwrap_or_else(|err| { + let raw = match raw { + Ok(raw) => raw, + Err(err) => { eprintln!("{err}"); std::process::exit(1) - }); - - if !opts.list { - match run(&start, &opts, self.cases, notifier.as_mut()) { - Ok(true) => {} - Ok(false) => std::process::exit(ERROR_EXIT_CODE), - Err(e) => { - eprintln!("error: io error when listing tests: {e:?}"); - std::process::exit(ERROR_EXIT_CODE) - } - } } + }; + let mut parser = cli::Parser::new(&raw); + let opts = parse(&mut parser).unwrap_or_else(|err| { + eprintln!("{err}"); + std::process::exit(1) + }); - std::process::exit(0) + #[cfg(feature = "color")] + match opts.color { + libtest_lexarg::ColorConfig::AutoColor => anstream::ColorChoice::Auto, + libtest_lexarg::ColorConfig::AlwaysColor => anstream::ColorChoice::Always, + libtest_lexarg::ColorConfig::NeverColor => anstream::ColorChoice::Never, } -} + .write_global(); -const ERROR_EXIT_CODE: i32 = 101; + let mut notifier = notifier(&opts).unwrap_or_else(|err| { + eprintln!("{err}"); + std::process::exit(1) + }); + discover(&start, &opts, &mut cases, notifier.as_mut()).unwrap_or_else(|err| { + eprintln!("{err}"); + std::process::exit(1) + }); + + if !opts.list { + match run(&start, &opts, cases, notifier.as_mut()) { + Ok(true) => {} + Ok(false) => std::process::exit(ERROR_EXIT_CODE), + Err(e) => { + eprintln!("error: io error when listing tests: {e:?}"); + std::process::exit(ERROR_EXIT_CODE) + } + } + } + + std::process::exit(0) +} fn parse<'p>(parser: &mut cli::Parser<'p>) -> Result> { let mut test_opts = libtest_lexarg::TestOptsBuilder::new(); diff --git a/crates/libtest2-mimic/Cargo.toml b/crates/libtest2-mimic/Cargo.toml index 8cea637..0cdda45 100644 --- a/crates/libtest2-mimic/Cargo.toml +++ b/crates/libtest2-mimic/Cargo.toml @@ -30,6 +30,7 @@ json = ["libtest2-harness/json"] threads = ["libtest2-harness/threads"] [dependencies] +libtest-json = { version = "0.0.1", path = "../libtest-json" } libtest2-harness = { version = "0.0.1", path = "../libtest2-harness" } [dev-dependencies] diff --git a/crates/libtest2-mimic/examples/mimic-simple.rs b/crates/libtest2-mimic/examples/mimic-simple.rs index beaf47f..a60f10c 100644 --- a/crates/libtest2-mimic/examples/mimic-simple.rs +++ b/crates/libtest2-mimic/examples/mimic-simple.rs @@ -15,21 +15,21 @@ fn main() { // Tests -fn check_toph(_context: &TestContext) -> RunResult { +fn check_toph(_context: TestContext<'_>) -> RunResult { Ok(()) } -fn check_katara(_context: &TestContext) -> RunResult { +fn check_katara(_context: TestContext<'_>) -> RunResult { Ok(()) } -fn check_sokka(_context: &TestContext) -> RunResult { +fn check_sokka(_context: TestContext<'_>) -> RunResult { Err(RunError::fail("Sokka tripped and fell :(")) } -fn long_computation(context: &TestContext) -> RunResult { +fn long_computation(context: TestContext<'_>) -> RunResult { context.ignore_for("slow")?; std::thread::sleep(std::time::Duration::from_secs(1)); Ok(()) } -fn compile_fail_dummy(_context: &TestContext) -> RunResult { +fn compile_fail_dummy(_context: TestContext<'_>) -> RunResult { Ok(()) } diff --git a/crates/libtest2-mimic/src/lib.rs b/crates/libtest2-mimic/src/lib.rs index 6dfe36b..d2456de 100644 --- a/crates/libtest2-mimic/src/lib.rs +++ b/crates/libtest2-mimic/src/lib.rs @@ -24,25 +24,51 @@ #![warn(clippy::print_stderr)] #![warn(clippy::print_stdout)] -pub use libtest2_harness::Harness; -pub use libtest2_harness::RunError; -pub use libtest2_harness::RunResult; -pub use libtest2_harness::TestContext; -pub use libtest2_harness::TestKind; +pub use libtest_json::RunMode; -use libtest2_harness::Case; -use libtest2_harness::Source; +pub struct Harness { + harness: libtest2_harness::Harness, +} + +impl Harness { + pub fn with_args(args: impl IntoIterator>) -> Self { + Self { + harness: libtest2_harness::Harness::with_args(args), + } + } + + pub fn with_env() -> Self { + Self { + harness: libtest2_harness::Harness::with_env(), + } + } + + pub fn case(mut self, case: Trial) -> Self { + self.harness.case(TrialCase { inner: case }); + self + } + + pub fn cases(mut self, cases: impl IntoIterator) -> Self { + self.harness + .cases(cases.into_iter().map(|c| TrialCase { inner: c })); + self + } + + pub fn main(self) -> ! { + self.harness.main() + } +} pub struct Trial { name: String, #[allow(clippy::type_complexity)] - runner: Box Result<(), RunError> + Send + Sync>, + runner: Box) -> Result<(), RunError> + Send + Sync>, } impl Trial { pub fn test( name: impl Into, - runner: impl Fn(&TestContext) -> Result<(), RunError> + Send + Sync + 'static, + runner: impl Fn(TestContext<'_>) -> Result<(), RunError> + Send + Sync + 'static, ) -> Self { Self { name: name.into(), @@ -51,22 +77,71 @@ impl Trial { } } -impl Case for Trial { +struct TrialCase { + inner: Trial, +} + +impl libtest2_harness::Case for TrialCase { fn name(&self) -> &str { - &self.name + &self.inner.name } - fn kind(&self) -> TestKind { + fn kind(&self) -> libtest2_harness::TestKind { Default::default() } - fn source(&self) -> Option<&Source> { + fn source(&self) -> Option<&libtest2_harness::Source> { None } - fn exclusive(&self, _: &TestContext) -> bool { + fn exclusive(&self, _: &libtest2_harness::TestContext) -> bool { false } - fn run(&self, context: &TestContext) -> Result<(), RunError> { - (self.runner)(context) + fn run( + &self, + context: &libtest2_harness::TestContext, + ) -> Result<(), libtest2_harness::RunError> { + (self.inner.runner)(TestContext { inner: context }).map_err(|e| e.inner) + } +} + +pub type RunResult = Result<(), RunError>; + +#[derive(Debug)] +pub struct RunError { + inner: libtest2_harness::RunError, +} + +impl RunError { + pub fn with_cause(cause: impl std::error::Error + Send + Sync + 'static) -> Self { + Self { + inner: libtest2_harness::RunError::with_cause(cause), + } + } + + pub fn fail(cause: impl std::fmt::Display) -> Self { + Self { + inner: libtest2_harness::RunError::fail(cause), + } + } +} + +#[derive(Debug)] +pub struct TestContext<'t> { + inner: &'t libtest2_harness::TestContext, +} + +impl<'t> TestContext<'t> { + pub fn ignore(&self) -> Result<(), RunError> { + self.inner.ignore().map_err(|e| RunError { inner: e }) + } + + pub fn ignore_for(&self, reason: impl std::fmt::Display) -> Result<(), RunError> { + self.inner + .ignore_for(reason) + .map_err(|e| RunError { inner: e }) + } + + pub fn current_mode(&self) -> RunMode { + self.inner.current_mode() } } diff --git a/crates/libtest2/examples/tidy.rs b/crates/libtest2/examples/tidy.rs index 47379e4..9aecc30 100644 --- a/crates/libtest2/examples/tidy.rs +++ b/crates/libtest2/examples/tidy.rs @@ -4,7 +4,9 @@ use libtest2::Trial; fn main() -> std::io::Result<()> { let tests = collect_tests()?; - libtest2::Harness::with_env().cases(tests).main() + let mut harness = libtest2::Harness::with_env(); + harness.cases(tests); + harness.main() } /// Creates one test for each `.rs` file in the current directory or diff --git a/crates/libtest2/src/lib.rs b/crates/libtest2/src/lib.rs index 0c21b0b..3ac52ba 100644 --- a/crates/libtest2/src/lib.rs +++ b/crates/libtest2/src/lib.rs @@ -75,9 +75,9 @@ impl Case for Trial { macro_rules! libtest2_main { ( $( $test:path ),* $(,)*) => { fn main() { - ::libtest2::Harness::with_env() - $(.case(::libtest2::Trial::test(::std::stringify!($test), $test)))* - .main(); + let mut harness = ::libtest2::Harness::with_env(); + $(harness.case(::libtest2::Trial::test(::std::stringify!($test), $test));)* + harness.main(); } } }