diff --git a/crates/snapbox/src/assert/mod.rs b/crates/snapbox/src/assert/mod.rs index 460bd933..bc5ba97c 100644 --- a/crates/snapbox/src/assert/mod.rs +++ b/crates/snapbox/src/assert/mod.rs @@ -9,6 +9,7 @@ use anstream::stderr; use std::io::stderr; use crate::filter::{Filter as _, FilterNewlines, FilterPaths, FilterRedactions}; +use crate::IntoData; pub use action::Action; pub use action::DEFAULT_ACTION_ENV; @@ -70,9 +71,9 @@ impl Assert { /// Assert::new().eq_(actual, file!["output.txt"]); /// ``` #[track_caller] - pub fn eq_(&self, actual: impl Into, expected: impl Into) { - let expected = expected.into(); - let actual = actual.into(); + pub fn eq_(&self, actual: impl IntoData, expected: impl IntoData) { + let expected = expected.into_data(); + let actual = actual.into_data(); if let Err(err) = self.try_eq(Some(&"In-memory"), actual, expected) { err.panic(); } diff --git a/crates/snapbox/src/cmd.rs b/crates/snapbox/src/cmd.rs index f84c4dc7..f13471a2 100644 --- a/crates/snapbox/src/cmd.rs +++ b/crates/snapbox/src/cmd.rs @@ -3,6 +3,8 @@ #[cfg(feature = "color")] use anstream::panic; +use crate::IntoData; + /// Process spawning for testing of non-interactive commands #[derive(Debug)] pub struct Command { @@ -243,8 +245,8 @@ impl Command { /// .assert() /// .stdout_eq("42"); /// ``` - pub fn stdin(mut self, stream: impl Into) -> Self { - self.stdin = Some(stream.into()); + pub fn stdin(mut self, stream: impl IntoData) -> Self { + self.stdin = Some(stream.into_data()); self } @@ -623,8 +625,8 @@ impl OutputAssert { /// .stdout_eq_(file!["stdout.log"]); /// ``` #[track_caller] - pub fn stdout_eq_(self, expected: impl Into) -> Self { - let expected = expected.into(); + pub fn stdout_eq_(self, expected: impl IntoData) -> Self { + let expected = expected.into_data(); self.stdout_eq_inner(expected) } @@ -700,7 +702,7 @@ impl OutputAssert { #[track_caller] fn stdout_eq_inner(self, expected: crate::Data) -> Self { - let actual = crate::Data::from(self.output.stdout.as_slice()); + let actual = self.output.stdout.as_slice().into_data(); if let Err(err) = self.config.try_eq(Some(&"stdout"), actual, expected) { err.panic(); } @@ -745,8 +747,8 @@ impl OutputAssert { /// .stderr_eq_(file!["stderr.log"]); /// ``` #[track_caller] - pub fn stderr_eq_(self, expected: impl Into) -> Self { - let expected = expected.into(); + pub fn stderr_eq_(self, expected: impl IntoData) -> Self { + let expected = expected.into_data(); self.stderr_eq_inner(expected) } @@ -822,7 +824,7 @@ impl OutputAssert { #[track_caller] fn stderr_eq_inner(self, expected: crate::Data) -> Self { - let actual = crate::Data::from(self.output.stderr.as_slice()); + let actual = self.output.stderr.as_slice().into_data(); if let Err(err) = self.config.try_eq(Some(&"stderr"), actual, expected) { err.panic(); } diff --git a/crates/snapbox/src/data/mod.rs b/crates/snapbox/src/data/mod.rs index 5056c777..7d9485d6 100644 --- a/crates/snapbox/src/data/mod.rs +++ b/crates/snapbox/src/data/mod.rs @@ -50,10 +50,52 @@ impl ToDebug for D { } } +/// Convert to [`Data`] with modifiers for `expected` data +pub trait IntoData: Sized { + /// Remove default [`filters`][crate::filter] from this `expected` result + fn raw(self) -> Data { + self.into_data().raw() + } + + /// Initialize as [`format`][DataFormat] or [`Error`][DataFormat::Error] + /// + /// This is generally used for `expected` data + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "json")] { + /// use snapbox::prelude::*; + /// use snapbox::str; + /// + /// let expected = str![[r#"{"hello": "world"}"#]] + /// .is(snapbox::data::DataFormat::Json); + /// assert_eq!(expected.format(), snapbox::data::DataFormat::Json); + /// # } + /// ``` + fn is(self, format: DataFormat) -> Data { + self.into_data().is(format) + } + + /// Convert to [`Data`], applying defaults + fn into_data(self) -> Data; +} + +impl IntoData for D +where + D: Into, +{ + fn into_data(self) -> Data { + self.into() + } +} + /// Declare an expected value for an assert from a file /// /// This is relative to the source file the macro is run from /// +/// Output type: [`Data`] +/// /// ``` /// # #[cfg(feature = "json")] { /// # use snapbox::file; @@ -88,6 +130,8 @@ macro_rules! file { /// Declare an expected value from within Rust source /// +/// Output type: [`Inline`], see [`IntoData`] for operations +/// /// ``` /// # use snapbox::str; /// str![[" @@ -97,8 +141,6 @@ macro_rules! file { /// ``` /// /// Leading indentation is stripped. -/// -/// See [`Inline::is`] for declaring the data to be of a certain format. #[macro_export] macro_rules! str { [$data:literal] => { $crate::str![[$data]] }; @@ -147,6 +189,7 @@ pub(crate) enum DataInner { /// - [`file!`] for external snapshots /// - [`ToString`] for verifying a `Display` representation /// - [`ToDebug`] for verifying a debug representation +/// - [`IntoData`] for modifying `expected` impl Data { /// Mark the data as binary (no post-processing) pub fn binary(raw: impl Into>) -> Self { @@ -587,6 +630,13 @@ impl<'s> From<&'s str> for Data { } } +impl From for super::Data { + fn from(inline: Inline) -> Self { + let trimmed = inline.trimmed(); + super::Data::text(trimmed).with_source(inline) + } +} + #[cfg(feature = "detect-encoding")] fn is_binary(data: &[u8]) -> bool { match content_inspector::inspect(data) { diff --git a/crates/snapbox/src/data/runtime.rs b/crates/snapbox/src/data/runtime.rs index 52dad661..5f10e130 100644 --- a/crates/snapbox/src/data/runtime.rs +++ b/crates/snapbox/src/data/runtime.rs @@ -373,8 +373,8 @@ impl PathRuntime { mod tests { use super::*; use crate::assert_eq; + use crate::prelude::*; use crate::str; - use crate::ToDebug as _; #[test] fn test_format_patch() { diff --git a/crates/snapbox/src/data/source.rs b/crates/snapbox/src/data/source.rs index 15dd77ea..6e0aae71 100644 --- a/crates/snapbox/src/data/source.rs +++ b/crates/snapbox/src/data/source.rs @@ -100,6 +100,8 @@ impl Inline { /// assert_eq!(expected.format(), snapbox::data::DataFormat::Json); /// # } /// ``` + // #[deprecated(since = "0.5.11", note = "Replaced with `IntoData::is`")] // can't deprecate + // because trait will always be preferred pub fn is(self, format: super::DataFormat) -> super::Data { let data: super::Data = self.into(); data.is(format) @@ -112,14 +114,7 @@ impl Inline { data.coerce_to(format) } - /// Remove default [`filters`][crate::filter] from this `expected` result - pub fn raw(self) -> super::Data { - let mut data: super::Data = self.into(); - data.filters = super::FilterSet::empty().newlines(); - data - } - - fn trimmed(&self) -> String { + pub(crate) fn trimmed(&self) -> String { let mut data = self.data; if data.contains('\n') { if data.starts_with('\n') { @@ -158,13 +153,6 @@ impl std::fmt::Display for Inline { } } -impl From for super::Data { - fn from(inline: Inline) -> Self { - let trimmed = inline.trimmed(); - super::Data::text(trimmed).with_source(inline) - } -} - /// Position within Rust source code, see [`Inline`] #[doc(hidden)] #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/crates/snapbox/src/lib.rs b/crates/snapbox/src/lib.rs index 8451f839..5f62ed24 100644 --- a/crates/snapbox/src/lib.rs +++ b/crates/snapbox/src/lib.rs @@ -113,6 +113,7 @@ pub mod harness; pub use assert::Action; pub use assert::Assert; pub use data::Data; +pub use data::IntoData; pub use data::ToDebug; pub use filter::RedactedValue; pub use filter::Redactions; @@ -130,6 +131,12 @@ pub type Result = std::result::Result; #[deprecated(since = "0.5.11", note = "Replaced with `assert::Error`")] pub type Error = assert::Error; +/// Easier access to common traits +pub mod prelude { + pub use crate::IntoData; + pub use crate::ToDebug; +} + /// Check if a value is the same as an expected value /// /// When the content is text, newlines are normalized. diff --git a/crates/trycmd/src/runner.rs b/crates/trycmd/src/runner.rs index 0d405fd4..96159164 100644 --- a/crates/trycmd/src/runner.rs +++ b/crates/trycmd/src/runner.rs @@ -15,6 +15,7 @@ use rayon::prelude::*; use snapbox::data::DataFormat; use snapbox::dir::FileType; use snapbox::filter::{Filter as _, FilterNewlines, FilterPaths, FilterRedactions}; +use snapbox::IntoData; #[derive(Debug)] pub(crate) struct Runner { @@ -584,12 +585,12 @@ impl Output { self.spawn.status = SpawnStatus::Ok; self.stdout = Some(Stream { stream: Stdio::Stdout, - content: output.stdout.into(), + content: output.stdout.into_data(), status: StreamStatus::Ok, }); self.stderr = Some(Stream { stream: Stdio::Stderr, - content: output.stderr.into(), + content: output.stderr.into_data(), status: StreamStatus::Ok, }); self