From 8fb2d1e9bf52284e75d47148eec9b9c8372c8251 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Sat, 29 May 2021 12:43:23 -0500 Subject: [PATCH] fix(diff): Remove duplicated output In the tree view, we already show the original and the current value, we shouldnt show an entire Diff that is only parseable by color. In changing this, we removed the more cosmetic atom selector. We also removed the edit distance, since there isn't a known case for it. Let us know if you needed this! Fixes #94 Fixes #105 --- CHANGELOG.md | 12 ++++ Cargo.toml | 6 +- src/lib.rs | 4 +- src/prelude.rs | 4 +- src/str/difference.rs | 128 +++++++----------------------------------- src/str/mod.rs | 6 +- 6 files changed, 42 insertions(+), 118 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e83d0d..549e7b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate +#### Breaking Changes + +- `predicates::str::diff` was removed +- `predicates::str::similar` was renamed to `diff` +- The `difference` feature flag was renamed to `diff` +- `diff().split` and `diff().distance` were removed + +#### Fixes + +- Shrink the output of Diffs because its redundant +- Moved off of an unmaintained Diff library + ## [1.0.8] - 2021-04-28 ## [1.0.7] - 2021-01-29 diff --git a/Cargo.toml b/Cargo.toml index 2734b42..bf4b05e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,14 +22,16 @@ azure-devops = { project = "assert-rs", pipeline = "predicates-rs" } [dependencies] predicates-core = { version = "1.0", path = "crates/core" } -difference = { version = "2.0", optional = true } +difflib = { version = "0.4", optional = true } normalize-line-endings = { version = "0.3.0", optional = true } regex = { version="1.0", optional = true } float-cmp = { version="0.8", optional = true } +itertools = "0.10" [dev-dependencies] predicates-tree = { version = "1.0", path = "crates/tree" } [features] -default = ["difference", "regex", "float-cmp", "normalize-line-endings"] +default = ["diff", "regex", "float-cmp", "normalize-line-endings"] +diff = ["difflib"] unstable = [] diff --git a/src/lib.rs b/src/lib.rs index 935595c..c3bf9a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -137,9 +137,8 @@ //! - [`predicate::str::is_empty`]: Specified string must be empty //! - [`str_pred = predicate::path::eq_file(...).utf8`]: Specified string must equal the contents //! of the given file. -//! - [`predicate::str::similar`]: Same as `eq` except report a diff. See [`DifferencePredicate`] +//! - [`predicate::str::diff`]: Same as `eq` except report a diff. See [`DifferencePredicate`] //! for more features. -//! - [`predicate::str::diff`]: Same as `ne`. See [`DifferencePredicate`] for more features. //! - [`predicate::str::starts_with`]: Specified string must start with the given needle. //! - [`predicate::str::ends_with`]: Specified string must end with the given needle. //! - [`predicate::str::contains`]: Specified string must contain the given needle. @@ -194,7 +193,6 @@ //! [`predicate::str::is_empty`]: prelude::predicate::str::is_empty() //! [`predicate::str::is_match(...).count`]: str::RegexPredicate::count() //! [`predicate::str::is_match`]: prelude::predicate::str::is_match() -//! [`predicate::str::similar`]: prelude::predicate::str::similar() //! [`predicate::str::starts_with`]: prelude::predicate::str::starts_with() //! [`str_pred = predicate::path::eq_file(...).utf8`]: path::BinaryFilePredicate::utf8() //! [`str_pred.normalize`]: prelude::PredicateStrExt::normalize() diff --git a/src/prelude.rs b/src/prelude.rs index 565f597..8cfd447 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -30,8 +30,8 @@ pub mod predicate { pub use crate::str::is_empty; pub use crate::str::{contains, ends_with, starts_with}; - #[cfg(feature = "difference")] - pub use crate::str::{diff, similar}; + #[cfg(feature = "diff")] + pub use crate::str::diff; #[cfg(feature = "regex")] pub use crate::str::is_match; diff --git a/src/str/difference.rs b/src/str/difference.rs index c125be6..0e87eaa 100644 --- a/src/str/difference.rs +++ b/src/str/difference.rs @@ -12,95 +12,36 @@ use std::fmt; use crate::reflection; use crate::Predicate; -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum DistanceOp { - Similar, - Different, -} - -impl DistanceOp { - fn eval(self, limit: i32, distance: i32) -> bool { - match self { - DistanceOp::Similar => distance <= limit, - DistanceOp::Different => limit < distance, - } - } -} - /// Predicate that diffs two strings. /// -/// This is created by the `predicate::str::similar`. +/// This is created by the `predicate::str::diff`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct DifferencePredicate { orig: borrow::Cow<'static, str>, - split: borrow::Cow<'static, str>, - distance: i32, - op: DistanceOp, -} - -impl DifferencePredicate { - /// The split used when identifying changes. - /// - /// Common splits include: - /// - `""` for char-level. - /// - `" "` for word-level. - /// - `"\n"` for line-level. - /// - /// Default: `"\n"` - /// - /// # Examples - /// - /// ``` - /// use predicates::prelude::*; - /// - /// let predicate_fn = predicate::str::similar("Hello World").split(" "); - /// assert_eq!(true, predicate_fn.eval("Hello World")); - /// ``` - pub fn split(mut self, split: S) -> Self - where - S: Into>, - { - self.split = split.into(); - self - } - - /// The maximum allowed edit distance. - /// - /// Default: `0` - /// - /// # Examples - /// - /// ``` - /// use predicates::prelude::*; - /// - /// let predicate_fn = predicate::str::similar("Hello World!").split("").distance(1); - /// assert_eq!(true, predicate_fn.eval("Hello World!")); - /// assert_eq!(true, predicate_fn.eval("Hello World")); - /// assert_eq!(false, predicate_fn.eval("Hello World?")); - /// ``` - pub fn distance(mut self, distance: i32) -> Self { - self.distance = distance; - self - } } impl Predicate for DifferencePredicate { fn eval(&self, edit: &str) -> bool { - let change = difference::Changeset::new(&self.orig, edit, &self.split); - self.op.eval(self.distance, change.distance) + edit == self.orig } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { - let change = difference::Changeset::new(&self.orig, variable, &self.split); - let result = self.op.eval(self.distance, change.distance); + let result = variable != self.orig; if result == expected { + None + } else { + let orig: Vec<_> = self.orig.lines().map(|l| format!("{}\n", l)).collect(); + let variable: Vec<_> = variable.lines().map(|l| format!("{}\n", l)).collect(); + let mut diff = + difflib::unified_diff(&orig, &variable, "value", "value", "expected", "actual", 0); + diff.insert(0, "\n".to_owned()); + Some( - reflection::Case::new(Some(self), result) - .add_product(reflection::Product::new("actual distance", change.distance)) - .add_product(reflection::Product::new("diff", change)), + reflection::Case::new(Some(self), result).add_product(reflection::Product::new( + "diff", + itertools::join(diff.iter(), ""), + )), ) - } else { - None } } } @@ -114,10 +55,7 @@ impl reflection::PredicateReflection for DifferencePredicate { impl fmt::Display for DifferencePredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.op { - DistanceOp::Similar => write!(f, "var - original <= {}", self.distance), - DistanceOp::Different => write!(f, "{} < var - original", self.distance), - } + write!(f, "diff var original") } } @@ -129,40 +67,14 @@ impl fmt::Display for DifferencePredicate { /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::diff("Hello World"); -/// assert_eq!(false, predicate_fn.eval("Hello World")); -/// assert_eq!(true, predicate_fn.eval("Goodbye World")); -/// ``` -pub fn diff(orig: S) -> DifferencePredicate -where - S: Into>, -{ - DifferencePredicate { - orig: orig.into(), - split: "\n".into(), - distance: 0, - op: DistanceOp::Different, - } -} - -/// Creates a new `Predicate` that checks strings for how similar they are. -/// -/// # Examples -/// -/// ``` -/// use predicates::prelude::*; -/// -/// let predicate_fn = predicate::str::similar("Hello World"); /// assert_eq!(true, predicate_fn.eval("Hello World")); +/// assert!(predicate_fn.find_case(false, "Hello World").is_none()); /// assert_eq!(false, predicate_fn.eval("Goodbye World")); +/// assert!(predicate_fn.find_case(false, "Goodbye World").is_some()); /// ``` -pub fn similar(orig: S) -> DifferencePredicate +pub fn diff(orig: S) -> DifferencePredicate where S: Into>, { - DifferencePredicate { - orig: orig.into(), - split: "\n".into(), - distance: 0, - op: DistanceOp::Similar, - } + DifferencePredicate { orig: orig.into() } } diff --git a/src/str/mod.rs b/src/str/mod.rs index d1f864e..0d0dffd 100644 --- a/src/str/mod.rs +++ b/src/str/mod.rs @@ -15,10 +15,10 @@ pub use self::basics::*; mod adapters; pub use self::adapters::*; -#[cfg(feature = "difference")] +#[cfg(feature = "diff")] mod difference; -#[cfg(feature = "difference")] -pub use self::difference::{diff, similar, DifferencePredicate}; +#[cfg(feature = "diff")] +pub use self::difference::{diff, DifferencePredicate}; #[cfg(feature = "normalize-line-endings")] mod normalize; #[cfg(feature = "normalize-line-endings")]