Skip to content

Commit

Permalink
refactor(snapbox): Changes to normalization
Browse files Browse the repository at this point in the history
- `map_text` to `normalize`
- make `normalize` take in a normalization operation
  • Loading branch information
Muscraft committed Aug 16, 2022
1 parent 9b3aee2 commit 849cff3
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 56 deletions.
40 changes: 17 additions & 23 deletions crates/snapbox/src/assert.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::data::DataFormat;
use crate::Action;
use crate::data::{DataFormat, NormalizeMatches, NormalizeNewlines};
use crate::{Action, NormalizePaths};

/// Snapshot assertion against a file's contents
///
Expand Down Expand Up @@ -178,16 +178,14 @@ impl Assert {
expected: crate::Result<crate::Data>,
mut actual: crate::Data,
) -> (crate::Result<crate::Data>, crate::Data) {
let expected = expected.map(|d| d.map_text(crate::utils::normalize_lines));
let expected = expected.map(|d| d.normalize(NormalizeNewlines));
// On `expected` being an error, make a best guess
let format = expected
.as_ref()
.map(|d| d.format())
.unwrap_or(DataFormat::Text);

actual = actual
.try_coerce(format)
.map_text(|s| crate::utils::normalize_lines(s));
actual = actual.try_coerce(format).normalize(NormalizeNewlines);

(expected, actual)
}
Expand All @@ -197,17 +195,21 @@ impl Assert {
expected: crate::Result<crate::Data>,
mut actual: crate::Data,
) -> (crate::Result<crate::Data>, crate::Data) {
let expected = expected.map(|d| d.map_text(crate::utils::normalize_lines));
let expected = expected.map(|d| d.normalize(NormalizeNewlines));
// On `expected` being an error, make a best guess
if let (Some(expected), format) = expected
.as_ref()
.map(|d| (d.as_str(), d.format()))
.unwrap_or((Some(""), DataFormat::Text))
{
let ok = expected.clone().unwrap_or_default();

if self.normalize_paths {
actual = actual
.try_coerce(ok.format())
.normalize(NormalizePaths)
.normalize(NormalizeNewlines)
.normalize(NormalizeMatches::new(&self.substitutions, ok));
} else {
actual = actual
.try_coerce(format)
.map_text(|s| self.normalize_text(s))
.map_text(|t| self.substitutions.normalize(t, expected));
.try_coerce(ok.format())
.normalize(NormalizeNewlines)
.normalize(NormalizeMatches::new(&self.substitutions, ok));
}

(expected, actual)
Expand Down Expand Up @@ -290,14 +292,6 @@ impl Assert {
Ok(())
}
}

fn normalize_text(&self, data: &str) -> String {
let mut data = crate::utils::normalize_lines(data);
if self.normalize_paths {
data = crate::utils::normalize_paths(&data);
}
data
}
}

