Skip to content
Merged
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
67 changes: 60 additions & 7 deletions crates/libtest2-mimic/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
//! An experimental replacement for libtest-mimic
//! An experimental replacement for
//! [libtest-mimic](https://docs.rs/libtest-mimic/latest/libtest_mimic/)
//!
//! Write your own tests that look and behave like built-in tests!
//!
//! This is a simple and small test harness that mimics the original `libtest`
//! (used by `cargo test`/`rustc --test`). That means: all output looks pretty
//! much like `cargo test` and most CLI arguments are understood and used. With
//! that plumbing work out of the way, your test runner can focus on the actual
//! testing.
//!
//! For a small real world example, see [`examples/mimic-tidy.rs`][1].
//!
//! [1]: https://github.com/assert-rs/libtest2/blob/main/crates/libtest2-mimic/examples/mimic-tidy.rs
//!
//! # Usage
//!
Expand All @@ -15,10 +28,37 @@
//! And in `tests/mytest.rs` you would call [`Harness::main`] in the `main` function:
//!
//! ```no_run
//! libtest2_mimic::Harness::with_env()
//! # use libtest2_mimic::Trial;
//! # use libtest2_mimic::Harness;
//! # use libtest2_mimic::RunError;
//! Harness::with_env()
//! .discover([
//! Trial::test("succeeding_test", move |_| Ok(())),
//! Trial::test("failing_test", move |_| Err(RunError::fail("Woops"))),
//! ])
//! .main();
//! ```
//! Instead of returning `Ok` or `Err` directly, you want to actually perform
//! your tests, of course. See [`Trial::test`] for more information on how to
//! define a test. You can of course list all your tests manually. But in many
//! cases it is useful to generate one test per file in a directory, for
//! example.
//!
//! You can then run `cargo test --test mytest` to run it. To see the CLI
//! arguments supported by this crate, run `cargo test --test mytest -- -h`.
//!
//! # Known limitations and differences to the official test harness
//!
//! `libtest2-mimic` aims to be fully compatible with stable, non-deprecated parts of `libtest`
//! but there are differences for now.
//!
//! Some of the notable differences:
//!
//! - Output capture and `--no-capture`: simply not supported. The official
//! `libtest` uses internal `std` functions to temporarily redirect output.
//! `libtest-mimic` cannot use those, see also [libtest2#12](https://github.com/assert-rs/libtest2/issues/12)
//! - `--format=json` (unstable): our schema is part of an experiment to see what should be
//! stabilized for `libtest`, see also [libtest2#42](https://github.com/assert-rs/libtest2/issues/42)

#![cfg_attr(docsrs, feature(doc_auto_cfg))]
//#![warn(clippy::print_stderr)]
Expand All @@ -30,23 +70,27 @@ pub struct Harness {
}

impl Harness {
/// Read the process's CLI arguments
pub fn with_env() -> Self {
let raw = std::env::args_os();
Self::with_args(raw)
}

/// Manually specify CLI arguments
pub fn with_args(args: impl IntoIterator<Item = impl Into<std::ffi::OsString>>) -> Self {
Self {
raw: args.into_iter().map(|a| a.into()).collect(),
cases: Vec::new(),
}
}

pub fn with_env() -> Self {
let raw = std::env::args_os();
Self::with_args(raw)
}

/// Enumerate all test [`Trial`]s
pub fn discover(mut self, cases: impl IntoIterator<Item = Trial>) -> Self {
self.cases.extend(cases);
self
}

/// Perform the tests and exit
pub fn main(self) -> ! {
match self.run() {
Ok(true) => std::process::exit(0),
Expand Down Expand Up @@ -79,6 +123,7 @@ impl Harness {
}
}

/// A test case to be run
pub struct Trial {
name: String,
#[allow(clippy::type_complexity)]
Expand Down Expand Up @@ -149,10 +194,18 @@ pub struct RunContext<'t> {
}

impl<'t> RunContext<'t> {
/// Request this test to be ignored
///
/// May be overridden by the CLI
///
/// **Note:** prefer [`RunContext::ignore_for`]
pub fn ignore(&self) -> Result<(), RunError> {
self.inner.ignore().map_err(|e| RunError { inner: e })
}

/// Request this test to be ignored
///
/// May be overridden by the CLI
pub fn ignore_for(&self, reason: impl std::fmt::Display) -> Result<(), RunError> {
self.inner
.ignore_for(reason)
Expand Down
Loading