From 2c710e066537cc14a955d97e0071c50ee83a739a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 5 Sep 2025 16:26:44 -0500 Subject: [PATCH 01/10] refactor(harness): Pull out 'main' --- crates/libtest2-harness/src/harness.rs | 86 ++++++++++++++------------ 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/crates/libtest2-harness/src/harness.rs b/crates/libtest2-harness/src/harness.rs index 15fa543..b06ff23 100644 --- a/crates/libtest2-harness/src/harness.rs +++ b/crates/libtest2-harness/src/harness.rs @@ -31,55 +31,59 @@ impl Harness { self } - pub fn main(mut self) -> ! { - let start = std::time::Instant::now(); - - 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) - }); + pub fn main(self) -> ! { + main(self.raw, self.cases) + } +} - #[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 self.cases, notifier.as_mut()).unwrap_or_else(|err| { +fn main(raw: std::io::Result>, mut cases: Vec>) -> ! { + let start = std::time::Instant::now(); + + 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(); From 4fd1552010ae506a0dfeb9d5f11ed798f87352ab Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 5 Sep 2025 16:33:31 -0500 Subject: [PATCH 02/10] fix(harness)!: Switch away from being a Builder --- crates/libtest2-harness/src/harness.rs | 6 +-- .../libtest2-mimic/examples/mimic-simple.rs | 14 ++--- crates/libtest2-mimic/examples/mimic-tidy.rs | 4 +- .../tests/testsuite/all_passing.rs | 14 ++--- .../libtest2-mimic/tests/testsuite/argfile.rs | 16 +++--- .../tests/testsuite/main_thread.rs | 16 +++--- .../tests/testsuite/mixed_bag.rs | 54 +++++++++---------- .../libtest2-mimic/tests/testsuite/panic.rs | 12 ++--- crates/libtest2/examples/tidy.rs | 4 +- crates/libtest2/src/lib.rs | 6 +-- 10 files changed, 74 insertions(+), 72 deletions(-) diff --git a/crates/libtest2-harness/src/harness.rs b/crates/libtest2-harness/src/harness.rs index b06ff23..41aa93d 100644 --- a/crates/libtest2-harness/src/harness.rs +++ b/crates/libtest2-harness/src/harness.rs @@ -19,16 +19,14 @@ 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(self) -> ! { diff --git a/crates/libtest2-mimic/examples/mimic-simple.rs b/crates/libtest2-mimic/examples/mimic-simple.rs index beaf47f..665f414 100644 --- a/crates/libtest2-mimic/examples/mimic-simple.rs +++ b/crates/libtest2-mimic/examples/mimic-simple.rs @@ -4,13 +4,13 @@ use libtest2_mimic::TestContext; use libtest2_mimic::Trial; fn main() { - libtest2_mimic::Harness::with_env() - .case(Trial::test("check_toph", check_toph)) - .case(Trial::test("check_katara", check_katara)) - .case(Trial::test("check_sokka", check_sokka)) - .case(Trial::test("long_computation", long_computation)) - .case(Trial::test("compile_fail_dummy", compile_fail_dummy)) - .main(); + let mut harness = libtest2_mimic::Harness::with_env(); + harness.case(Trial::test("check_toph", check_toph)); + harness.case(Trial::test("check_katara", check_katara)); + harness.case(Trial::test("check_sokka", check_sokka)); + harness.case(Trial::test("long_computation", long_computation)); + harness.case(Trial::test("compile_fail_dummy", compile_fail_dummy)); + harness.main(); } // Tests diff --git a/crates/libtest2-mimic/examples/mimic-tidy.rs b/crates/libtest2-mimic/examples/mimic-tidy.rs index 71f50b4..d273e7b 100644 --- a/crates/libtest2-mimic/examples/mimic-tidy.rs +++ b/crates/libtest2-mimic/examples/mimic-tidy.rs @@ -4,7 +4,9 @@ use libtest2_mimic::Trial; fn main() -> std::io::Result<()> { let tests = collect_tests()?; - libtest2_mimic::Harness::with_env().cases(tests).main() + let mut harness = libtest2_mimic::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-mimic/tests/testsuite/all_passing.rs b/crates/libtest2-mimic/tests/testsuite/all_passing.rs index 6438fe5..937e43e 100644 --- a/crates/libtest2-mimic/tests/testsuite/all_passing.rs +++ b/crates/libtest2-mimic/tests/testsuite/all_passing.rs @@ -9,13 +9,13 @@ fn test_cmd() -> snapbox::cmd::Command { r#" fn main() { use libtest2_mimic::Trial; - libtest2_mimic::Harness::with_env() - .cases(vec![ - Trial::test("foo", |_| Ok(())), - Trial::test("bar", |_| Ok(())), - Trial::test("barro", |_| Ok(())), - ]) - .main(); + let mut harness = libtest2_mimic::Harness::with_env(); + harness.cases(vec![ + Trial::test("foo", |_| Ok(())), + Trial::test("bar", |_| Ok(())), + Trial::test("barro", |_| Ok(())), + ]); + harness.main(); } "#, false, diff --git a/crates/libtest2-mimic/tests/testsuite/argfile.rs b/crates/libtest2-mimic/tests/testsuite/argfile.rs index 8d671db..fb5c62d 100644 --- a/crates/libtest2-mimic/tests/testsuite/argfile.rs +++ b/crates/libtest2-mimic/tests/testsuite/argfile.rs @@ -10,14 +10,14 @@ fn test_cmd() -> snapbox::cmd::Command { fn main() { use libtest2_mimic::Trial; use libtest2_mimic::RunError; - libtest2_mimic::Harness::with_env() - .cases(vec![ - Trial::test("one", |_| Ok(())), - Trial::test("two", |_| Ok(())), - Trial::test("three", |_| Ok(())), - Trial::test("one_two", |_| Ok(())), - ]) - .main(); + let mut harness = libtest2_mimic::Harness::with_env(); + harness.cases(vec![ + Trial::test("one", |_| Ok(())), + Trial::test("two", |_| Ok(())), + Trial::test("three", |_| Ok(())), + Trial::test("one_two", |_| Ok(())), + ]); + harness.main(); } "#, false, diff --git a/crates/libtest2-mimic/tests/testsuite/main_thread.rs b/crates/libtest2-mimic/tests/testsuite/main_thread.rs index 48cf9ed..869dd39 100644 --- a/crates/libtest2-mimic/tests/testsuite/main_thread.rs +++ b/crates/libtest2-mimic/tests/testsuite/main_thread.rs @@ -7,14 +7,14 @@ fn check_test_on_main_thread() { fn main() { use libtest2_mimic::Trial; let outer_thread = std::thread::current().id(); - libtest2_mimic::Harness::with_env() - .cases(vec![ - Trial::test("check", move |_| { - assert_eq!(outer_thread, std::thread::current().id()); - Ok(()) - }) - ]) - .main(); + let mut harness = libtest2_mimic::Harness::with_env(); + harness.cases(vec![ + Trial::test("check", move |_| { + assert_eq!(outer_thread, std::thread::current().id()); + Ok(()) + }) + ]); + harness.main(); } "#, false, diff --git a/crates/libtest2-mimic/tests/testsuite/mixed_bag.rs b/crates/libtest2-mimic/tests/testsuite/mixed_bag.rs index 7e36001..386988a 100644 --- a/crates/libtest2-mimic/tests/testsuite/mixed_bag.rs +++ b/crates/libtest2-mimic/tests/testsuite/mixed_bag.rs @@ -10,33 +10,33 @@ fn test_cmd() -> snapbox::cmd::Command { fn main() { use libtest2_mimic::Trial; use libtest2_mimic::RunError; - libtest2_mimic::Harness::with_env() - .cases(vec![ - Trial::test("cat", |_| Ok(())), - Trial::test("dog", |_| Err(RunError::fail("was not a good boy"))), - Trial::test("fox", |_| Ok(())), - Trial::test("bunny", |state| { - state.ignore_for("fails")?; - Err(RunError::fail("jumped too high")) - }), - Trial::test("frog", |state| { - state.ignore_for("slow")?; - Ok(()) - }), - Trial::test("owl", |state| { - state.ignore_for("fails")?; - Err(RunError::fail("broke neck")) - }), - Trial::test("fly", |state| { - state.ignore_for("fails")?; - Ok(()) - }), - Trial::test("bear", |state| { - state.ignore_for("fails")?; - Err(RunError::fail("no honey")) - }), - ]) - .main(); + let mut harness = libtest2_mimic::Harness::with_env(); + harness.cases(vec![ + Trial::test("cat", |_| Ok(())), + Trial::test("dog", |_| Err(RunError::fail("was not a good boy"))), + Trial::test("fox", |_| Ok(())), + Trial::test("bunny", |state| { + state.ignore_for("fails")?; + Err(RunError::fail("jumped too high")) + }), + Trial::test("frog", |state| { + state.ignore_for("slow")?; + Ok(()) + }), + Trial::test("owl", |state| { + state.ignore_for("fails")?; + Err(RunError::fail("broke neck")) + }), + Trial::test("fly", |state| { + state.ignore_for("fails")?; + Ok(()) + }), + Trial::test("bear", |state| { + state.ignore_for("fails")?; + Err(RunError::fail("no honey")) + }), + ]); + harness.main(); } "#, false, diff --git a/crates/libtest2-mimic/tests/testsuite/panic.rs b/crates/libtest2-mimic/tests/testsuite/panic.rs index 9d2db79..6234c1b 100644 --- a/crates/libtest2-mimic/tests/testsuite/panic.rs +++ b/crates/libtest2-mimic/tests/testsuite/panic.rs @@ -9,12 +9,12 @@ fn test_cmd() -> snapbox::cmd::Command { r#" fn main() { use libtest2_mimic::Trial; - libtest2_mimic::Harness::with_env() - .cases(vec![ - Trial::test("passes", |_| Ok(())), - Trial::test("panics", |_| panic!("uh oh")), - ]) - .main(); + let mut harness = libtest2_mimic::Harness::with_env(); + harness.cases(vec![ + Trial::test("passes", |_| Ok(())), + Trial::test("panics", |_| panic!("uh oh")), + ]); + harness.main(); } "#, false, 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(); } } } From 62dc6a58dfcde84819b4d01dec91634ea0fcf1cb Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 5 Sep 2025 16:39:25 -0500 Subject: [PATCH 03/10] fix(mimic)!: Create custom Harness --- crates/libtest2-mimic/src/lib.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/libtest2-mimic/src/lib.rs b/crates/libtest2-mimic/src/lib.rs index 6dfe36b..ebbb444 100644 --- a/crates/libtest2-mimic/src/lib.rs +++ b/crates/libtest2-mimic/src/lib.rs @@ -24,7 +24,6 @@ #![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; @@ -33,6 +32,36 @@ pub use libtest2_harness::TestKind; 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.harness.case(case) + } + + pub fn cases(&mut self, cases: impl IntoIterator) { + self.harness.cases(cases) + } + + pub fn main(self) -> ! { + self.harness.main() + } +} + pub struct Trial { name: String, #[allow(clippy::type_complexity)] From 33d047850714fa8fd1a035c1598aecd42a93268c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 5 Sep 2025 16:41:17 -0500 Subject: [PATCH 04/10] fix(mimic): Restore Builder API --- .../libtest2-mimic/examples/mimic-simple.rs | 14 ++--- crates/libtest2-mimic/examples/mimic-tidy.rs | 4 +- crates/libtest2-mimic/src/lib.rs | 10 ++-- .../tests/testsuite/all_passing.rs | 14 ++--- .../libtest2-mimic/tests/testsuite/argfile.rs | 16 +++--- .../tests/testsuite/main_thread.rs | 16 +++--- .../tests/testsuite/mixed_bag.rs | 54 +++++++++---------- .../libtest2-mimic/tests/testsuite/panic.rs | 12 ++--- 8 files changed, 70 insertions(+), 70 deletions(-) diff --git a/crates/libtest2-mimic/examples/mimic-simple.rs b/crates/libtest2-mimic/examples/mimic-simple.rs index 665f414..beaf47f 100644 --- a/crates/libtest2-mimic/examples/mimic-simple.rs +++ b/crates/libtest2-mimic/examples/mimic-simple.rs @@ -4,13 +4,13 @@ use libtest2_mimic::TestContext; use libtest2_mimic::Trial; fn main() { - let mut harness = libtest2_mimic::Harness::with_env(); - harness.case(Trial::test("check_toph", check_toph)); - harness.case(Trial::test("check_katara", check_katara)); - harness.case(Trial::test("check_sokka", check_sokka)); - harness.case(Trial::test("long_computation", long_computation)); - harness.case(Trial::test("compile_fail_dummy", compile_fail_dummy)); - harness.main(); + libtest2_mimic::Harness::with_env() + .case(Trial::test("check_toph", check_toph)) + .case(Trial::test("check_katara", check_katara)) + .case(Trial::test("check_sokka", check_sokka)) + .case(Trial::test("long_computation", long_computation)) + .case(Trial::test("compile_fail_dummy", compile_fail_dummy)) + .main(); } // Tests diff --git a/crates/libtest2-mimic/examples/mimic-tidy.rs b/crates/libtest2-mimic/examples/mimic-tidy.rs index d273e7b..71f50b4 100644 --- a/crates/libtest2-mimic/examples/mimic-tidy.rs +++ b/crates/libtest2-mimic/examples/mimic-tidy.rs @@ -4,9 +4,7 @@ use libtest2_mimic::Trial; fn main() -> std::io::Result<()> { let tests = collect_tests()?; - let mut harness = libtest2_mimic::Harness::with_env(); - harness.cases(tests); - harness.main() + libtest2_mimic::Harness::with_env().cases(tests).main() } /// Creates one test for each `.rs` file in the current directory or diff --git a/crates/libtest2-mimic/src/lib.rs b/crates/libtest2-mimic/src/lib.rs index ebbb444..a6f5c5a 100644 --- a/crates/libtest2-mimic/src/lib.rs +++ b/crates/libtest2-mimic/src/lib.rs @@ -49,12 +49,14 @@ impl Harness { } } - pub fn case(&mut self, case: Trial) { - self.harness.case(case) + pub fn case(mut self, case: Trial) -> Self { + self.harness.case(case); + self } - pub fn cases(&mut self, cases: impl IntoIterator) { - self.harness.cases(cases) + pub fn cases(mut self, cases: impl IntoIterator) -> Self { + self.harness.cases(cases); + self } pub fn main(self) -> ! { diff --git a/crates/libtest2-mimic/tests/testsuite/all_passing.rs b/crates/libtest2-mimic/tests/testsuite/all_passing.rs index 937e43e..6438fe5 100644 --- a/crates/libtest2-mimic/tests/testsuite/all_passing.rs +++ b/crates/libtest2-mimic/tests/testsuite/all_passing.rs @@ -9,13 +9,13 @@ fn test_cmd() -> snapbox::cmd::Command { r#" fn main() { use libtest2_mimic::Trial; - let mut harness = libtest2_mimic::Harness::with_env(); - harness.cases(vec![ - Trial::test("foo", |_| Ok(())), - Trial::test("bar", |_| Ok(())), - Trial::test("barro", |_| Ok(())), - ]); - harness.main(); + libtest2_mimic::Harness::with_env() + .cases(vec![ + Trial::test("foo", |_| Ok(())), + Trial::test("bar", |_| Ok(())), + Trial::test("barro", |_| Ok(())), + ]) + .main(); } "#, false, diff --git a/crates/libtest2-mimic/tests/testsuite/argfile.rs b/crates/libtest2-mimic/tests/testsuite/argfile.rs index fb5c62d..8d671db 100644 --- a/crates/libtest2-mimic/tests/testsuite/argfile.rs +++ b/crates/libtest2-mimic/tests/testsuite/argfile.rs @@ -10,14 +10,14 @@ fn test_cmd() -> snapbox::cmd::Command { fn main() { use libtest2_mimic::Trial; use libtest2_mimic::RunError; - let mut harness = libtest2_mimic::Harness::with_env(); - harness.cases(vec![ - Trial::test("one", |_| Ok(())), - Trial::test("two", |_| Ok(())), - Trial::test("three", |_| Ok(())), - Trial::test("one_two", |_| Ok(())), - ]); - harness.main(); + libtest2_mimic::Harness::with_env() + .cases(vec![ + Trial::test("one", |_| Ok(())), + Trial::test("two", |_| Ok(())), + Trial::test("three", |_| Ok(())), + Trial::test("one_two", |_| Ok(())), + ]) + .main(); } "#, false, diff --git a/crates/libtest2-mimic/tests/testsuite/main_thread.rs b/crates/libtest2-mimic/tests/testsuite/main_thread.rs index 869dd39..48cf9ed 100644 --- a/crates/libtest2-mimic/tests/testsuite/main_thread.rs +++ b/crates/libtest2-mimic/tests/testsuite/main_thread.rs @@ -7,14 +7,14 @@ fn check_test_on_main_thread() { fn main() { use libtest2_mimic::Trial; let outer_thread = std::thread::current().id(); - let mut harness = libtest2_mimic::Harness::with_env(); - harness.cases(vec![ - Trial::test("check", move |_| { - assert_eq!(outer_thread, std::thread::current().id()); - Ok(()) - }) - ]); - harness.main(); + libtest2_mimic::Harness::with_env() + .cases(vec![ + Trial::test("check", move |_| { + assert_eq!(outer_thread, std::thread::current().id()); + Ok(()) + }) + ]) + .main(); } "#, false, diff --git a/crates/libtest2-mimic/tests/testsuite/mixed_bag.rs b/crates/libtest2-mimic/tests/testsuite/mixed_bag.rs index 386988a..7e36001 100644 --- a/crates/libtest2-mimic/tests/testsuite/mixed_bag.rs +++ b/crates/libtest2-mimic/tests/testsuite/mixed_bag.rs @@ -10,33 +10,33 @@ fn test_cmd() -> snapbox::cmd::Command { fn main() { use libtest2_mimic::Trial; use libtest2_mimic::RunError; - let mut harness = libtest2_mimic::Harness::with_env(); - harness.cases(vec![ - Trial::test("cat", |_| Ok(())), - Trial::test("dog", |_| Err(RunError::fail("was not a good boy"))), - Trial::test("fox", |_| Ok(())), - Trial::test("bunny", |state| { - state.ignore_for("fails")?; - Err(RunError::fail("jumped too high")) - }), - Trial::test("frog", |state| { - state.ignore_for("slow")?; - Ok(()) - }), - Trial::test("owl", |state| { - state.ignore_for("fails")?; - Err(RunError::fail("broke neck")) - }), - Trial::test("fly", |state| { - state.ignore_for("fails")?; - Ok(()) - }), - Trial::test("bear", |state| { - state.ignore_for("fails")?; - Err(RunError::fail("no honey")) - }), - ]); - harness.main(); + libtest2_mimic::Harness::with_env() + .cases(vec![ + Trial::test("cat", |_| Ok(())), + Trial::test("dog", |_| Err(RunError::fail("was not a good boy"))), + Trial::test("fox", |_| Ok(())), + Trial::test("bunny", |state| { + state.ignore_for("fails")?; + Err(RunError::fail("jumped too high")) + }), + Trial::test("frog", |state| { + state.ignore_for("slow")?; + Ok(()) + }), + Trial::test("owl", |state| { + state.ignore_for("fails")?; + Err(RunError::fail("broke neck")) + }), + Trial::test("fly", |state| { + state.ignore_for("fails")?; + Ok(()) + }), + Trial::test("bear", |state| { + state.ignore_for("fails")?; + Err(RunError::fail("no honey")) + }), + ]) + .main(); } "#, false, diff --git a/crates/libtest2-mimic/tests/testsuite/panic.rs b/crates/libtest2-mimic/tests/testsuite/panic.rs index 6234c1b..9d2db79 100644 --- a/crates/libtest2-mimic/tests/testsuite/panic.rs +++ b/crates/libtest2-mimic/tests/testsuite/panic.rs @@ -9,12 +9,12 @@ fn test_cmd() -> snapbox::cmd::Command { r#" fn main() { use libtest2_mimic::Trial; - let mut harness = libtest2_mimic::Harness::with_env(); - harness.cases(vec![ - Trial::test("passes", |_| Ok(())), - Trial::test("panics", |_| panic!("uh oh")), - ]); - harness.main(); + libtest2_mimic::Harness::with_env() + .cases(vec![ + Trial::test("passes", |_| Ok(())), + Trial::test("panics", |_| panic!("uh oh")), + ]) + .main(); } "#, false, From 8c08e746f74abfb561172a22e1408951dfad8195 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 5 Sep 2025 16:43:07 -0500 Subject: [PATCH 05/10] refactor(mimic): Remove rarely used imports --- crates/libtest2-mimic/src/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/libtest2-mimic/src/lib.rs b/crates/libtest2-mimic/src/lib.rs index a6f5c5a..b52df90 100644 --- a/crates/libtest2-mimic/src/lib.rs +++ b/crates/libtest2-mimic/src/lib.rs @@ -29,9 +29,6 @@ pub use libtest2_harness::RunResult; pub use libtest2_harness::TestContext; pub use libtest2_harness::TestKind; -use libtest2_harness::Case; -use libtest2_harness::Source; - pub struct Harness { harness: libtest2_harness::Harness, } @@ -82,14 +79,14 @@ impl Trial { } } -impl Case for Trial { +impl libtest2_harness::Case for Trial { fn name(&self) -> &str { &self.name } fn kind(&self) -> TestKind { Default::default() } - fn source(&self) -> Option<&Source> { + fn source(&self) -> Option<&libtest2_harness::Source> { None } fn exclusive(&self, _: &TestContext) -> bool { From ff56f0f47c9123ba5b9f933e3ea8742116bbe8aa Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 5 Sep 2025 16:44:44 -0500 Subject: [PATCH 06/10] fix(mimic): Remove unused `pub` re-export --- crates/libtest2-mimic/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/libtest2-mimic/src/lib.rs b/crates/libtest2-mimic/src/lib.rs index b52df90..6854b57 100644 --- a/crates/libtest2-mimic/src/lib.rs +++ b/crates/libtest2-mimic/src/lib.rs @@ -27,7 +27,6 @@ pub use libtest2_harness::RunError; pub use libtest2_harness::RunResult; pub use libtest2_harness::TestContext; -pub use libtest2_harness::TestKind; pub struct Harness { harness: libtest2_harness::Harness, @@ -83,7 +82,7 @@ impl libtest2_harness::Case for Trial { fn name(&self) -> &str { &self.name } - fn kind(&self) -> TestKind { + fn kind(&self) -> libtest2_harness::TestKind { Default::default() } fn source(&self) -> Option<&libtest2_harness::Source> { From 1579c1f617e4f728c8543d28783df9c78d9f0235 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 10 Sep 2025 14:20:36 -0500 Subject: [PATCH 07/10] fix(mimic)!: Create custom TestContext --- .../libtest2-mimic/examples/mimic-simple.rs | 10 +++---- crates/libtest2-mimic/src/lib.rs | 30 +++++++++++++++---- 2 files changed, 29 insertions(+), 11 deletions(-) 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 6854b57..15a886d 100644 --- a/crates/libtest2-mimic/src/lib.rs +++ b/crates/libtest2-mimic/src/lib.rs @@ -26,7 +26,6 @@ pub use libtest2_harness::RunError; pub use libtest2_harness::RunResult; -pub use libtest2_harness::TestContext; pub struct Harness { harness: libtest2_harness::Harness, @@ -63,13 +62,13 @@ impl Harness { 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(), @@ -88,12 +87,31 @@ impl libtest2_harness::Case for Trial { 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<(), RunError> { + (self.runner)(TestContext { inner: context }) + } +} + +#[derive(Debug)] +pub struct TestContext<'t> { + inner: &'t libtest2_harness::TestContext, +} + +impl<'t> TestContext<'t> { + pub fn ignore(&self) -> Result<(), RunError> { + self.inner.ignore() + } + + pub fn ignore_for(&self, reason: impl std::fmt::Display) -> Result<(), RunError> { + self.inner.ignore_for(reason) + } + + pub fn current_mode(&self) -> libtest2_harness::RunMode { + self.inner.current_mode() } } From 6130e0239f6ad261930e345aaf423a80aa1065a2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 10 Sep 2025 14:25:26 -0500 Subject: [PATCH 08/10] fix(mimic): Re-export RunMode --- Cargo.lock | 1 + crates/libtest2-mimic/Cargo.toml | 1 + crates/libtest2-mimic/src/lib.rs | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) 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-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/src/lib.rs b/crates/libtest2-mimic/src/lib.rs index 15a886d..285d79e 100644 --- a/crates/libtest2-mimic/src/lib.rs +++ b/crates/libtest2-mimic/src/lib.rs @@ -26,6 +26,7 @@ pub use libtest2_harness::RunError; pub use libtest2_harness::RunResult; +pub use libtest_json::RunMode; pub struct Harness { harness: libtest2_harness::Harness, @@ -110,7 +111,7 @@ impl<'t> TestContext<'t> { self.inner.ignore_for(reason) } - pub fn current_mode(&self) -> libtest2_harness::RunMode { + pub fn current_mode(&self) -> RunMode { self.inner.current_mode() } } From 4c45db5c1884a457f7ac5da83784f76f4dfd3248 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 10 Sep 2025 14:29:55 -0500 Subject: [PATCH 09/10] fix(mimic)!: Create custom RunError/RunResult --- crates/libtest2-mimic/src/lib.rs | 36 ++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/crates/libtest2-mimic/src/lib.rs b/crates/libtest2-mimic/src/lib.rs index 285d79e..d63f611 100644 --- a/crates/libtest2-mimic/src/lib.rs +++ b/crates/libtest2-mimic/src/lib.rs @@ -24,8 +24,6 @@ #![warn(clippy::print_stderr)] #![warn(clippy::print_stdout)] -pub use libtest2_harness::RunError; -pub use libtest2_harness::RunResult; pub use libtest_json::RunMode; pub struct Harness { @@ -92,8 +90,32 @@ impl libtest2_harness::Case for Trial { false } - fn run(&self, context: &libtest2_harness::TestContext) -> Result<(), RunError> { - (self.runner)(TestContext { inner: context }) + fn run( + &self, + context: &libtest2_harness::TestContext, + ) -> Result<(), libtest2_harness::RunError> { + (self.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), + } } } @@ -104,11 +126,13 @@ pub struct TestContext<'t> { impl<'t> TestContext<'t> { pub fn ignore(&self) -> Result<(), RunError> { - self.inner.ignore() + 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) + self.inner + .ignore_for(reason) + .map_err(|e| RunError { inner: e }) } pub fn current_mode(&self) -> RunMode { From deebe88ee9399d60b1408d6085e0133990a2127c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 10 Sep 2025 14:31:54 -0500 Subject: [PATCH 10/10] fix(mimic)!: Drop impl Case for Trial --- crates/libtest2-mimic/src/lib.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/libtest2-mimic/src/lib.rs b/crates/libtest2-mimic/src/lib.rs index d63f611..d2456de 100644 --- a/crates/libtest2-mimic/src/lib.rs +++ b/crates/libtest2-mimic/src/lib.rs @@ -44,12 +44,13 @@ impl Harness { } pub fn case(mut self, case: Trial) -> Self { - self.harness.case(case); + self.harness.case(TrialCase { inner: case }); self } pub fn cases(mut self, cases: impl IntoIterator) -> Self { - self.harness.cases(cases); + self.harness + .cases(cases.into_iter().map(|c| TrialCase { inner: c })); self } @@ -76,9 +77,13 @@ impl Trial { } } -impl libtest2_harness::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) -> libtest2_harness::TestKind { Default::default() @@ -94,7 +99,7 @@ impl libtest2_harness::Case for Trial { &self, context: &libtest2_harness::TestContext, ) -> Result<(), libtest2_harness::RunError> { - (self.runner)(TestContext { inner: context }).map_err(|e| e.inner) + (self.inner.runner)(TestContext { inner: context }).map_err(|e| e.inner) } }