From 8e26ddb9cd402d8b0786cf3934fbd9cf6718df16 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 22 Apr 2024 21:39:06 -0500 Subject: [PATCH 1/3] feat(fn)!: Split Harness out into tryfn --- Cargo.lock | 11 ++++- crates/snapbox/Cargo.toml | 5 --- crates/snapbox/src/assert/mod.rs | 8 +++- crates/snapbox/src/lib.rs | 36 ----------------- crates/tryfn/CHANGELOG.md | 11 +++++ crates/tryfn/Cargo.toml | 40 +++++++++++++++++++ crates/tryfn/LICENSE-APACHE | 1 + crates/tryfn/LICENSE-MIT | 1 + crates/tryfn/README.md | 26 ++++++++++++ .../src/harness.rs => tryfn/src/lib.rs} | 32 +++++++-------- 10 files changed, 109 insertions(+), 62 deletions(-) create mode 100644 crates/tryfn/CHANGELOG.md create mode 100644 crates/tryfn/Cargo.toml create mode 120000 crates/tryfn/LICENSE-APACHE create mode 120000 crates/tryfn/LICENSE-MIT create mode 100644 crates/tryfn/README.md rename crates/{snapbox/src/harness.rs => tryfn/src/lib.rs} (87%) diff --git a/Cargo.lock b/Cargo.lock index 450d44fb..657366c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -885,9 +885,7 @@ dependencies = [ "dunce", "escargot", "filetime", - "ignore", "libc", - "libtest-mimic", "normalize-line-endings", "os_pipe", "regex", @@ -1017,6 +1015,15 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "tryfn" +version = "0.1.0" +dependencies = [ + "ignore", + "libtest-mimic", + "snapbox", +] + [[package]] name = "unicode-ident" version = "1.0.3" diff --git a/crates/snapbox/Cargo.toml b/crates/snapbox/Cargo.toml index a12a73e5..8d62bdf3 100644 --- a/crates/snapbox/Cargo.toml +++ b/crates/snapbox/Cargo.toml @@ -32,8 +32,6 @@ default = ["color-auto", "diff"] #! Feature Flags -## Simple input/output test harness -harness = ["dep:libtest-mimic", "dep:ignore"] ## Smarter binary file detection detect-encoding = ["dep:content_inspector"] ## Snapshotting of paths @@ -71,9 +69,6 @@ name = "snap-fixture" # For `snapbox`s tests only normalize-line-endings = "0.3.0" snapbox-macros = { path = "../snapbox-macros", version = "0.3.8" } -libtest-mimic = { version = "0.7.0", optional = true } -ignore = { version = "0.4", optional = true } - content_inspector = { version = "0.2.4", optional = true } tempfile = { version = "3.0", optional = true } diff --git a/crates/snapbox/src/assert/mod.rs b/crates/snapbox/src/assert/mod.rs index 2c986c4e..8031595e 100644 --- a/crates/snapbox/src/assert/mod.rs +++ b/crates/snapbox/src/assert/mod.rs @@ -77,7 +77,7 @@ impl Assert { } } - pub(crate) fn try_eq( + pub fn try_eq( &self, expected: crate::Data, actual: crate::Data, @@ -397,6 +397,12 @@ impl Assert { } } +impl Assert { + pub fn selected_action(&self) -> Action { + self.action + } +} + impl Default for Assert { fn default() -> Self { Self { diff --git a/crates/snapbox/src/lib.rs b/crates/snapbox/src/lib.rs index 2ce67dfe..29476730 100644 --- a/crates/snapbox/src/lib.rs +++ b/crates/snapbox/src/lib.rs @@ -27,7 +27,6 @@ //! //! Testing Functions: //! - [`assert_eq`][crate::assert_eq()] for quick and dirty snapshotting -//! - [`harness::Harness`] for discovering test inputs and asserting against snapshot files: //! //! Testing Commands: //! - [`cmd::Command`]: Process spawning for testing of non-interactive commands @@ -58,38 +57,6 @@ //! .eq(snapbox::file!["help_output_is_clean.txt"], actual); //! ``` //! -//! [`harness::Harness`] -#![cfg_attr(not(feature = "harness"), doc = " ```rust,ignore")] -#![cfg_attr(feature = "harness", doc = " ```rust,no_run")] -//! snapbox::harness::Harness::new( -//! "tests/fixtures/invalid", -//! setup, -//! test, -//! ) -//! .select(["tests/cases/*.in"]) -//! .action_env("SNAPSHOTS") -//! .test(); -//! -//! fn setup(input_path: std::path::PathBuf) -> snapbox::harness::Case { -//! let name = input_path.file_name().unwrap().to_str().unwrap().to_owned(); -//! let expected = snapbox::Data::read_from(&input_path.with_extension("out"), None); -//! snapbox::harness::Case { -//! name, -//! fixture: input_path, -//! expected, -//! } -//! } -//! -//! fn test(input_path: &std::path::Path) -> Result> { -//! let raw = std::fs::read_to_string(input_path)?; -//! let num = raw.parse::()?; -//! -//! let actual = num + 10; -//! -//! Ok(actual) -//! } -//! ``` -//! //! [trycmd]: https://docs.rs/trycmd #![cfg_attr(docsrs, feature(doc_auto_cfg))] @@ -104,9 +71,6 @@ pub mod path; pub mod report; pub mod utils; -#[cfg(feature = "harness")] -pub mod harness; - pub use assert::Assert; pub use data::Data; pub use data::IntoData; diff --git a/crates/tryfn/CHANGELOG.md b/crates/tryfn/CHANGELOG.md new file mode 100644 index 00000000..1c71609d --- /dev/null +++ b/crates/tryfn/CHANGELOG.md @@ -0,0 +1,11 @@ +# Change Log +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + + +## [Unreleased] - ReleaseDate + + +[Unreleased]: https://github.com/assert-rs/trycmd/compare/3e293f6f6167270d85f57a7b59fd94590af6fa97...HEAD diff --git a/crates/tryfn/Cargo.toml b/crates/tryfn/Cargo.toml new file mode 100644 index 00000000..ada42991 --- /dev/null +++ b/crates/tryfn/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "tryfn" +version = "0.1.0" +description = "File-driven snapshot testing for a function" +authors = ["Ed Page "] +repository = "https://github.com/assert-rs/trycmd.git" +homepage = "https://github.com/assert-rs/trycmd" +documentation = "http://docs.rs/tryfn/" +readme = "README.md" +categories = ["development-tools::testing"] +keywords = ["test", "assert", "snapsjot"] +license.workspace = true +edition.workspace = true +rust-version.workspace = true +include.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] + +[package.metadata.release] +pre-release-replacements = [ + {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, + {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, + {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/assert-rs/trycmd/compare/{{tag_name}}...HEAD", exactly=1}, +] + +[features] +default = ["color-auto", "diff"] +diff = ["snapbox/diff"] +color = ["snapbox/color"] +color-auto = ["snapbox/color-auto"] + +[dependencies] +snapbox = { path = "../snapbox", version = "0.5.9", default-features = false } +libtest-mimic = "0.7.0" +ignore = "0.4" diff --git a/crates/tryfn/LICENSE-APACHE b/crates/tryfn/LICENSE-APACHE new file mode 120000 index 00000000..1cd601d0 --- /dev/null +++ b/crates/tryfn/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/tryfn/LICENSE-MIT b/crates/tryfn/LICENSE-MIT new file mode 120000 index 00000000..b2cfbdc7 --- /dev/null +++ b/crates/tryfn/LICENSE-MIT @@ -0,0 +1 @@ +../../LICENSE-MIT \ No newline at end of file diff --git a/crates/tryfn/README.md b/crates/tryfn/README.md new file mode 100644 index 00000000..9a6c44a9 --- /dev/null +++ b/crates/tryfn/README.md @@ -0,0 +1,26 @@ +# tryfn + +> File-driven snapshot testing for a function + +[![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] +![License](https://img.shields.io/crates/l/tryfn.svg) +[![Crates Status](https://img.shields.io/crates/v/tryfn.svg)][Crates.io] + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. + +[Crates.io]: https://crates.io/crates/tryfn +[Documentation]: https://docs.rs/tryfn diff --git a/crates/snapbox/src/harness.rs b/crates/tryfn/src/lib.rs similarity index 87% rename from crates/snapbox/src/harness.rs rename to crates/tryfn/src/lib.rs index 5bb00671..77dc31fe 100644 --- a/crates/snapbox/src/harness.rs +++ b/crates/tryfn/src/lib.rs @@ -6,7 +6,7 @@ //! # Examples //! //! ```rust,no_run -//! snapbox::harness::Harness::new( +//! tryfn::Harness::new( //! "tests/fixtures/invalid", //! setup, //! test, @@ -15,10 +15,10 @@ //! .action_env("SNAPSHOTS") //! .test(); //! -//! fn setup(input_path: std::path::PathBuf) -> snapbox::harness::Case { +//! fn setup(input_path: std::path::PathBuf) -> tryfn::Case { //! let name = input_path.file_name().unwrap().to_str().unwrap().to_owned(); -//! let expected = snapbox::Data::read_from(&input_path.with_extension("out"), None); -//! snapbox::harness::Case { +//! let expected = tryfn::Data::read_from(&input_path.with_extension("out"), None); +//! tryfn::Case { //! name, //! fixture: input_path, //! expected, @@ -35,20 +35,18 @@ //! } //! ``` -use crate::assert::Action; -use crate::Data; - use libtest_mimic::Trial; +pub use snapbox::assert::Action; +pub use snapbox::Data; + /// [`Harness`] for discovering test inputs and asserting against snapshot files -/// -/// See [`harness`][crate::harness] for more details pub struct Harness { root: std::path::PathBuf, overrides: Option, setup: S, test: T, - config: crate::Assert, + config: snapbox::Assert, test_output: std::marker::PhantomData, test_error: std::marker::PhantomData, } @@ -67,21 +65,21 @@ where /// - `setup`: Given a path, choose the test name and the output location /// - `test`: Given a path, return the actual output value /// - /// By default [`filters`][crate::filters] are applied, including: + /// By default [`filters`][snapbox::filters] are applied, including: /// - `...` is a line-wildcard when on a line by itself /// - `[..]` is a character-wildcard when inside a line /// - `[EXE]` matches `.exe` on Windows /// - `\` to `/` /// - Newlines /// - /// To limit this to newline normalization for text, have [`Setup`] call [`Data::raw`][crate::Data::raw] on `expected`. + /// To limit this to newline normalization for text, have [`Setup`] call [`Data::raw`][snapbox::Data::raw] on `expected`. pub fn new(input_root: impl Into, setup: S, test: T) -> Self { Self { root: input_root.into(), overrides: None, setup, test, - config: crate::Assert::new().action_env(crate::assert::DEFAULT_ACTION_ENV), + config: snapbox::Assert::new().action_env(snapbox::assert::DEFAULT_ACTION_ENV), test_output: Default::default(), test_error: Default::default(), } @@ -112,7 +110,7 @@ where } /// Customize the assertion behavior - pub fn with_assert(mut self, config: crate::Assert) -> Self { + pub fn with_assert(mut self, config: snapbox::Assert) -> Self { self.config = config; self } @@ -149,11 +147,11 @@ where Trial::test(case.name.clone(), move || { let actual = test.run(&case.fixture)?; let actual = actual.to_string(); - let actual = crate::Data::text(actual); + let actual = snapbox::Data::text(actual); config.try_eq(case.expected.clone(), actual, Some(&case.name))?; Ok(()) }) - .with_ignored_flag(shared_config.action == Action::Ignore) + .with_ignored_flag(shared_config.selected_action() == Action::Ignore) }) .collect(); @@ -195,8 +193,6 @@ where } /// A test case enumerated by the [`Harness`] with data from the `setup` function -/// -/// See [`harness`][crate::harness] for more details pub struct Case { /// Display name pub name: String, From c736e0317518cb078d96b4a82b3b72293c077566 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 23 Apr 2024 06:11:44 -0500 Subject: [PATCH 2/3] docs(tryfn): Improve documentation --- crates/tryfn/src/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/crates/tryfn/src/lib.rs b/crates/tryfn/src/lib.rs index 77dc31fe..e2d82f0e 100644 --- a/crates/tryfn/src/lib.rs +++ b/crates/tryfn/src/lib.rs @@ -6,13 +6,17 @@ //! # Examples //! //! ```rust,no_run +//! fn some_func(num: usize) -> usize { +//! // ... +//! # 10 +//! } +//! //! tryfn::Harness::new( //! "tests/fixtures/invalid", //! setup, //! test, //! ) //! .select(["tests/cases/*.in"]) -//! .action_env("SNAPSHOTS") //! .test(); //! //! fn setup(input_path: std::path::PathBuf) -> tryfn::Case { @@ -29,7 +33,7 @@ //! let raw = std::fs::read_to_string(input_path)?; //! let num = raw.parse::()?; //! -//! let actual = num + 10; +//! let actual = some_func(num); //! //! Ok(actual) //! } @@ -38,6 +42,7 @@ use libtest_mimic::Trial; pub use snapbox::assert::Action; +pub use snapbox::data::DataFormat; pub use snapbox::Data; /// [`Harness`] for discovering test inputs and asserting against snapshot files @@ -87,7 +92,7 @@ where /// Path patterns for selecting input files /// - /// This used gitignore syntax + /// This uses gitignore syntax pub fn select<'p>(mut self, patterns: impl IntoIterator) -> Self { let mut overrides = ignore::overrides::OverrideBuilder::new(&self.root); for line in patterns { @@ -160,6 +165,7 @@ where } } +/// Function signature for generating a test [`Case`] from a path fixture pub trait Setup { fn setup(&self, fixture: std::path::PathBuf) -> Case; } @@ -173,6 +179,7 @@ where } } +/// Function signature for running a test [`Case`] pub trait Test where S: std::fmt::Display, @@ -192,7 +199,7 @@ where } } -/// A test case enumerated by the [`Harness`] with data from the `setup` function +/// A test case enumerated by the [`Harness`] with data from the [`Setup`] function pub struct Case { /// Display name pub name: String, From a30d3bf4d72aef572a1794d3eb002fd518a56b2b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 23 Apr 2024 06:14:23 -0500 Subject: [PATCH 3/3] fix(tryfn)!: Remove Action overriding, deferring to Assert overriding --- crates/tryfn/src/lib.rs | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/crates/tryfn/src/lib.rs b/crates/tryfn/src/lib.rs index e2d82f0e..14a66ff5 100644 --- a/crates/tryfn/src/lib.rs +++ b/crates/tryfn/src/lib.rs @@ -41,7 +41,6 @@ use libtest_mimic::Trial; -pub use snapbox::assert::Action; pub use snapbox::data::DataFormat; pub use snapbox::Data; @@ -102,19 +101,11 @@ where self } - /// Read the failure action from an environment variable - pub fn action_env(mut self, var_name: &str) -> Self { - self.config = self.config.action_env(var_name); - self - } - - /// Override the failure action - pub fn action(mut self, action: Action) -> Self { - self.config = self.config.action(action); - self - } - /// Customize the assertion behavior + /// + /// Includes + /// - Configuring redactions + /// - Override updating environment vaeiable pub fn with_assert(mut self, config: snapbox::Assert) -> Self { self.config = config; self @@ -156,7 +147,9 @@ where config.try_eq(case.expected.clone(), actual, Some(&case.name))?; Ok(()) }) - .with_ignored_flag(shared_config.selected_action() == Action::Ignore) + .with_ignored_flag( + shared_config.selected_action() == snapbox::assert::Action::Ignore, + ) }) .collect();