/// # Directory Assertions
Expand Down
69 changes: 62 additions & 7 deletions crates/snapbox/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,8 @@ impl Data {
/// Post-process text
///
/// See [utils][crate::utils]
pub fn map_text(self, op: impl FnOnce(&str) -> String) -> Self {
match self.inner {
DataInner::Binary(data) => Self::binary(data),
DataInner::Text(data) => Self::text(op(&data)),
}
pub fn normalize(self, op: impl Normalize) -> Self {
op.normalize(self)
}

/// Coerce to a string
Expand All @@ -110,10 +107,10 @@ impl Data {
/// Return the underlying `str`
///
/// Note: this will not inspect binary data for being a valid `str`.
pub fn as_str(&self) -> Option<&str> {
pub fn render(&self) -> Option<String> {
match &self.inner {
DataInner::Binary(_) => None,
DataInner::Text(data) => Some(data.as_str()),
DataInner::Text(data) => Some(data.clone()),
}
}

Expand Down Expand Up @@ -206,6 +203,64 @@ impl<'s> From<&'s str> for Data {
}
}

pub trait Normalize {
fn normalize(&self, data: Data) -> Data;
}

pub struct NormalizeNewlines;
impl Normalize for NormalizeNewlines {
fn normalize(&self, data: Data) -> Data {
match data.inner {
DataInner::Binary(bin) => Data::binary(bin),
DataInner::Text(text) => {
let lines = crate::utils::normalize_lines(&text);
Data::text(lines)
}
}
}
}

pub struct NormalizePaths;
impl Normalize for NormalizePaths {
fn normalize(&self, data: Data) -> Data {
match data.inner {
DataInner::Binary(bin) => Data::binary(bin),
DataInner::Text(text) => {
let lines = crate::utils::normalize_paths(&text);
Data::text(lines)
}
}
}
}

pub struct NormalizeMatches<'a> {
substitutions: &'a crate::Substitutions,
pattern: Data,
}

impl<'a> NormalizeMatches<'a> {
pub fn new(substitutions: &'a crate::Substitutions, pattern: Data) -> Self {
NormalizeMatches {
substitutions,
pattern,
}
}
}

impl Normalize for NormalizeMatches<'_> {
fn normalize(&self, data: Data) -> Data {
match data.inner {
DataInner::Binary(bin) => Data::binary(bin),
DataInner::Text(text) => {
let lines = self
.substitutions
.normalize(&text, &self.pattern.render().unwrap());
Data::text(lines)
}
}
}
}

#[cfg(feature = "detect-encoding")]
fn is_binary(data: &[u8]) -> bool {
match content_inspector::inspect(data) {
Expand Down
6 changes: 3 additions & 3 deletions crates/snapbox/src/harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
//! }
//! ```
use crate::data::DataFormat;
use crate::data::{DataFormat, NormalizeNewlines};
use crate::Action;

pub struct Harness<S, T> {
Expand Down Expand Up @@ -122,7 +122,7 @@ where
match (self.test)(&test.data.fixture) {
Ok(actual) => {
let actual = actual.to_string();
let actual = crate::Data::text(actual).map_text(crate::utils::normalize_lines);
let actual = crate::Data::text(actual).normalize(NormalizeNewlines);
let verify = Verifier::new()
.palette(crate::report::Palette::auto())
.action(self.action);
Expand Down Expand Up @@ -214,7 +214,7 @@ impl Verifier {
actual: crate::Data,
) -> crate::Result<()> {
let expected = crate::Data::read_from(expected_path, Some(DataFormat::Text))?
.map_text(crate::utils::normalize_lines);
.normalize(NormalizeNewlines);

if expected != actual {
let mut buf = String::new();
Expand Down
1 change: 1 addition & 0 deletions crates/snapbox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ pub use action::DEFAULT_ACTION_ENV;
pub use assert::Assert;
pub use data::Data;
pub use data::DataFormat;
pub use data::{Normalize, NormalizeMatches, NormalizeNewlines, NormalizePaths};
pub use error::Error;
pub use snapbox_macros::debug;
pub use substitutions::Substitutions;
Expand Down
20 changes: 11 additions & 9 deletions crates/snapbox/src/path.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! Initialize working directories and assert on how they've changed
use crate::data::{NormalizeMatches, NormalizeNewlines};
use crate::NormalizePaths;

/// Working directory for tests
#[derive(Debug)]
pub struct PathFixture(PathFixtureInner);
Expand Down Expand Up @@ -179,12 +182,12 @@ impl PathDiff {
crate::Data::read_from(&actual_path, None).map_err(Self::Failure)?;

let expected = crate::Data::read_from(&expected_path, None)
.map(|d| d.map_text(crate::utils::normalize_lines))
.map(|d| d.normalize(NormalizeNewlines))
.map_err(Self::Failure)?;

actual = actual
.try_coerce(expected.format())
.map_text(crate::utils::normalize_lines);
.normalize(NormalizeNewlines);

if expected != actual {
return Err(Self::ContentMismatch {
Expand Down Expand Up @@ -257,15 +260,14 @@ impl PathDiff {
crate::Data::read_from(&actual_path, None).map_err(Self::Failure)?;

let expected = crate::Data::read_from(&expected_path, None)
.map(|d| d.map_text(crate::utils::normalize_lines))
.map(|d| d.normalize(NormalizeNewlines))
.map_err(Self::Failure)?;

if let (Some(expected), format) = (expected.as_str(), expected.format()) {
actual = actual
.try_coerce(format)
.map_text(crate::utils::normalize_text)
.map_text(|t| substitutions.normalize(t, expected));
}
actual = actual
.try_coerce(expected.format())
.normalize(NormalizePaths)
.normalize(NormalizeNewlines)
.normalize(NormalizeMatches::new(substitutions, expected.clone()));

if expected != actual {
return Err(Self::ContentMismatch {
Expand Down
6 changes: 3 additions & 3 deletions crates/snapbox/src/report/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ pub fn write_diff(
#[allow(unused_mut)]
let mut rendered = false;
#[cfg(feature = "diff")]
if let (Some(expected), Some(actual)) = (expected.as_str(), actual.as_str()) {
if let (Some(expected), Some(actual)) = (expected.render(), actual.render()) {
write_diff_inner(
writer,
expected,
actual,
&expected,
&actual,
expected_name,
actual_name,
palette,
Expand Down
13 changes: 9 additions & 4 deletions src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::io::prelude::*;

use rayon::prelude::*;
use snapbox::path::FileType;
use snapbox::{NormalizeNewlines, NormalizePaths};

#[derive(Debug)]
pub(crate) struct Runner {
Expand Down Expand Up @@ -419,9 +420,10 @@ impl Case {
}

if let Some(expected_content) = expected_content {
if let Some(e) = expected_content.as_str() {
stream.content = stream.content.map_text(|t| substitutions.normalize(t, e));
}
stream.content = stream.content.normalize(snapbox::NormalizeMatches::new(
substitutions,
expected_content.clone(),
));
if stream.content != *expected_content {
stream.status = StreamStatus::Expected(expected_content.clone());
return Some(stream);
Expand Down Expand Up @@ -720,7 +722,10 @@ impl Stream {
if self.content.make_text().is_err() {
self.status = StreamStatus::Failure("invalid UTF-8".into());
}
self.content = self.content.map_text(snapbox::utils::normalize_text);
self.content = self
.content
.normalize(NormalizePaths)
.normalize(NormalizeNewlines);
self
}

Expand Down
14 changes: 7 additions & 7 deletions src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//!
//! [`OneShot`] is the top-level item in the `cmd.toml` files.
use snapbox::{NormalizeNewlines, NormalizePaths};
use std::collections::BTreeMap;
use std::collections::VecDeque;

Expand Down Expand Up @@ -40,7 +41,8 @@ impl TryCmd {
let stdout = if stdout_path.exists() {
Some(
crate::Data::read_from(&stdout_path, Some(is_binary))?
.map_text(snapbox::utils::normalize_text),
.normalize(NormalizePaths)
.normalize(NormalizeNewlines),
)
} else {
None
Expand All @@ -53,7 +55,8 @@ impl TryCmd {
let stderr = if stderr_path.exists() {
Some(
crate::Data::read_from(&stderr_path, Some(is_binary))?
.map_text(snapbox::utils::normalize_text),
.normalize(NormalizePaths)
.normalize(NormalizeNewlines),
)
} else {
None
Expand Down Expand Up @@ -143,10 +146,7 @@ impl TryCmd {
.expected_stdout_source
.clone()
.expect("always present for .trycmd");
let mut stdout = stdout
.as_str()
.expect("already converted to Text")
.to_owned();
let mut stdout = stdout.render().expect("already converted to Text");
// Add back trailing newline removed when parsing
stdout.push('\n');
let raw = std::fs::read_to_string(path)
Expand Down Expand Up @@ -324,7 +324,7 @@ fn overwrite_toml_output(
let output_path = path.with_extension(output_ext);
if output_path.exists() {
output.write_to(&output_path)?;
} else if let Some(output) = output.as_str() {
} else if let Some(output) = output.render() {
let raw = std::fs::read_to_string(path)
.map_err(|e| format!("Failed to read {}: {}", path.display(), e))?;
let mut doc = raw
Expand Down

0 comments on commit 849cff3

Please sign in to comment.