From 542fc71d8f9b39658c13991bab3bb84b9b8cf044 Mon Sep 17 00:00:00 2001 From: haraldmaida Date: Sat, 27 Dec 2025 12:43:21 +0100 Subject: [PATCH 1/3] feat: implement `any_match`, `all_match`, and `none_match` for collections and iterators --- src/assertions.rs | 69 ++++++++++++++- src/expectations.rs | 35 ++++++++ src/iterator/mod.rs | 191 +++++++++++++++++++++++++++++++++--------- src/iterator/tests.rs | 141 +++++++++++++++++++++++++++++++ src/lib.rs | 15 ++++ 5 files changed, 412 insertions(+), 39 deletions(-) diff --git a/src/assertions.rs b/src/assertions.rs index 25bf397..fa2e6c7 100644 --- a/src/assertions.rs +++ b/src/assertions.rs @@ -3661,6 +3661,8 @@ pub trait AssertMapContainsValue { /// /// # Examples /// +/// Filtering elements: +/// /// ``` /// use asserting::prelude::*; /// @@ -3670,6 +3672,21 @@ pub trait AssertMapContainsValue { /// let subject = [1, 2, 3, 4, 5]; /// assert_that!(subject).filtered_on(|e| e & 1 == 0).contains_exactly_in_any_order([2, 4]); /// ``` +/// +/// Some elements match a predicate: +/// +/// ``` +/// use asserting::prelude::*; +/// +/// let subject = [1, 41, 43, 42, 5]; +/// assert_that!(subject).any_match(|e| *e == 42); +/// +/// let subject = [43, 44, 45, 46, 47]; +/// assert_that!(subject).all_match(|e| *e > 42); +/// +/// let subject = [42, 43, 44, 45, 46]; +/// assert_that!(subject).none_match(|e| *e < 42); +/// ``` pub trait AssertElements<'a, T, R> { /// Verify that the iterator contains exactly one element and return a /// [`Spec`] for that single element. @@ -3706,7 +3723,57 @@ pub trait AssertElements<'a, T, R> { /// .is_equal_to("three"); /// ``` #[track_caller] - fn filtered_on(self, condition: impl Fn(&T) -> bool) -> Spec<'a, Vec, R>; + fn filtered_on(self, condition: C) -> Spec<'a, Vec, R> + where + C: FnMut(&T) -> bool; + + /// Verify that any element of a collection or an iterator matches a given + /// predicate. + /// + /// # Examples + /// + /// ``` + /// use asserting::prelude::*; + /// + /// let subject = [1, 41, 43, 42, 5]; + /// assert_that!(subject).any_match(|e| *e == 42); + /// ``` + #[track_caller] + fn any_match

(self, predicate: P) -> Spec<'a, Vec, R> + where + P: FnMut(&T) -> bool; + + /// Verify that all elements of a collection or an iterator matches a given + /// predicate. + /// + /// # Examples + /// + /// ``` + /// use asserting::prelude::*; + /// + /// let subject = [43, 44, 45, 46, 47]; + /// assert_that!(subject).all_match(|e| *e > 42); + /// ``` + #[track_caller] + fn all_match

(self, predicate: P) -> Spec<'a, Vec, R> + where + P: FnMut(&T) -> bool; + + /// Verify that none of the elements of a collection or an iterator matches + /// a given predicate. + /// + /// # Examples + /// + /// ``` + /// use asserting::prelude::*; + /// + /// let subject = [42, 43, 44, 45, 46]; + /// assert_that!(subject).none_match(|e| *e < 42); + /// ``` + #[track_caller] + fn none_match

(self, predicate: P) -> Spec<'a, Vec, R> + where + P: FnMut(&T) -> bool; } /// Filter assertions for elements of a collection or an iterator that yields diff --git a/src/expectations.rs b/src/expectations.rs index b067f75..be30240 100644 --- a/src/expectations.rs +++ b/src/expectations.rs @@ -1197,6 +1197,41 @@ pub struct HasAtLeastNumberOfElements { pub expected_number_of_elements: usize, } +pub fn any_match

(predicate: P) -> AnyMatch

{ + AnyMatch { predicate } +} + +#[must_use] +pub struct AnyMatch

{ + pub predicate: P, +} + +pub fn all_match

(predicate: P) -> AllMatch

{ + AllMatch { + predicate, + not_matching: HashSet::new(), + } +} + +#[must_use] +pub struct AllMatch

{ + pub predicate: P, + pub not_matching: HashSet, +} + +pub fn none_match

(predicate: P) -> NoneMatch

{ + NoneMatch { + predicate, + matching: HashSet::new(), + } +} + +#[must_use] +pub struct NoneMatch

{ + pub predicate: P, + pub matching: HashSet, +} + /// Creates a [`MapContainsKey`] expectation. pub fn map_contains_key(expected_key: E) -> MapContainsKey { MapContainsKey { expected_key } diff --git a/src/iterator/mod.rs b/src/iterator/mod.rs index fece921..726d0bc 100644 --- a/src/iterator/mod.rs +++ b/src/iterator/mod.rs @@ -9,14 +9,15 @@ use crate::colored::{ mark_selected_items_in_collection, mark_unexpected, mark_unexpected_string, }; use crate::expectations::{ - has_at_least_number_of_elements, has_single_element, iterator_contains, + all_match, any_match, has_at_least_number_of_elements, has_single_element, iterator_contains, iterator_contains_all_in_order, iterator_contains_all_of, iterator_contains_any_of, iterator_contains_exactly, iterator_contains_exactly_in_any_order, iterator_contains_only, iterator_contains_only_once, iterator_contains_sequence, iterator_ends_with, - iterator_starts_with, not, HasAtLeastNumberOfElements, HasSingleElement, IteratorContains, - IteratorContainsAllInOrder, IteratorContainsAllOf, IteratorContainsAnyOf, - IteratorContainsExactly, IteratorContainsExactlyInAnyOrder, IteratorContainsOnly, - IteratorContainsOnlyOnce, IteratorContainsSequence, IteratorEndsWith, IteratorStartsWith, + iterator_starts_with, none_match, not, AllMatch, AnyMatch, HasAtLeastNumberOfElements, + HasSingleElement, IteratorContains, IteratorContainsAllInOrder, IteratorContainsAllOf, + IteratorContainsAnyOf, IteratorContainsExactly, IteratorContainsExactlyInAnyOrder, + IteratorContainsOnly, IteratorContainsOnlyOnce, IteratorContainsSequence, IteratorEndsWith, + IteratorStartsWith, NoneMatch, }; use crate::properties::DefinedOrderProperty; use crate::spec::{ @@ -775,6 +776,55 @@ where } } +impl<'a, S, T, R> AssertElements<'a, T, R> for Spec<'a, S, R> +where + S: IntoIterator, + T: Debug, + R: FailingStrategy, +{ + fn single_element(self) -> Spec<'a, T, R> { + let spec = self.mapping(Vec::from_iter).expecting(has_single_element()); + if spec.has_failures() { + PanicOnFail.do_fail_with(&spec.failures()); + unreachable!("Assertion failed and should have panicked! Please report a bug.") + } + spec.extracting(|mut collection| { + collection.pop().unwrap_or_else(|| { + unreachable!("Assertion failed and should have panicked! Please report a bug.") + }) + }) + } + + fn filtered_on(self, condition: C) -> Spec<'a, Vec, R> + where + C: FnMut(&T) -> bool, + { + self.mapping(|subject| subject.into_iter().filter(condition).collect()) + } + + fn any_match

(self, predicate: P) -> Spec<'a, Vec, R> + where + P: FnMut(&T) -> bool, + { + self.mapping(Vec::from_iter).expecting(any_match(predicate)) + } + + fn all_match

(self, predicate: P) -> Spec<'a, Vec, R> + where + P: FnMut(&T) -> bool, + { + self.mapping(Vec::from_iter).expecting(all_match(predicate)) + } + + fn none_match

(self, predicate: P) -> Spec<'a, Vec, R> + where + P: FnMut(&T) -> bool, + { + self.mapping(Vec::from_iter) + .expecting(none_match(predicate)) + } +} + impl Expectation> for HasSingleElement where T: Debug, @@ -804,36 +854,74 @@ where } } -impl<'a, S, T, R> AssertElements<'a, T, R> for Spec<'a, S, R> +impl Expectation> for AnyMatch

where - S: IntoIterator, T: Debug, - R: FailingStrategy, + P: FnMut(&T) -> bool, { - fn single_element(self) -> Spec<'a, T, R> { - let spec = self.mapping(Vec::from_iter).expecting(has_single_element()); - if spec.has_failures() { - PanicOnFail.do_fail_with(&spec.failures()); - unreachable!("Assertion failed and should have panicked! Please report a bug.") + fn test(&mut self, subject: &Vec) -> bool { + subject.iter().any(|e| (self.predicate)(e)) + } + + fn message( + &self, + expression: &Expression<'_>, + actual: &Vec, + _inverted: bool, + _format: &DiffFormat, + ) -> String { + format!( + r"expected any element of {expression} to match the predicate, but none did match + actual: {actual:?}" + ) + } +} + +impl Expectation> for AllMatch

