diff --git a/crates/snapbox/src/assert/mod.rs b/crates/snapbox/src/assert/mod.rs index bc5ba97c..abfafcd3 100644 --- a/crates/snapbox/src/assert/mod.rs +++ b/crates/snapbox/src/assert/mod.rs @@ -291,7 +291,7 @@ impl Assert { } let checks: Vec<_> = - crate::path::PathDiff::subset_eq_iter_inner(expected_root, actual_root).collect(); + crate::dir::PathDiff::subset_eq_iter_inner(expected_root, actual_root).collect(); self.verify(checks); } @@ -319,7 +319,7 @@ impl Assert { Action::Ignore | Action::Verify | Action::Overwrite => {} } - let checks: Vec<_> = crate::path::PathDiff::subset_matches_iter_inner( + let checks: Vec<_> = crate::dir::PathDiff::subset_matches_iter_inner( expected_root, actual_root, &self.substitutions, @@ -332,7 +332,7 @@ impl Assert { #[track_caller] fn verify( &self, - mut checks: Vec>, + mut checks: Vec>, ) { if checks.iter().all(Result::is_ok) { for check in checks { diff --git a/crates/snapbox/src/data/mod.rs b/crates/snapbox/src/data/mod.rs index a47a12e2..e345e04b 100644 --- a/crates/snapbox/src/data/mod.rs +++ b/crates/snapbox/src/data/mod.rs @@ -38,7 +38,7 @@ use filters::FilterSet; /// /// let actual = some_function(); /// let expected = snapbox::str![["5"]]; -/// snapbox::assert_eq(actual.to_debug(), expected); +/// snapbox::assert_data_eq!(actual.to_debug(), expected); /// ``` pub trait ToDebug { fn to_debug(&self) -> Data; @@ -64,7 +64,7 @@ impl ToDebug for D { /// /// let actual = some_function(); /// let expected = snapbox::str![["5"]]; -/// snapbox::assert_eq(actual.into_json(), expected); +/// snapbox::assert_data_eq!(actual.into_json(), expected); /// ``` #[cfg(feature = "json")] pub trait IntoJson { diff --git a/crates/snapbox/src/data/runtime.rs b/crates/snapbox/src/data/runtime.rs index 5f10e130..6e237db9 100644 --- a/crates/snapbox/src/data/runtime.rs +++ b/crates/snapbox/src/data/runtime.rs @@ -372,7 +372,7 @@ impl PathRuntime { #[cfg(test)] mod tests { use super::*; - use crate::assert_eq; + use crate::assert_data_eq; use crate::prelude::*; use crate::str; @@ -380,33 +380,33 @@ mod tests { fn test_format_patch() { let patch = format_patch(None, "hello\nworld\n"); - assert_eq( + assert_data_eq!( + patch, str![[r##" [r#" hello world "#]"##]], - patch, ); let patch = format_patch(None, r"hello\tworld"); - assert_eq(str![[r##"[r#"hello\tworld"#]"##]], patch); + assert_data_eq!(patch, str![[r##"[r#"hello\tworld"#]"##]].raw()); let patch = format_patch(None, "{\"foo\": 42}"); - assert_eq(str![[r##"[r#"{"foo": 42}"#]"##]], patch); + assert_data_eq!(patch, str![[r##"[r#"{"foo": 42}"#]"##]]); let patch = format_patch(Some(0), "hello\nworld\n"); - assert_eq( + assert_data_eq!( + patch, str![[r##" [r#" hello world "#]"##]], - patch, ); let patch = format_patch(Some(4), "single line"); - assert_eq(str![[r#""single line""#]], patch); + assert_data_eq!(patch, str![[r#""single line""#]]); } #[test] @@ -415,7 +415,8 @@ mod tests { patchwork.patch(4..7, "zwei"); patchwork.patch(0..3, "один"); patchwork.patch(8..13, "3"); - assert_eq( + assert_data_eq!( + patchwork.to_debug(), str![[r#" Patchwork { text: "один zwei 3", @@ -435,7 +436,6 @@ mod tests { ], } "#]], - patchwork.to_debug(), ); } diff --git a/crates/snapbox/src/filter/redactions.rs b/crates/snapbox/src/filter/redactions.rs index d6ded213..b488b6c5 100644 --- a/crates/snapbox/src/filter/redactions.rs +++ b/crates/snapbox/src/filter/redactions.rs @@ -17,11 +17,11 @@ impl Redactions { } pub(crate) fn with_exe() -> Self { - let mut substitutions = Self::new(); - substitutions + let mut redactions = Self::new(); + redactions .insert("[EXE]", std::env::consts::EXE_SUFFIX) .unwrap(); - substitutions + redactions } /// Insert an additional match pattern @@ -172,7 +172,7 @@ fn validate_placeholder(placeholder: &'static str) -> crate::assert::Result<&'st Ok(placeholder) } -fn normalize(input: &str, pattern: &str, substitutions: &Redactions) -> String { +fn normalize(input: &str, pattern: &str, redactions: &Redactions) -> String { if input == pattern { return input.to_owned(); } @@ -191,7 +191,7 @@ fn normalize(input: &str, pattern: &str, substitutions: &Redactions) -> String { input_lines[input_index..] .iter() .copied() - .map(|s| substitutions.substitute(s)), + .map(|s| redactions.substitute(s)), ); break 'outer; }; @@ -204,7 +204,7 @@ fn normalize(input: &str, pattern: &str, substitutions: &Redactions) -> String { }; let next_input_index = input_index + 1; - if line_matches(input_line, pattern_line, substitutions) { + if line_matches(input_line, pattern_line, redactions) { pattern_index = next_pattern_index; input_index = next_input_index; normalized.push(Cow::Borrowed(pattern_line)); @@ -232,7 +232,7 @@ fn normalize(input: &str, pattern: &str, substitutions: &Redactions) -> String { input_lines[input_index..] .iter() .copied() - .map(|s| substitutions.substitute(s)), + .map(|s| redactions.substitute(s)), ); break 'outer; } @@ -250,7 +250,7 @@ fn normalize(input: &str, pattern: &str, substitutions: &Redactions) -> String { input_lines[input_index..future_input_index] .iter() .copied() - .map(|s| substitutions.substitute(s)), + .map(|s| redactions.substitute(s)), ); pattern_index = future_pattern_index; input_index = future_input_index; @@ -262,7 +262,7 @@ fn normalize(input: &str, pattern: &str, substitutions: &Redactions) -> String { input_lines[input_index..] .iter() .copied() - .map(|s| substitutions.substitute(s)), + .map(|s| redactions.substitute(s)), ); break 'outer; } @@ -275,15 +275,15 @@ fn is_line_elide(line: &str) -> bool { line == "...\n" || line == "..." } -fn line_matches(line: &str, pattern: &str, substitutions: &Redactions) -> bool { +fn line_matches(line: &str, pattern: &str, redactions: &Redactions) -> bool { if line == pattern { return true; } - let subbed = substitutions.substitute(line); + let subbed = redactions.substitute(line); let mut line = subbed.as_ref(); - let pattern = substitutions.clear(pattern); + let pattern = redactions.clear(pattern); let mut sections = pattern.split("[..]").peekable(); while let Some(section) = sections.next() { diff --git a/crates/snapbox/src/lib.rs b/crates/snapbox/src/lib.rs index 44aa3ed2..5d924f77 100644 --- a/crates/snapbox/src/lib.rs +++ b/crates/snapbox/src/lib.rs @@ -12,6 +12,7 @@ //! ## Which tool is right //! //! - [cram](https://bitheap.org/cram/): End-to-end CLI snapshotting agnostic of any programming language +//! - See also [scrut](https://github.com/facebookincubator/scrut) //! - [trycmd](https://crates.io/crates/trycmd): For running a lot of blunt tests (limited test predicates) //! - Particular attention is given to allow the test data to be pulled into documentation, like //! with [mdbook](https://rust-lang.github.io/mdBook/) @@ -25,7 +26,7 @@ //! ## Getting Started //! //! Testing Functions: -//! - [`assert_eq`][crate::assert_eq()] and [`assert_matches`] for reusing diffing / pattern matching for non-snapshot testing +//! - [`assert_data_eq!`] for quick and dirty snapshotting //! - [`harness::Harness`] for discovering test inputs and asserting against snapshot files: //! //! Testing Commands: @@ -44,9 +45,9 @@ //! //! # Examples //! -//! [`assert_matches`] +//! [`assert_data_eq!`] //! ```rust -//! snapbox::assert_matches("Hello [..] people!", "Hello many people!"); +//! snapbox::assert_data_eq!("Hello many people!", "Hello [..] people!"); //! ``` //! //! [`Assert`] @@ -54,7 +55,7 @@ //! let actual = "..."; //! snapbox::Assert::new() //! .action_env("SNAPSHOTS") -//! .matches(snapbox::file!["help_output_is_clean.txt"], actual); +//! .eq_(actual, snapbox::file!["help_output_is_clean.txt"]); //! ``` //! //! [`harness::Harness`] @@ -160,6 +161,10 @@ pub mod prelude { /// assert_eq(file!["output.txt"], actual); /// ``` #[track_caller] +#[deprecated( + since = "0.5.11", + note = "Replaced with `assert_data_eq!(actual, expected.raw())`" +)] pub fn assert_eq(expected: impl Into, actual: impl Into) { Assert::new() .action_env(assert::DEFAULT_ACTION_ENV) @@ -192,6 +197,7 @@ pub fn assert_eq(expected: impl Into, actual: impl Into, actual: impl Into) { Assert::new() .action_env(assert::DEFAULT_ACTION_ENV) diff --git a/crates/snapbox/src/macros.rs b/crates/snapbox/src/macros.rs index 3078bb25..6adf8483 100644 --- a/crates/snapbox/src/macros.rs +++ b/crates/snapbox/src/macros.rs @@ -1,3 +1,50 @@ +/// Check if a value is the same as an expected value +/// +/// By default [`filters`][crate::filter] 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, call [`Data::raw`][crate::Data] on `expected`. +/// +/// # Effective signature +/// +/// ```rust +/// # use snapbox::IntoData; +/// fn assert_data_eq(actual: impl IntoData, expected: impl IntoData) { +/// // ... +/// } +/// ``` +/// +/// # Examples +/// +/// ```rust +/// # use snapbox::assert_data_eq; +/// let output = "something"; +/// let expected = "so[..]g"; +/// assert_data_eq!(output, expected); +/// ``` +/// +/// Can combine this with [`file!`] +/// ```rust,no_run +/// # use snapbox::assert_data_eq; +/// # use snapbox::file; +/// let actual = "something"; +/// assert_data_eq!(actual, file!["output.txt"]); +/// ``` +#[macro_export] +macro_rules! assert_data_eq { + ($actual: expr, $expected: expr $(,)?) => {{ + let actual = $crate::IntoData::into_data($actual); + let expected = $crate::IntoData::into_data($expected); + $crate::Assert::new() + .action_env($crate::assert::DEFAULT_ACTION_ENV) + .eq_(actual, expected); + }}; +} + /// Find the directory for your source file #[doc(hidden)] // forced to be visible in intended location #[macro_export] diff --git a/crates/snapbox/tests/testsuite/assert.rs b/crates/snapbox/tests/testsuite/assert.rs index 4c9bad6d..416ec884 100644 --- a/crates/snapbox/tests/testsuite/assert.rs +++ b/crates/snapbox/tests/testsuite/assert.rs @@ -1,40 +1,40 @@ -use snapbox::assert_eq; +use snapbox::assert_data_eq; use snapbox::file; use snapbox::str; #[test] fn test_trivial_assert() { - assert_eq(str!["5"], "5"); + assert_data_eq!("5", str!["5"]); } #[test] fn smoke_test_indent() { - assert_eq( + assert_data_eq!( + "\ +line1 + line2 +", str![[r#" line1 line2 "#]] .indent(true), + ); + + assert_data_eq!( "\ line1 line2 ", - ); - - assert_eq( str![[r#" line1 line2 "#]] .indent(false), - "\ -line1 - line2 -", ); } #[test] fn test_expect_file() { - assert_eq(file!["../../README.md"], include_str!("../../README.md")) + assert_data_eq!(include_str!("../../README.md"), file!["../../README.md"]); }