forked from assert-rs/snapbox
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(filter): Move from
data
to filter
Cherry-pick fe2fb1e (assert-rs#288) Cherry-pick 79e3167 (assert-rs#285)
- Loading branch information
Showing
6 changed files
with
561 additions
and
528 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,196 +1,24 @@ | ||
//! Normalize `actual` or `expected` [`Data`] | ||
//! | ||
//! This can be done for | ||
//! - Making snapshots consistent across platforms or conditional compilation | ||
//! - Focusing snapshots on the characteristics of the data being tested | ||
#![allow(deprecated)] | ||
|
||
use super::Data; | ||
use super::DataInner; | ||
|
||
pub trait Normalize { | ||
fn normalize(&self, data: Data) -> Data; | ||
} | ||
pub use crate::filter::Normalize; | ||
|
||
#[deprecated(since = "0.5.11", note = "Replaced with `filter::NormalizeNewlines")] | ||
pub struct NormalizeNewlines; | ||
impl Normalize for NormalizeNewlines { | ||
fn normalize(&self, data: Data) -> Data { | ||
let source = data.source; | ||
let inner = match data.inner { | ||
DataInner::Error(err) => DataInner::Error(err), | ||
DataInner::Binary(bin) => DataInner::Binary(bin), | ||
DataInner::Text(text) => { | ||
let lines = crate::utils::normalize_lines(&text); | ||
DataInner::Text(lines) | ||
} | ||
#[cfg(feature = "json")] | ||
DataInner::Json(value) => { | ||
let mut value = value; | ||
normalize_value(&mut value, crate::utils::normalize_lines); | ||
DataInner::Json(value) | ||
} | ||
#[cfg(feature = "term-svg")] | ||
DataInner::TermSvg(text) => { | ||
let lines = crate::utils::normalize_lines(&text); | ||
DataInner::TermSvg(lines) | ||
} | ||
}; | ||
Data { inner, source } | ||
crate::filter::NormalizeNewlines.normalize(data) | ||
} | ||
} | ||
|
||
#[deprecated(since = "0.5.11", note = "Replaced with `filter::NormalizePaths")] | ||
pub struct NormalizePaths; | ||
impl Normalize for NormalizePaths { | ||
fn normalize(&self, data: Data) -> Data { | ||
let source = data.source; | ||
let inner = match data.inner { | ||
DataInner::Error(err) => DataInner::Error(err), | ||
DataInner::Binary(bin) => DataInner::Binary(bin), | ||
DataInner::Text(text) => { | ||
let lines = crate::utils::normalize_paths(&text); | ||
DataInner::Text(lines) | ||
} | ||
#[cfg(feature = "json")] | ||
DataInner::Json(value) => { | ||
let mut value = value; | ||
normalize_value(&mut value, crate::utils::normalize_paths); | ||
DataInner::Json(value) | ||
} | ||
#[cfg(feature = "term-svg")] | ||
DataInner::TermSvg(text) => { | ||
let lines = crate::utils::normalize_paths(&text); | ||
DataInner::TermSvg(lines) | ||
} | ||
}; | ||
Data { inner, source } | ||
} | ||
} | ||
|
||
pub struct NormalizeMatches<'a> { | ||
substitutions: &'a crate::Substitutions, | ||
pattern: &'a Data, | ||
} | ||
|
||
impl<'a> NormalizeMatches<'a> { | ||
pub fn new(substitutions: &'a crate::Substitutions, pattern: &'a Data) -> Self { | ||
NormalizeMatches { | ||
substitutions, | ||
pattern, | ||
} | ||
} | ||
} | ||
|
||
impl Normalize for NormalizeMatches<'_> { | ||
fn normalize(&self, data: Data) -> Data { | ||
let source = data.source; | ||
let inner = match data.inner { | ||
DataInner::Error(err) => DataInner::Error(err), | ||
DataInner::Binary(bin) => DataInner::Binary(bin), | ||
DataInner::Text(text) => { | ||
if let Some(pattern) = self.pattern.render() { | ||
let lines = self.substitutions.normalize(&text, &pattern); | ||
DataInner::Text(lines) | ||
} else { | ||
DataInner::Text(text) | ||
} | ||
} | ||
#[cfg(feature = "json")] | ||
DataInner::Json(value) => { | ||
let mut value = value; | ||
if let DataInner::Json(exp) = &self.pattern.inner { | ||
normalize_value_matches(&mut value, exp, self.substitutions); | ||
} | ||
DataInner::Json(value) | ||
} | ||
#[cfg(feature = "term-svg")] | ||
DataInner::TermSvg(text) => { | ||
if let Some(pattern) = self.pattern.render() { | ||
let lines = self.substitutions.normalize(&text, &pattern); | ||
DataInner::TermSvg(lines) | ||
} else { | ||
DataInner::TermSvg(text) | ||
} | ||
} | ||
}; | ||
Data { inner, source } | ||
crate::filter::NormalizePaths.normalize(data) | ||
} | ||
} | ||
|
||
#[cfg(feature = "structured-data")] | ||
fn normalize_value(value: &mut serde_json::Value, op: fn(&str) -> String) { | ||
match value { | ||
serde_json::Value::String(str) => { | ||
*str = op(str); | ||
} | ||
serde_json::Value::Array(arr) => { | ||
for value in arr.iter_mut() { | ||
normalize_value(value, op) | ||
} | ||
} | ||
serde_json::Value::Object(obj) => { | ||
for (_, value) in obj.iter_mut() { | ||
normalize_value(value, op) | ||
} | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
#[cfg(feature = "structured-data")] | ||
fn normalize_value_matches( | ||
actual: &mut serde_json::Value, | ||
expected: &serde_json::Value, | ||
substitutions: &crate::Substitutions, | ||
) { | ||
use serde_json::Value::*; | ||
|
||
const VALUE_WILDCARD: &str = "{...}"; | ||
|
||
match (actual, expected) { | ||
(act, String(exp)) if exp == VALUE_WILDCARD => { | ||
*act = serde_json::json!(VALUE_WILDCARD); | ||
} | ||
(String(act), String(exp)) => { | ||
*act = substitutions.normalize(act, exp); | ||
} | ||
(Array(act), Array(exp)) => { | ||
let mut sections = exp.split(|e| e == VALUE_WILDCARD).peekable(); | ||
let mut processed = 0; | ||
while let Some(expected_subset) = sections.next() { | ||
// Process all values in the current section | ||
if !expected_subset.is_empty() { | ||
let actual_subset = &mut act[processed..processed + expected_subset.len()]; | ||
for (a, e) in actual_subset.iter_mut().zip(expected_subset) { | ||
normalize_value_matches(a, e, substitutions); | ||
} | ||
processed += expected_subset.len(); | ||
} | ||
|
||
if let Some(next_section) = sections.peek() { | ||
// If the next section has nothing in it, replace from processed to end with | ||
// a single "{...}" | ||
if next_section.is_empty() { | ||
act.splice(processed.., vec![String(VALUE_WILDCARD.to_owned())]); | ||
processed += 1; | ||
} else { | ||
let first = next_section.first().unwrap(); | ||
// Replace everything up until the value we are looking for with | ||
// a single "{...}". | ||
if let Some(index) = act.iter().position(|v| v == first) { | ||
act.splice(processed..index, vec![String(VALUE_WILDCARD.to_owned())]); | ||
processed += 1; | ||
} else { | ||
// If we cannot find the value we are looking for return early | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
(Object(act), Object(exp)) => { | ||
for (a, e) in act.iter_mut().zip(exp).filter(|(a, e)| a.0 == e.0) { | ||
normalize_value_matches(a.1, e.1, substitutions) | ||
} | ||
} | ||
(_, _) => {} | ||
} | ||
} | ||
#[deprecated(since = "0.5.11", note = "Replaced with `filter::NormalizeMatches")] | ||
pub type NormalizeMatches<'a> = crate::filter::NormalizeMatches<'a>; |
Oops, something went wrong.