+where + T: Debug, + P: FnMut(&T) -> bool, +{ + fn test(&mut self, subject: &Vec) -> bool { + for (i, e) in subject.iter().enumerate() { + if !(self.predicate)(e) { + self.not_matching.insert(i); + } } - spec.extracting(|mut collection| { - collection.pop().unwrap_or_else(|| { - unreachable!("Assertion failed and should have panicked! Please report a bug.") - }) - }) + self.not_matching.is_empty() } - fn filtered_on(self, condition: impl Fn(&T) -> bool) -> Spec<'a, Vec, R> { - self.mapping(|subject| subject.into_iter().filter(condition).collect()) + fn message( + &self, + expression: &Expression<'_>, + actual: &Vec, + _inverted: bool, + format: &DiffFormat, + ) -> String { + let number_not_matching = self.not_matching.len(); + let not_matching = collect_selected_values(&self.not_matching, actual); + let marked_actual = + mark_selected_items_in_collection(actual, &self.not_matching, format, mark_unexpected); + format!( + r"expected all elements of {expression} to match the predicate, but {number_not_matching} did not match + actual: {marked_actual} + not matching: {not_matching:?}" + ) } } -impl Expectation> for HasAtLeastNumberOfElements +impl Expectation> for NoneMatch

where T: Debug, + P: FnMut(&T) -> bool, { fn test(&mut self, subject: &Vec) -> bool { - subject.len() >= self.expected_number_of_elements + for (i, e) in subject.iter().enumerate() { + if (self.predicate)(e) { + self.matching.insert(i); + } + } + self.matching.is_empty() } fn message( @@ -843,23 +931,14 @@ where _inverted: bool, format: &DiffFormat, ) -> String { - let actual_length = actual.len(); - let actual_elements = match actual_length { - 0 => mark_unexpected_string("no elements", format), - 1 => mark_unexpected_string("one element", format), - _ => mark_unexpected_string(&format!("{actual_length} elements"), format), - }; - let expected_elements = match self.expected_number_of_elements { - 0 => mark_missing_string("no elements", format), - 1 => mark_missing_string("at least one element", format), - _ => mark_missing_string( - &format!("at least {} elements", self.expected_number_of_elements), - format, - ), - }; + let number_of_matches = self.matching.len(); + let matching = collect_selected_values(&self.matching, actual); + let marked_actual = + mark_selected_items_in_collection(actual, &self.matching, format, mark_unexpected); format!( - r"expected {expression} to have {expected_elements}, but has {actual_elements} - actual: {actual:?}" + r"expected none of the elements of {expression} to match the predicate, but {number_of_matches} did match + actual: {marked_actual} + matching: {matching:?}" ) } } @@ -921,6 +1000,42 @@ where } } +impl Expectation> for HasAtLeastNumberOfElements +where + T: Debug, +{ + fn test(&mut self, subject: &Vec) -> bool { + subject.len() >= self.expected_number_of_elements + } + + fn message( + &self, + expression: &Expression<'_>, + actual: &Vec, + _inverted: bool, + format: &DiffFormat, + ) -> String { + let actual_length = actual.len(); + let actual_elements = match actual_length { + 0 => mark_unexpected_string("no elements", format), + 1 => mark_unexpected_string("one element", format), + _ => mark_unexpected_string(&format!("{actual_length} elements"), format), + }; + let expected_elements = match self.expected_number_of_elements { + 0 => mark_missing_string("no elements", format), + 1 => mark_missing_string("at least one element", format), + _ => mark_missing_string( + &format!("at least {} elements", self.expected_number_of_elements), + format, + ), + }; + format!( + r"expected {expression} to have {expected_elements}, but has {actual_elements} + actual: {actual:?}" + ) + } +} + pub fn collect_selected_values<'a, T>(indices: &HashSet, collection: &'a [T]) -> Vec<&'a T> { collection .iter() diff --git a/src/iterator/tests.rs b/src/iterator/tests.rs index c0d9794..7439217 100644 --- a/src/iterator/tests.rs +++ b/src/iterator/tests.rs @@ -458,4 +458,145 @@ mod element_filters { .elements_at([0, 2, 4]) .contains_exactly(["one", "three", "five"]); } + + #[test] + fn any_match_on_elements_of_iterator_value_is_equal_to_42() { + let subject = CustomCollection { + inner: vec![1, 41, 43, 42, 5], + }; + + assert_that(subject).any_match(|e| *e == 42); + } + + #[test] + fn verify_any_match_on_elements_of_iterator_value_is_equal_to_42_fails() { + let subject = CustomCollection { + inner: vec![1, 2, 43, 41, 5], + }; + + let failures = verify_that(subject) + .named("my_numbers") + .any_match(|e| *e == 42) + .display_failures(); + + assert_eq!( + failures, + &[ + r"expected any element of my_numbers to match the predicate, but none did match + actual: [1, 2, 43, 41, 5] +" + ] + ); + } + + #[test] + fn all_match_on_elements_of_iterator_value_is_greater_than_42() { + let subject = CustomCollection { + inner: vec![47, 46, 45, 44, 43], + }; + + assert_that(subject).all_match(|e| *e > 42); + } + + #[test] + fn verify_all_match_on_elements_of_iterator_value_is_greater_than_42_fails() { + let subject = CustomCollection { + inner: vec![43, 44, 45, 42, 47], + }; + + let failures = verify_that(subject) + .named("my_numbers") + .all_match(|e| *e > 42) + .display_failures(); + + assert_eq!( + failures, + &[ + r"expected all elements of my_numbers to match the predicate, but 1 did not match + actual: [43, 44, 45, 42, 47] + not matching: [42] +" + ] + ); + } + + #[test] + fn none_match_on_elements_of_iterator_value_is_greater_than_42() { + let subject = CustomCollection { + inner: vec![42, 41, 40, 39, 38], + }; + + assert_that(subject).none_match(|e| *e > 42); + } + + #[test] + fn verify_none_match_on_elements_of_iterator_value_is_greater_than_42_fails() { + let subject = CustomCollection { + inner: vec![41, 43, 45, 42, 47], + }; + + let failures = verify_that(subject) + .named("my_numbers") + .none_match(|e| *e > 42) + .display_failures(); + + assert_eq!( + failures, + &[ + r"expected none of the elements of my_numbers to match the predicate, but 3 did match + actual: [41, 43, 45, 42, 47] + matching: [43, 45, 47] +" + ] + ); + } + + #[cfg(feature = "colored")] + mod colored { + use super::*; + + #[test] + fn highlight_all_match_on_elements_of_iterator() { + let subject = CustomCollection { + inner: vec![43, 44, 45, 42, 47], + }; + + let failures = verify_that(subject) + .named("my_numbers") + .with_diff_format(DIFF_FORMAT_RED_YELLOW) + .all_match(|e| *e > 42) + .display_failures(); + + assert_eq!( + failures, + &[ + "expected all elements of my_numbers to match the predicate, but 1 did not match\n \ + actual: [43, 44, 45, \u{1b}[31m42\u{1b}[0m, 47]\n \ + not matching: [42]\n" + ] + ); + } + + #[test] + fn highlight_none_match_on_elements_of_iterator() { + let subject = CustomCollection { + inner: vec![41, 43, 45, 42, 47], + }; + + let failures = verify_that(subject) + .named("my_numbers") + .with_diff_format(DIFF_FORMAT_RED_YELLOW) + .none_match(|e| *e > 42) + .display_failures(); + + assert_eq!( + failures, + &[ + "expected none of the elements of my_numbers to match the predicate, but 3 did match\n \ + actual: [41, \u{1b}[31m43\u{1b}[0m, \u{1b}[31m45\u{1b}[0m, 42, \u{1b}[31m47\u{1b}[0m]\n \ + matching: [43, 45, 47]\n" + ] + ); + } + } } diff --git a/src/lib.rs b/src/lib.rs index e79c1a7..d9d7482 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,6 +198,21 @@ //! .contains_exactly(["one", "three", "five"]); //! ``` //! +//! Assert some elements of a collection or an iterator match a predicate: +//! +//! ``` +//! use asserting::prelude::*; +//! +//! let subject = [1, 41, 43, 42, 5]; +//! assert_that!(subject).any_match(|e| *e == 42); +//! +//! let subject = [43, 44, 45, 46, 47]; +//! assert_that!(subject).all_match(|e| *e > 42); +//! +//! let subject = [42, 43, 44, 45, 46]; +//! assert_that!(subject).none_match(|e| *e < 42); +//! ``` +//! //! ## Soft assertions //! //! ```should_panic From b2c24f9e71fe9d3b9d15aff06d649779e4dce558 Mon Sep 17 00:00:00 2001 From: haraldmaida Date: Sat, 27 Dec 2025 12:47:35 +0100 Subject: [PATCH 2/3] doc: document new assertions `any_match`, `all_match`, and `none_match` in README --- README.md | 3 +++ src/assertions.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 213bdb2..dbb0051 100644 --- a/README.md +++ b/README.md @@ -419,6 +419,9 @@ for all iterators. | contains_only_once | verify that an iterator/collection contains only the specified values in any order and each of them only once | | single_element | verify that an iterator/collection contains exaclty one element and return a `Spec` for that one element | | filtered_on | filter the elements of an iterator/collection on a condition and return a `Spec` that contains the filtered elements | +| any_match | verify that any element of an iterator/collection matches a predicate | +| all_match | verify that all elements of an iterator/collection match a predicate | +| none_match | verify that none of the elements of an iterator/collection match a predicate | for iterators that yield items in a well-defined order. diff --git a/src/assertions.rs b/src/assertions.rs index fa2e6c7..b6dd7bf 100644 --- a/src/assertions.rs +++ b/src/assertions.rs @@ -3743,7 +3743,7 @@ pub trait AssertElements<'a, T, R> { where P: FnMut(&T) -> bool; - /// Verify that all elements of a collection or an iterator matches a given + /// Verify that all elements of a collection or an iterator match a given /// predicate. /// /// # Examples @@ -3759,7 +3759,7 @@ pub trait AssertElements<'a, T, R> { where P: FnMut(&T) -> bool; - /// Verify that none of the elements of a collection or an iterator matches + /// Verify that none of the elements of a collection or an iterator match /// a given predicate. /// /// # Examples From 32051f1796325448e44db16121434ab59aa081ce Mon Sep 17 00:00:00 2001 From: haraldmaida Date: Sat, 27 Dec 2025 19:25:41 +0100 Subject: [PATCH 3/3] refactor: rename assertions `any_match` to `any_satisfies`, `all_match` to `all_satisfy`, and `none_match` to `none_satisfies` --- README.md | 6 ++-- src/assertions.rs | 28 ++++++++--------- src/expectations.rs | 26 ++++++++-------- src/iterator/mod.rs | 72 ++++++++++++++++++++++--------------------- src/iterator/tests.rs | 58 +++++++++++++++++----------------- src/lib.rs | 34 ++++++++++---------- 6 files changed, 114 insertions(+), 110 deletions(-) diff --git a/README.md b/README.md index dbb0051..e22a4c4 100644 --- a/README.md +++ b/README.md @@ -419,9 +419,9 @@ for all iterators. | contains_only_once | verify that an iterator/collection contains only the specified values in any order and each of them only once | | single_element | verify that an iterator/collection contains exaclty one element and return a `Spec` for that one element | | filtered_on | filter the elements of an iterator/collection on a condition and return a `Spec` that contains the filtered elements | -| any_match | verify that any element of an iterator/collection matches a predicate | -| all_match | verify that all elements of an iterator/collection match a predicate | -| none_match | verify that none of the elements of an iterator/collection match a predicate | +| any_satisfies | verify that any element of an iterator/collection satisfies a predicate | +| all_satisfy | verify that all elements of an iterator/collection satisfy a predicate | +| none_satisfies | verify that none of the elements of an iterator/collection satisfies a predicate | for iterators that yield items in a well-defined order. diff --git a/src/assertions.rs b/src/assertions.rs index b6dd7bf..333d5b6 100644 --- a/src/assertions.rs +++ b/src/assertions.rs @@ -3673,19 +3673,19 @@ pub trait AssertMapContainsValue { /// assert_that!(subject).filtered_on(|e| e & 1 == 0).contains_exactly_in_any_order([2, 4]); /// ``` /// -/// Some elements match a predicate: +/// Some elements satisfy a predicate: /// /// ``` /// use asserting::prelude::*; /// /// let subject = [1, 41, 43, 42, 5]; -/// assert_that!(subject).any_match(|e| *e == 42); +/// assert_that!(subject).any_satisfies(|e| *e == 42); /// /// let subject = [43, 44, 45, 46, 47]; -/// assert_that!(subject).all_match(|e| *e > 42); +/// assert_that!(subject).all_satisfy(|e| *e > 42); /// /// let subject = [42, 43, 44, 45, 46]; -/// assert_that!(subject).none_match(|e| *e < 42); +/// assert_that!(subject).none_satisfies(|e| *e < 42); /// ``` pub trait AssertElements<'a, T, R> { /// Verify that the iterator contains exactly one element and return a @@ -3727,7 +3727,7 @@ pub trait AssertElements<'a, T, R> { where C: FnMut(&T) -> bool; - /// Verify that any element of a collection or an iterator matches a given + /// Verify that any element of a collection or an iterator satisfies a given /// predicate. /// /// # Examples @@ -3736,14 +3736,14 @@ pub trait AssertElements<'a, T, R> { /// use asserting::prelude::*; /// /// let subject = [1, 41, 43, 42, 5]; - /// assert_that!(subject).any_match(|e| *e == 42); + /// assert_that!(subject).any_satisfies(|e| *e == 42); /// ``` #[track_caller] - fn any_match

(self, predicate: P) -> Spec<'a, Vec, R> + fn any_satisfies

(self, predicate: P) -> Spec<'a, Vec, R> where P: FnMut(&T) -> bool; - /// Verify that all elements of a collection or an iterator match a given + /// Verify that all elements of a collection or an iterator satisfy a given /// predicate. /// /// # Examples @@ -3752,15 +3752,15 @@ pub trait AssertElements<'a, T, R> { /// use asserting::prelude::*; /// /// let subject = [43, 44, 45, 46, 47]; - /// assert_that!(subject).all_match(|e| *e > 42); + /// assert_that!(subject).all_satisfy(|e| *e > 42); /// ``` #[track_caller] - fn all_match

(self, predicate: P) -> Spec<'a, Vec, R> + fn all_satisfy

(self, predicate: P) -> Spec<'a, Vec, R> where P: FnMut(&T) -> bool; - /// Verify that none of the elements of a collection or an iterator match - /// a given predicate. + /// Verify that none of the elements of a collection or an iterator + /// satisfies a given predicate. /// /// # Examples /// @@ -3768,10 +3768,10 @@ pub trait AssertElements<'a, T, R> { /// use asserting::prelude::*; /// /// let subject = [42, 43, 44, 45, 46]; - /// assert_that!(subject).none_match(|e| *e < 42); + /// assert_that!(subject).none_satisfies(|e| *e < 42); /// ``` #[track_caller] - fn none_match

(self, predicate: P) -> Spec<'a, Vec, R> + fn none_satisfies

(self, predicate: P) -> Spec<'a, Vec, R> where P: FnMut(&T) -> bool; } diff --git a/src/expectations.rs b/src/expectations.rs index be30240..ccc4c6d 100644 --- a/src/expectations.rs +++ b/src/expectations.rs @@ -1197,39 +1197,39 @@ pub struct HasAtLeastNumberOfElements { pub expected_number_of_elements: usize, } -pub fn any_match

(predicate: P) -> AnyMatch

{ - AnyMatch { predicate } +pub fn any_satisfies

(predicate: P) -> AnySatisfies

{ + AnySatisfies { predicate } } #[must_use] -pub struct AnyMatch

{ +pub struct AnySatisfies

{ pub predicate: P, } -pub fn all_match

(predicate: P) -> AllMatch

{ - AllMatch { +pub fn all_satisfy

(predicate: P) -> AllSatisfy

{ + AllSatisfy { predicate, - not_matching: HashSet::new(), + failing: HashSet::new(), } } #[must_use] -pub struct AllMatch

{ +pub struct AllSatisfy

{ pub predicate: P, - pub not_matching: HashSet, + pub failing: HashSet, } -pub fn none_match

(predicate: P) -> NoneMatch

{ - NoneMatch { +pub fn none_satisfies

(predicate: P) -> NoneSatisfies

{ + NoneSatisfies { predicate, - matching: HashSet::new(), + failing: HashSet::new(), } } #[must_use] -pub struct NoneMatch

{ +pub struct NoneSatisfies

{ pub predicate: P, - pub matching: HashSet, + pub failing: HashSet, } /// Creates a [`MapContainsKey`] expectation. diff --git a/src/iterator/mod.rs b/src/iterator/mod.rs index 726d0bc..90e5284 100644 --- a/src/iterator/mod.rs +++ b/src/iterator/mod.rs @@ -9,15 +9,15 @@ use crate::colored::{ mark_selected_items_in_collection, mark_unexpected, mark_unexpected_string, }; use crate::expectations::{ - all_match, any_match, has_at_least_number_of_elements, has_single_element, iterator_contains, - iterator_contains_all_in_order, iterator_contains_all_of, iterator_contains_any_of, - iterator_contains_exactly, iterator_contains_exactly_in_any_order, iterator_contains_only, - iterator_contains_only_once, iterator_contains_sequence, iterator_ends_with, - iterator_starts_with, none_match, not, AllMatch, AnyMatch, HasAtLeastNumberOfElements, - HasSingleElement, IteratorContains, IteratorContainsAllInOrder, IteratorContainsAllOf, - IteratorContainsAnyOf, IteratorContainsExactly, IteratorContainsExactlyInAnyOrder, - IteratorContainsOnly, IteratorContainsOnlyOnce, IteratorContainsSequence, IteratorEndsWith, - IteratorStartsWith, NoneMatch, + all_satisfy, any_satisfies, has_at_least_number_of_elements, has_single_element, + iterator_contains, iterator_contains_all_in_order, iterator_contains_all_of, + iterator_contains_any_of, iterator_contains_exactly, iterator_contains_exactly_in_any_order, + iterator_contains_only, iterator_contains_only_once, iterator_contains_sequence, + iterator_ends_with, iterator_starts_with, none_satisfies, not, AllSatisfy, AnySatisfies, + HasAtLeastNumberOfElements, HasSingleElement, IteratorContains, IteratorContainsAllInOrder, + IteratorContainsAllOf, IteratorContainsAnyOf, IteratorContainsExactly, + IteratorContainsExactlyInAnyOrder, IteratorContainsOnly, IteratorContainsOnlyOnce, + IteratorContainsSequence, IteratorEndsWith, IteratorStartsWith, NoneSatisfies, }; use crate::properties::DefinedOrderProperty; use crate::spec::{ @@ -802,26 +802,28 @@ where self.mapping(|subject| subject.into_iter().filter(condition).collect()) } - fn any_match

(self, predicate: P) -> Spec<'a, Vec, R> + fn any_satisfies

(self, predicate: P) -> Spec<'a, Vec, R> where P: FnMut(&T) -> bool, { - self.mapping(Vec::from_iter).expecting(any_match(predicate)) + self.mapping(Vec::from_iter) + .expecting(any_satisfies(predicate)) } - fn all_match

(self, predicate: P) -> Spec<'a, Vec, R> + fn all_satisfy

(self, predicate: P) -> Spec<'a, Vec, R> where P: FnMut(&T) -> bool, { - self.mapping(Vec::from_iter).expecting(all_match(predicate)) + self.mapping(Vec::from_iter) + .expecting(all_satisfy(predicate)) } - fn none_match

(self, predicate: P) -> Spec<'a, Vec, R> + fn none_satisfies

(self, predicate: P) -> Spec<'a, Vec, R> where P: FnMut(&T) -> bool, { self.mapping(Vec::from_iter) - .expecting(none_match(predicate)) + .expecting(none_satisfies(predicate)) } } @@ -854,7 +856,7 @@ where } } -impl Expectation> for AnyMatch

+impl Expectation> for AnySatisfies

where T: Debug, P: FnMut(&T) -> bool, @@ -871,13 +873,13 @@ where _format: &DiffFormat, ) -> String { format!( - r"expected any element of {expression} to match the predicate, but none did match + r"expected any element of {expression} to satisfy the predicate, but none did actual: {actual:?}" ) } } -impl Expectation> for AllMatch

+impl Expectation> for AllSatisfy

where T: Debug, P: FnMut(&T) -> bool, @@ -885,10 +887,10 @@ where fn test(&mut self, subject: &Vec) -> bool { for (i, e) in subject.iter().enumerate() { if !(self.predicate)(e) { - self.not_matching.insert(i); + self.failing.insert(i); } } - self.not_matching.is_empty() + self.failing.is_empty() } fn message( @@ -898,19 +900,19 @@ where _inverted: bool, format: &DiffFormat, ) -> String { - let number_not_matching = self.not_matching.len(); - let not_matching = collect_selected_values(&self.not_matching, actual); + let number_of_failing = self.failing.len(); + let failing = collect_selected_values(&self.failing, actual); let marked_actual = - mark_selected_items_in_collection(actual, &self.not_matching, format, mark_unexpected); + mark_selected_items_in_collection(actual, &self.failing, format, mark_unexpected); format!( - r"expected all elements of {expression} to match the predicate, but {number_not_matching} did not match - actual: {marked_actual} - not matching: {not_matching:?}" + r"expected all elements of {expression} to satisfy the predicate, but {number_of_failing} did not + actual: {marked_actual} + failing: {failing:?}" ) } } -impl Expectation> for NoneMatch

+impl Expectation> for NoneSatisfies

where T: Debug, P: FnMut(&T) -> bool, @@ -918,10 +920,10 @@ where fn test(&mut self, subject: &Vec) -> bool { for (i, e) in subject.iter().enumerate() { if (self.predicate)(e) { - self.matching.insert(i); + self.failing.insert(i); } } - self.matching.is_empty() + self.failing.is_empty() } fn message( @@ -931,14 +933,14 @@ where _inverted: bool, format: &DiffFormat, ) -> String { - let number_of_matches = self.matching.len(); - let matching = collect_selected_values(&self.matching, actual); + let number_of_failing = self.failing.len(); + let failing = collect_selected_values(&self.failing, actual); let marked_actual = - mark_selected_items_in_collection(actual, &self.matching, format, mark_unexpected); + mark_selected_items_in_collection(actual, &self.failing, format, mark_unexpected); format!( - r"expected none of the elements of {expression} to match the predicate, but {number_of_matches} did match - actual: {marked_actual} - matching: {matching:?}" + r"expected none of the elements of {expression} to satisfy the predicate, but {number_of_failing} did + actual: {marked_actual} + failing: {failing:?}" ) } } diff --git a/src/iterator/tests.rs b/src/iterator/tests.rs index 7439217..8256dc1 100644 --- a/src/iterator/tests.rs +++ b/src/iterator/tests.rs @@ -460,29 +460,29 @@ mod element_filters { } #[test] - fn any_match_on_elements_of_iterator_value_is_equal_to_42() { + fn any_satisfies_on_elements_of_iterator_value_is_equal_to_42() { let subject = CustomCollection { inner: vec![1, 41, 43, 42, 5], }; - assert_that(subject).any_match(|e| *e == 42); + assert_that(subject).any_satisfies(|e| *e == 42); } #[test] - fn verify_any_match_on_elements_of_iterator_value_is_equal_to_42_fails() { + fn verify_any_satisfies_on_elements_of_iterator_value_is_equal_to_42_fails() { let subject = CustomCollection { inner: vec![1, 2, 43, 41, 5], }; let failures = verify_that(subject) .named("my_numbers") - .any_match(|e| *e == 42) + .any_satisfies(|e| *e == 42) .display_failures(); assert_eq!( failures, &[ - r"expected any element of my_numbers to match the predicate, but none did match + r"expected any element of my_numbers to satisfy the predicate, but none did actual: [1, 2, 43, 41, 5] " ] @@ -490,62 +490,62 @@ mod element_filters { } #[test] - fn all_match_on_elements_of_iterator_value_is_greater_than_42() { + fn all_satisfy_on_elements_of_iterator_value_is_greater_than_42() { let subject = CustomCollection { inner: vec![47, 46, 45, 44, 43], }; - assert_that(subject).all_match(|e| *e > 42); + assert_that(subject).all_satisfy(|e| *e > 42); } #[test] - fn verify_all_match_on_elements_of_iterator_value_is_greater_than_42_fails() { + fn verify_all_satisfy_on_elements_of_iterator_value_is_greater_than_42_fails() { let subject = CustomCollection { inner: vec![43, 44, 45, 42, 47], }; let failures = verify_that(subject) .named("my_numbers") - .all_match(|e| *e > 42) + .all_satisfy(|e| *e > 42) .display_failures(); assert_eq!( failures, &[ - r"expected all elements of my_numbers to match the predicate, but 1 did not match - actual: [43, 44, 45, 42, 47] - not matching: [42] + r"expected all elements of my_numbers to satisfy the predicate, but 1 did not + actual: [43, 44, 45, 42, 47] + failing: [42] " ] ); } #[test] - fn none_match_on_elements_of_iterator_value_is_greater_than_42() { + fn none_satisfies_on_elements_of_iterator_value_is_greater_than_42() { let subject = CustomCollection { inner: vec![42, 41, 40, 39, 38], }; - assert_that(subject).none_match(|e| *e > 42); + assert_that(subject).none_satisfies(|e| *e > 42); } #[test] - fn verify_none_match_on_elements_of_iterator_value_is_greater_than_42_fails() { + fn verify_none_satisfies_on_elements_of_iterator_value_is_greater_than_42_fails() { let subject = CustomCollection { inner: vec![41, 43, 45, 42, 47], }; let failures = verify_that(subject) .named("my_numbers") - .none_match(|e| *e > 42) + .none_satisfies(|e| *e > 42) .display_failures(); assert_eq!( failures, &[ - r"expected none of the elements of my_numbers to match the predicate, but 3 did match - actual: [41, 43, 45, 42, 47] - matching: [43, 45, 47] + r"expected none of the elements of my_numbers to satisfy the predicate, but 3 did + actual: [41, 43, 45, 42, 47] + failing: [43, 45, 47] " ] ); @@ -556,7 +556,7 @@ mod element_filters { use super::*; #[test] - fn highlight_all_match_on_elements_of_iterator() { + fn highlight_all_satisfy_on_elements_of_iterator() { let subject = CustomCollection { inner: vec![43, 44, 45, 42, 47], }; @@ -564,21 +564,21 @@ mod element_filters { let failures = verify_that(subject) .named("my_numbers") .with_diff_format(DIFF_FORMAT_RED_YELLOW) - .all_match(|e| *e > 42) + .all_satisfy(|e| *e > 42) .display_failures(); assert_eq!( failures, &[ - "expected all elements of my_numbers to match the predicate, but 1 did not match\n \ - actual: [43, 44, 45, \u{1b}[31m42\u{1b}[0m, 47]\n \ - not matching: [42]\n" + "expected all elements of my_numbers to satisfy the predicate, but 1 did not\n \ + actual: [43, 44, 45, \u{1b}[31m42\u{1b}[0m, 47]\n \ + failing: [42]\n" ] ); } #[test] - fn highlight_none_match_on_elements_of_iterator() { + fn highlight_none_satisfies_on_elements_of_iterator() { let subject = CustomCollection { inner: vec![41, 43, 45, 42, 47], }; @@ -586,15 +586,15 @@ mod element_filters { let failures = verify_that(subject) .named("my_numbers") .with_diff_format(DIFF_FORMAT_RED_YELLOW) - .none_match(|e| *e > 42) + .none_satisfies(|e| *e > 42) .display_failures(); assert_eq!( failures, &[ - "expected none of the elements of my_numbers to match the predicate, but 3 did match\n \ - actual: [41, \u{1b}[31m43\u{1b}[0m, \u{1b}[31m45\u{1b}[0m, 42, \u{1b}[31m47\u{1b}[0m]\n \ - matching: [43, 45, 47]\n" + "expected none of the elements of my_numbers to satisfy the predicate, but 3 did\n \ + actual: [41, \u{1b}[31m43\u{1b}[0m, \u{1b}[31m45\u{1b}[0m, 42, \u{1b}[31m47\u{1b}[0m]\n \ + failing: [43, 45, 47]\n" ] ); } diff --git a/src/lib.rs b/src/lib.rs index d9d7482..f8e49f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,7 +125,9 @@ //! .contains_only([1, 3, 5, 7, 9, 11, 13, 17, 19, 23, 29, 31, 37, 43]); //! ``` //! -//! ## Asserting each item of a collection or an iterator +//! ## Asserting some elements of a collection or an iterator +//! +//! Asserting some elements of a collection or an iterator: //! //! ``` //! use asserting::prelude::*; @@ -138,6 +140,21 @@ //! ); //! ``` //! +//! Assert some elements of a collection or an iterator to satisfy a predicate: +//! +//! ``` +//! use asserting::prelude::*; +//! +//! let subject = [1, 41, 43, 42, 5]; +//! assert_that!(subject).any_satisfies(|e| *e == 42); +//! +//! let subject = [43, 44, 45, 46, 47]; +//! assert_that!(subject).all_satisfy(|e| *e > 42); +//! +//! let subject = [42, 43, 44, 45, 46]; +//! assert_that!(subject).none_satisfies(|e| *e < 42); +//! ``` +//! //! For more details see [`Spec::each_item()`]. //! //! ## Asserting specific elements of a collection or an iterator @@ -198,21 +215,6 @@ //! .contains_exactly(["one", "three", "five"]); //! ``` //! -//! Assert some elements of a collection or an iterator match a predicate: -//! -//! ``` -//! use asserting::prelude::*; -//! -//! let subject = [1, 41, 43, 42, 5]; -//! assert_that!(subject).any_match(|e| *e == 42); -//! -//! let subject = [43, 44, 45, 46, 47]; -//! assert_that!(subject).all_match(|e| *e > 42); -//! -//! let subject = [42, 43, 44, 45, 46]; -//! assert_that!(subject).none_match(|e| *e < 42); -//! ``` -//! //! ## Soft assertions //! //! ```should_panic