From 51a9394c89113e1b3505ae7c69320f999608dd41 Mon Sep 17 00:00:00 2001 From: haraldmaida Date: Sat, 28 Mar 2026 12:06:14 +0100 Subject: [PATCH] refactor: Change assertion traits to define spec-like types returned by mapping assertion methods as associated type --- src/assertions.rs | 212 +++++++++++++++++++++++++++++++++----------- src/error/mod.rs | 9 +- src/iterator/mod.rs | 56 +++++++----- src/mapping.rs | 12 ++- src/option/mod.rs | 12 ++- src/panic/mod.rs | 10 ++- src/result/mod.rs | 30 ++++--- 7 files changed, 238 insertions(+), 103 deletions(-) diff --git a/src/assertions.rs b/src/assertions.rs index a493d5b..59626dd 100644 --- a/src/assertions.rs +++ b/src/assertions.rs @@ -10,11 +10,9 @@ //! assertions. #![allow(clippy::wrong_self_convention, clippy::return_self_not_must_use)] -use crate::spec::Spec; use crate::std::fmt::Debug; use crate::std::ops::RangeBounds; use crate::std::string::String; -use crate::std::vec::Vec; /// Assert whether two values are equal or not. /// @@ -1883,7 +1881,13 @@ pub trait AssertOption { /// let subject: Option<&str> = Some("ullamco cupiditat diam hendrerit"); /// assert_that!(subject).some().is_not_empty(); /// ``` -pub trait AssertOptionValue<'a, T, R> { +pub trait AssertOptionValue { + /// A spec-like type that contains the option's value as the subject, which + /// is returned by the mapping assertion method. + /// + /// If the subject is an `Option`, this is usually `Spec<'a, T, R>`. + type Some; + /// Maps the subject to the option's value if it has some. Otherwise, this /// assertion fails. /// @@ -1899,7 +1903,7 @@ pub trait AssertOptionValue<'a, T, R> { /// assert_that!(subject).some().is_not_empty(); /// ``` #[track_caller] - fn some(self) -> Spec<'a, T, R>; + fn some(self) -> Self::Some; } /// Assert the value of a borrowed option by mapping the subject. @@ -1917,7 +1921,13 @@ pub trait AssertOptionValue<'a, T, R> { /// let subject: Option<&str> = Some("ullamco cupiditat diam hendrerit"); /// assert_that!(&subject).some().is_not_empty(); /// ``` -pub trait AssertBorrowedOptionValue<'a, T, R> { +pub trait AssertBorrowedOptionValue { + /// A spec-like type that contains the option's borrowed value as the + /// subject, which is returned by the mapping assertion method. + /// + /// If the subject is an `Option<&T>`, this is usually `Spec<'a, &'a T, R>`. + type Some; + /// Maps the subject to the option's value if it has some. Otherwise, this /// assertion fails. /// @@ -1933,7 +1943,7 @@ pub trait AssertBorrowedOptionValue<'a, T, R> { /// assert_that!(&subject).some().is_not_empty(); /// ``` #[track_caller] - fn some(self) -> Spec<'a, &'a T, R>; + fn some(self) -> Self::Some; } /// Assert whether a subject of the `Result` type holds some value or an error. @@ -1990,7 +2000,18 @@ pub trait AssertResult { /// let subject: Result = Err("te anim adipisici mollit".to_string()); /// assert_that!(subject).err().is_equal_to("te anim adipisici mollit"); /// ``` -pub trait AssertResultValue<'a, T, E, R> { +pub trait AssertResultValue { + /// A spec-like type that contains the result's ok value as the subject, + /// which is returned by the mapping assertion method. + /// + /// If the subject is a `Result`, this is usually `Spec<'a, T, R>`. + type Ok; + /// A spec-like type that contains the result's error value as the subject, + /// which is returned by the mapping assertion method. + /// + /// If the subject is a `Result`, this is usually `Spec<'a, E, R>`. + type Err; + /// Maps the subject to the result's ok value. /// /// If the result is an error, this method panics. @@ -2004,7 +2025,7 @@ pub trait AssertResultValue<'a, T, E, R> { /// assert_that!(subject).ok().is_not_empty(); /// ``` #[track_caller] - fn ok(self) -> Spec<'a, T, R>; + fn ok(self) -> Self::Ok; /// Maps the subject to the result's err value. /// @@ -2019,7 +2040,7 @@ pub trait AssertResultValue<'a, T, E, R> { /// assert_that!(subject).err().is_equal_to("te anim adipisici mollit"); /// ``` #[track_caller] - fn err(self) -> Spec<'a, E, R>; + fn err(self) -> Self::Err; } /// Assert the ok-value or error of a borrowed result by mapping the subject. @@ -2035,7 +2056,18 @@ pub trait AssertResultValue<'a, T, E, R> { /// let subject: Result = Err("te anim adipisici mollit".to_string()); /// assert_that!(&subject).err().is_equal_to("te anim adipisici mollit"); /// ``` -pub trait AssertBorrowedResultValue<'a, T, E, R> { +pub trait AssertBorrowedResultValue { + /// A spec-like type that contains the result's borrowed ok value as the + /// subject, which is returned by the mapping assertion method. + /// + /// If the subject is a `Result`, this is usually `Spec<'a, &'a T, R>`. + type Ok; + /// A spec-like type that contains the result's borrowed error value as the + /// subject, which is returned by the mapping assertion method. + /// + /// If the subject is a `Result`, this is usually `Spec<'a, &'a E, R>`. + type Err; + /// Maps the subject to the result's ok value. /// /// If the result is an error, this method panics. @@ -2049,7 +2081,7 @@ pub trait AssertBorrowedResultValue<'a, T, E, R> { /// assert_that!(&subject).ok().contains_exactly(&[1, 2, 3]); /// ``` #[track_caller] - fn ok(self) -> Spec<'a, &'a T, R>; + fn ok(self) -> Self::Ok; /// Maps the subject to the result's err value. /// @@ -2064,7 +2096,7 @@ pub trait AssertBorrowedResultValue<'a, T, E, R> { /// assert_that!(&subject).err().is_equal_to("te anim adipisici mollit"); /// ``` #[track_caller] - fn err(self) -> Spec<'a, &'a E, R>; + fn err(self) -> Self::Err; } /// Assert that a subject of some container type holds a value that is equal to @@ -2172,7 +2204,13 @@ pub trait AssertHasError { /// let subject: Result<(), anyhow::Error> = Err(anyhow!("mollit in ullamcorper no".to_string())); /// assert_that!(subject).has_error_message("mollit in ullamcorper no"); /// ``` -pub trait AssertHasErrorMessage<'a, E, R> { +pub trait AssertHasErrorMessage { + /// A spec-like type that contains the error message as the subject, + /// which is returned by the mapping assertion method. + /// + /// This is usually a `Spec<'a, String, R>`. + type ErrorMessage; + /// Verifies that the subject is an error value with the expected message. /// /// This is useful for opaque error types that do not implement @@ -2192,7 +2230,7 @@ pub trait AssertHasErrorMessage<'a, E, R> { /// assert_that!(subject).has_error_message("mollit in ullamcorper no"); /// ``` #[track_caller] - fn has_error_message(self, expected_message: E) -> Spec<'a, String, R>; + fn has_error_message(self, expected_message: E) -> Self::ErrorMessage; } /// Assert the source of any type that implements `std::error::Error`. @@ -2247,7 +2285,13 @@ pub trait AssertHasErrorMessage<'a, E, R> { /// assert_that!(&error).has_source(); /// assert_that!(&error).has_source_message("foo error"); /// ``` -pub trait AssertErrorHasSource<'a, R> { +pub trait AssertErrorHasSource { + /// A spec-like type that contains the source message as the subject, + /// which is returned by the mapping assertion method. + /// + /// This is usually a `Spec<'a, String, R>`. + type SourceMessage; + /// Verifies that an error has no source. /// /// # Example @@ -2406,10 +2450,7 @@ pub trait AssertErrorHasSource<'a, R> { /// assert_that!(result).err().has_source_message("foo error"); /// ``` #[track_caller] - fn has_source_message( - self, - expected_source_message: impl Into, - ) -> Spec<'a, Option, R>; + fn has_source_message(self, expected_source_message: impl Into) -> Self::SourceMessage; } /// Assert a type formatted into a debug string. @@ -2492,7 +2533,13 @@ pub trait AssertHasDebugString { /// assert_that!(&subject).debug_string().contains("World"); /// assert_that!(&subject).debug_string().does_not_start_with("Bar"); /// ``` -pub trait AssertDebugString<'a, R> { +pub trait AssertDebugString { + /// A spec-like type that contains the debug string as the subject, + /// which is returned by the mapping assertion method. + /// + /// This is usually a `Spec<'a, String, R>`. + type DebugString; + /// Maps the subject into its debug string representation to do assertions /// on its debug string. /// @@ -2512,7 +2559,7 @@ pub trait AssertDebugString<'a, R> { /// assert_that!(&subject).debug_string().does_not_start_with("Bar"); /// ``` #[track_caller] - fn debug_string(self) -> Spec<'a, String, R>; + fn debug_string(self) -> Self::DebugString; } /// Assert a type formatted into a display string. @@ -2615,7 +2662,13 @@ pub trait AssertHasDisplayString { /// assert_that!(&subject).display_string().is_equal_to("Hello, World"); /// assert_that!(&subject).display_string().does_not_end_with('!'); /// ``` -pub trait AssertDisplayString<'a, R> { +pub trait AssertDisplayString { + /// A spec-like type that contains the display string as the subject, + /// which is returned by the mapping assertion method. + /// + /// This is usually a `Spec<'a, String, R>`. + type DisplayString; + /// Maps the subject into its display string representation to do assertions /// on its display string. /// @@ -2640,7 +2693,7 @@ pub trait AssertDisplayString<'a, R> { /// assert_that!(&subject).display_string().does_not_end_with('!'); /// ``` #[track_caller] - fn display_string(self) -> Spec<'a, String, R>; + fn display_string(self) -> Self::DisplayString; } /// Assert that a string contains a substring or character. @@ -2895,7 +2948,14 @@ pub trait AssertStringMatches { /// let some_btree_map = BTreeMap::from_iter([('a', 3), ('b', 0), ('c', 8)]); /// assert_that!(some_btree_map).contains(('b', 0)); /// ``` -pub trait AssertIteratorContains<'a, U, E, R> { +pub trait AssertIteratorContains { + /// A spec-like type that contains the collected values from the iterator as + /// the subject, which is returned by the mapping assertion methods. + /// + /// Usually this a `Spec<'a, Vec, R>` with T as the type of the items + /// yielded by the iterator. + type Sequence; + /// Verifies that the actual collection/iterator contains at least one /// element that is equal to the expected value. /// @@ -2918,7 +2978,7 @@ pub trait AssertIteratorContains<'a, U, E, R> { /// assert_that!(some_btree_map).contains(('b', 0)); /// ``` #[track_caller] - fn contains(self, element: E) -> Spec<'a, U, R>; + fn contains(self, element: E) -> Self::Sequence; /// Verifies that the actual collection/iterator does not contain an element /// that is equal to the expected value. @@ -2942,7 +3002,7 @@ pub trait AssertIteratorContains<'a, U, E, R> { /// assert_that!(some_btree_map).does_not_contain(('d', 5)); /// ``` #[track_caller] - fn does_not_contain(self, element: E) -> Spec<'a, U, R>; + fn does_not_contain(self, element: E) -> Self::Sequence; } /// Assert values in a collection. @@ -2951,7 +3011,14 @@ pub trait AssertIteratorContains<'a, U, E, R> { /// over its values. They are implemented for any iterator over items that /// implement `PartialEq` with `E` being the type of the items in the /// expected collection or iterator. -pub trait AssertIteratorContainsInAnyOrder<'a, S, E, R> { +pub trait AssertIteratorContainsInAnyOrder { + /// A spec-like type that contains the collected values from the iterator as + /// the subject, which is returned by the mapping assertion methods. + /// + /// Usually this a `Spec<'a, Vec, R>` with T as the type of the items + /// yielded by the iterator. + type Sequence; + /// Verifies that the actual collection/iterator contains exactly the given /// values and nothing else in any order. /// @@ -2974,7 +3041,7 @@ pub trait AssertIteratorContainsInAnyOrder<'a, S, E, R> { /// assert_that!(some_btree_map).contains_exactly_in_any_order([('b', 0), ('a', 3), ('c', 8)]); /// ``` #[track_caller] - fn contains_exactly_in_any_order(self, expected: E) -> Spec<'a, S, R>; + fn contains_exactly_in_any_order(self, expected: E) -> Self::Sequence; /// Verifies that the actual collection/iterator contains at least one of /// the specified values. @@ -2998,7 +3065,7 @@ pub trait AssertIteratorContainsInAnyOrder<'a, S, E, R> { /// assert_that!(some_btree_map).contains_any_of([('x', 2), ('a', 3), ('y', 7)]); /// ``` #[track_caller] - fn contains_any_of(self, expected: E) -> Spec<'a, S, R>; + fn contains_any_of(self, expected: E) -> Self::Sequence; /// Verifies that the actual collection/iterator does not contain any of /// the specified values. @@ -3022,7 +3089,7 @@ pub trait AssertIteratorContainsInAnyOrder<'a, S, E, R> { /// assert_that!(some_btree_map).does_not_contain_any_of([('x', 2), ('z', 3), ('y', 7)]); /// ``` #[track_caller] - fn does_not_contain_any_of(self, expected: E) -> Spec<'a, S, R>; + fn does_not_contain_any_of(self, expected: E) -> Self::Sequence; /// Verifies that the actual collection/iterator contains the given values /// in any order. @@ -3049,7 +3116,7 @@ pub trait AssertIteratorContainsInAnyOrder<'a, S, E, R> { /// assert_that!(some_btree_map).contains_all_of([('a', 3), ('b', 0)]); /// ``` #[track_caller] - fn contains_all_of(self, expected: E) -> Spec<'a, S, R>; + fn contains_all_of(self, expected: E) -> Self::Sequence; /// Verifies that the actual collection/iterator contains only the given /// values and nothing else in any order and ignoring duplicates. @@ -3075,7 +3142,7 @@ pub trait AssertIteratorContainsInAnyOrder<'a, S, E, R> { /// assert_that!(some_btree_map).contains_only([('a', 3), ('b', 0), ('c', 8), ('d', 4)]); /// ``` #[track_caller] - fn contains_only(self, expected: E) -> Spec<'a, S, R>; + fn contains_only(self, expected: E) -> Self::Sequence; /// Verifies that the actual collection/iterator contains only the given /// values in any order and each of them only once. @@ -3098,14 +3165,21 @@ pub trait AssertIteratorContainsInAnyOrder<'a, S, E, R> { /// assert_that!(some_vec).contains_only_once([4, 6, 8, 10, 12, 15, 20]); /// ``` #[track_caller] - fn contains_only_once(self, expected: E) -> Spec<'a, S, R>; + fn contains_only_once(self, expected: E) -> Self::Sequence; } /// Assert values in an ordered collection. /// /// These assertions are applicable to collections which iterate over their /// values in a defined order. -pub trait AssertIteratorContainsInOrder<'a, S, E, R> { +pub trait AssertIteratorContainsInOrder { + /// A spec-like type that contains the collected values from the iterator as + /// the subject, which is returned by the mapping assertion methods. + /// + /// Usually this a `Spec<'a, Vec, R>` with T as the type of the items + /// yielded by the iterator. + type Sequence; + /// Verifies that the actual collection/iterator contains exactly the given /// values and nothing else in the given order. /// @@ -3128,7 +3202,7 @@ pub trait AssertIteratorContainsInOrder<'a, S, E, R> { /// assert_that!(some_btree_map).contains_exactly([('a', 3), ('b', 0), ('c', 8)]); /// ``` #[track_caller] - fn contains_exactly(self, expected: E) -> Spec<'a, S, R>; + fn contains_exactly(self, expected: E) -> Self::Sequence; /// Verifies that the actual collection/iterator contains the given sequence /// of values in the given order and without extra values between the @@ -3156,7 +3230,7 @@ pub trait AssertIteratorContainsInOrder<'a, S, E, R> { /// assert_that!(some_btree_map).contains_sequence([('a', 3), ('b', 0), ('c', 8)]); /// ``` #[track_caller] - fn contains_sequence(self, expected: E) -> Spec<'a, S, R>; + fn contains_sequence(self, expected: E) -> Self::Sequence; /// Verifies that the actual collection/iterator contains all the given /// values and in the given order, possibly with other values between them. @@ -3180,7 +3254,7 @@ pub trait AssertIteratorContainsInOrder<'a, S, E, R> { /// assert_that!(some_btree_map).contains_all_in_order([('a', 3), ('c', 8)]); /// ``` #[track_caller] - fn contains_all_in_order(self, expected: E) -> Spec<'a, S, R>; + fn contains_all_in_order(self, expected: E) -> Self::Sequence; /// Verifies that the actual collection/iterator contains the given values /// as the first elements in order. @@ -3204,7 +3278,7 @@ pub trait AssertIteratorContainsInOrder<'a, S, E, R> { /// assert_that!(some_btree_map).starts_with([('a', 3), ('b', 0)]); /// ``` #[track_caller] - fn starts_with(self, expected: E) -> Spec<'a, S, R>; + fn starts_with(self, expected: E) -> Self::Sequence; /// Verifies that the actual collection/iterator contains the given values /// as the last elements in order. @@ -3228,7 +3302,7 @@ pub trait AssertIteratorContainsInOrder<'a, S, E, R> { /// assert_that!(some_btree_map).ends_with([('b', 0), ('c', 8)]); /// ``` #[track_caller] - fn ends_with(self, expected: E) -> Spec<'a, S, R>; + fn ends_with(self, expected: E) -> Self::Sequence; } /// Assert the order of the values within a collection. @@ -3272,7 +3346,15 @@ pub trait AssertIsSorted { /// ``` #[cfg(feature = "panic")] #[cfg_attr(docsrs, doc(cfg(feature = "panic")))] -pub trait AssertCodePanics<'a, R> { +pub trait AssertCodePanics { + /// A spec-like type that contains the mapped type as subject, which is + /// returned by mapping assertion methods. + /// + /// For closures only one assertion method can be called. Therefore, the + /// spec-like type contains unit, to prevent calling more assertions. + /// Usually the mapped type is a `Spec<'a, (), R>`. + type Mapped; + /// Verifies that the actual code under test does not panic. /// /// # Example @@ -3291,7 +3373,7 @@ pub trait AssertCodePanics<'a, R> { /// }).does_not_panic(); /// ``` #[track_caller] - fn does_not_panic(self) -> Spec<'a, (), R>; + fn does_not_panic(self) -> Self::Mapped; /// Verifies that the actual code under test panics with any message. /// @@ -3311,7 +3393,7 @@ pub trait AssertCodePanics<'a, R> { /// }).panics(); /// ``` #[track_caller] - fn panics(self) -> Spec<'a, (), R>; + fn panics(self) -> Self::Mapped; /// Verifies that the actual code under test panics with the given /// message. @@ -3332,7 +3414,7 @@ pub trait AssertCodePanics<'a, R> { /// }).panics_with_message("input is empty"); /// ``` #[track_caller] - fn panics_with_message(self, message: impl Into) -> Spec<'a, (), R>; + fn panics_with_message(self, message: impl Into) -> Self::Mapped; } /// Assertions for the keys of a map. @@ -3921,7 +4003,18 @@ pub trait AssertMapContainsValue { /// let subject = [42, 43, 44, 45, 46]; /// assert_that!(subject).none_satisfies(|e| *e < 42); /// ``` -pub trait AssertElements<'a, T, R> { +pub trait AssertElements { + /// A spec-like type that contains a single element as the subject that is + /// extracted from the iterator. + /// + /// Usually this is a `Spec<'a, T, R>`. + type SingleElement; + /// A spec-like type that contains multiple or all elements of an iterator + /// as the subject. + /// + /// Usually this is a `Spec<'a, Vec, R>`. + type MultipleElements; + /// Verify that the iterator contains exactly one element and return a /// [`Spec`] for that single element. /// @@ -3935,7 +4028,7 @@ pub trait AssertElements<'a, T, R> { /// assert_that!(subject).single_element().is_equal_to("single"); /// ``` #[track_caller] - fn single_element(self) -> Spec<'a, T, R>; + fn single_element(self) -> Self::SingleElement; /// Filter the elements of a collection or an iterator on a condition and /// return a [`Spec`] only containing the elements that match the condition. @@ -3957,7 +4050,7 @@ pub trait AssertElements<'a, T, R> { /// .is_equal_to("three"); /// ``` #[track_caller] - fn filtered_on(self, condition: C) -> Spec<'a, Vec, R> + fn filtered_on(self, condition: C) -> Self::MultipleElements where C: FnMut(&T) -> bool; @@ -3973,7 +4066,7 @@ pub trait AssertElements<'a, T, R> { /// assert_that!(subject).any_satisfies(|e| *e == 42); /// ``` #[track_caller] - fn any_satisfies

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

(self, predicate: P) -> Self::MultipleElements where P: FnMut(&T) -> bool; @@ -3989,7 +4082,7 @@ pub trait AssertElements<'a, T, R> { /// assert_that!(subject).all_satisfy(|e| *e > 42); /// ``` #[track_caller] - fn all_satisfy

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

(self, predicate: P) -> Self::MultipleElements where P: FnMut(&T) -> bool; @@ -4005,7 +4098,7 @@ pub trait AssertElements<'a, T, R> { /// assert_that!(subject).none_satisfies(|e| *e < 42); /// ``` #[track_caller] - fn none_satisfies

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

(self, predicate: P) -> Self::MultipleElements where P: FnMut(&T) -> bool; } @@ -4033,7 +4126,18 @@ pub trait AssertElements<'a, T, R> { /// .elements_at([0, 2, 4]) /// .contains_exactly(["one", "three", "five"]); /// ``` -pub trait AssertOrderedElements<'a, T, R> { +pub trait AssertOrderedElements { + /// A spec-like type that contains a single element as the subject that is + /// extracted from the iterator. + /// + /// Usually this is a `Spec<'a, T, R>`. + type SingleElement; + /// A spec-like type that contains multiple or all elements of an iterator + /// as the subject. + /// + /// Usually this is a `Spec<'a, Vec, R>`. + type MultipleElements; + /// Verify that a collection or an iterator contains at least one element /// and return a [`Spec`] for the first element. /// @@ -4047,7 +4151,7 @@ pub trait AssertOrderedElements<'a, T, R> { /// assert_that!(subject).first_element().is_equal_to("first"); /// ``` #[track_caller] - fn first_element(self) -> Spec<'a, T, R>; + fn first_element(self) -> Self::SingleElement; /// Verify that a collection or an iterator contains at least one element /// and return a [`Spec`] for the last element. @@ -4062,7 +4166,7 @@ pub trait AssertOrderedElements<'a, T, R> { /// assert_that!(subject).last_element().is_equal_to("third"); /// ``` #[track_caller] - fn last_element(self) -> Spec<'a, T, R>; + fn last_element(self) -> Self::SingleElement; /// Verify that a collection or an iterator contains at least n + 1 elements /// and return a [`Spec`] for the nth element. @@ -4081,7 +4185,7 @@ pub trait AssertOrderedElements<'a, T, R> { /// assert_that!(subject).nth_element(2).is_equal_to("third"); /// ``` #[track_caller] - fn nth_element(self, n: usize) -> Spec<'a, T, R>; + fn nth_element(self, n: usize) -> Self::SingleElement; /// Pick the elements of a collection or an iterator at the given positions /// and return a [`Spec`] only containing the selected elements. @@ -4098,5 +4202,5 @@ pub trait AssertOrderedElements<'a, T, R> { /// .contains_exactly(["one", "three", "five"]); /// ``` #[track_caller] - fn elements_at(self, indices: impl IntoIterator) -> Spec<'a, Vec, R>; + fn elements_at(self, indices: impl IntoIterator) -> Self::MultipleElements; } diff --git a/src/error/mod.rs b/src/error/mod.rs index 9a73319..4133fa8 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -8,11 +8,13 @@ use crate::std::error::Error; use crate::std::format; use crate::std::string::{String, ToString}; -impl<'a, S, R> AssertErrorHasSource<'a, R> for Spec<'a, S, R> +impl<'a, S, R> AssertErrorHasSource for Spec<'a, S, R> where S: Error, R: FailingStrategy, { + type SourceMessage = Spec<'a, Option, R>; + fn has_no_source(self) -> Self { self.expecting(not(error_has_source())) } @@ -21,10 +23,7 @@ where self.expecting(error_has_source()) } - fn has_source_message( - self, - expected_source_message: impl Into, - ) -> Spec<'a, Option, R> { + fn has_source_message(self, expected_source_message: impl Into) -> Self::SourceMessage { let expected_source_message = expected_source_message.into(); self.expecting(error_has_source_message(expected_source_message)) .mapping(|err| err.source().map(ToString::to_string)) diff --git a/src/iterator/mod.rs b/src/iterator/mod.rs index 02fd26f..aa4cbdb 100644 --- a/src/iterator/mod.rs +++ b/src/iterator/mod.rs @@ -30,19 +30,21 @@ use crate::std::mem; use crate::std::{format, string::String, vec, vec::Vec}; use hashbrown::HashSet; -impl<'a, S, T, E, R> AssertIteratorContains<'a, Vec, E, R> for Spec<'a, S, R> +impl<'a, S, T, E, R> AssertIteratorContains for Spec<'a, S, R> where S: IntoIterator, T: PartialEq + Debug, E: Debug, R: FailingStrategy, { - fn contains(self, expected: E) -> Spec<'a, Vec, R> { + type Sequence = Spec<'a, Vec, R>; + + fn contains(self, expected: E) -> Self::Sequence { self.mapping(Vec::from_iter) .expecting(iterator_contains(expected)) } - fn does_not_contain(self, expected: E) -> Spec<'a, Vec, R> { + fn does_not_contain(self, expected: E) -> Self::Sequence { self.mapping(Vec::from_iter) .expecting(not(iterator_contains(expected))) } @@ -97,7 +99,7 @@ where impl Invertible for IteratorContains {} -impl<'a, S, T, E, R> AssertIteratorContainsInAnyOrder<'a, Vec, E, R> for Spec<'a, S, R> +impl<'a, S, T, E, R> AssertIteratorContainsInAnyOrder for Spec<'a, S, R> where S: IntoIterator, T: PartialEq<::Item> + Debug, @@ -105,7 +107,9 @@ where ::Item: Debug, R: FailingStrategy, { - fn contains_exactly_in_any_order(self, expected: E) -> Spec<'a, Vec, R> { + type Sequence = Spec<'a, Vec, R>; + + fn contains_exactly_in_any_order(self, expected: E) -> Self::Sequence { self.mapping(Vec::from_iter) .expecting(iterator_contains_exactly_in_any_order(expected)) } @@ -414,7 +418,7 @@ where } } -impl<'a, S, T, E, R> AssertIteratorContainsInOrder<'a, Vec, E, R> for Spec<'a, S, R> +impl<'a, S, T, E, R> AssertIteratorContainsInOrder for Spec<'a, S, R> where S: IntoIterator, ::IntoIter: DefinedOrderProperty, @@ -424,27 +428,29 @@ where T: PartialEq<::Item> + Debug, R: FailingStrategy, { - fn contains_exactly(self, expected: E) -> Spec<'a, Vec, R> { + type Sequence = Spec<'a, Vec, R>; + + fn contains_exactly(self, expected: E) -> Self::Sequence { self.mapping(Vec::from_iter) .expecting(iterator_contains_exactly(expected)) } - fn contains_sequence(self, expected: E) -> Spec<'a, Vec, R> { + fn contains_sequence(self, expected: E) -> Self::Sequence { self.mapping(Vec::from_iter) .expecting(iterator_contains_sequence(expected)) } - fn contains_all_in_order(self, expected: E) -> Spec<'a, Vec, R> { + fn contains_all_in_order(self, expected: E) -> Self::Sequence { self.mapping(Vec::from_iter) .expecting(iterator_contains_all_in_order(expected)) } - fn starts_with(self, expected: E) -> Spec<'a, Vec, R> { + fn starts_with(self, expected: E) -> Self::Sequence { self.mapping(Vec::from_iter) .expecting(iterator_starts_with(expected)) } - fn ends_with(self, expected: E) -> Spec<'a, Vec, R> { + fn ends_with(self, expected: E) -> Self::Sequence { self.mapping(Vec::from_iter) .expecting(iterator_ends_with(expected)) } @@ -777,13 +783,16 @@ where } } -impl<'a, S, T, R> AssertElements<'a, T, R> for Spec<'a, S, R> +impl<'a, S, T, R> AssertElements for Spec<'a, S, R> where S: IntoIterator, T: Debug, R: FailingStrategy, { - fn single_element(self) -> Spec<'a, T, R> { + type SingleElement = Spec<'a, T, R>; + type MultipleElements = Spec<'a, Vec, R>; + + fn single_element(self) -> Self::SingleElement { let spec = self.mapping(Vec::from_iter).expecting(has_single_element()); if spec.has_failures() { PanicOnFail.do_fail_with(&spec.failures()); @@ -796,14 +805,14 @@ where }) } - fn filtered_on(self, condition: C) -> Spec<'a, Vec, R> + fn filtered_on(self, condition: C) -> Self::MultipleElements where C: FnMut(&T) -> bool, { self.mapping(|subject| subject.into_iter().filter(condition).collect()) } - fn any_satisfies

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

(self, predicate: P) -> Self::MultipleElements where P: FnMut(&T) -> bool, { @@ -811,7 +820,7 @@ where .expecting(any_satisfies(predicate)) } - fn all_satisfy

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

(self, predicate: P) -> Self::MultipleElements where P: FnMut(&T) -> bool, { @@ -819,7 +828,7 @@ where .expecting(all_satisfy(predicate)) } - fn none_satisfies

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

(self, predicate: P) -> Self::MultipleElements where P: FnMut(&T) -> bool, { @@ -946,14 +955,17 @@ where } } -impl<'a, S, T, R> AssertOrderedElements<'a, T, R> for Spec<'a, S, R> +impl<'a, S, T, R> AssertOrderedElements for Spec<'a, S, R> where S: IntoIterator, ::IntoIter: DefinedOrderProperty, T: Debug, R: FailingStrategy, { - fn first_element(self) -> Spec<'a, T, R> { + type SingleElement = Spec<'a, T, R>; + type MultipleElements = Spec<'a, Vec, R>; + + fn first_element(self) -> Self::SingleElement { let spec = self .mapping(Vec::from_iter) .expecting(has_at_least_number_of_elements(1)); @@ -964,7 +976,7 @@ where spec.extracting(|mut collection| collection.remove(0)) } - fn last_element(self) -> Spec<'a, T, R> { + fn last_element(self) -> Self::SingleElement { let spec = self .mapping(Vec::from_iter) .expecting(has_at_least_number_of_elements(1)); @@ -979,7 +991,7 @@ where }) } - fn nth_element(self, n: usize) -> Spec<'a, T, R> { + fn nth_element(self, n: usize) -> Self::SingleElement { let min_len = n + 1; let spec = self .mapping(Vec::from_iter) @@ -991,7 +1003,7 @@ where spec.extracting(|mut collection| collection.remove(n)) } - fn elements_at(self, indices: impl IntoIterator) -> Spec<'a, Vec, R> { + fn elements_at(self, indices: impl IntoIterator) -> Self::MultipleElements { let indices = HashSet::<_>::from_iter(indices); self.mapping(|subject| { subject diff --git a/src/mapping.rs b/src/mapping.rs index b8283d1..78d241e 100644 --- a/src/mapping.rs +++ b/src/mapping.rs @@ -4,24 +4,28 @@ use crate::std::fmt::{Debug, Display}; use crate::std::format; use crate::std::string::{String, ToString}; -impl<'a, S, R> AssertDebugString<'a, R> for Spec<'a, S, R> +impl<'a, S, R> AssertDebugString for Spec<'a, S, R> where S: Debug, R: FailingStrategy, { - fn debug_string(self) -> Spec<'a, String, R> { + type DebugString = Spec<'a, String, R>; + + fn debug_string(self) -> Self::DebugString { let expression_debug_string = format!("{}'s debug string", self.expression()); self.mapping(|subject| format!("{subject:?}")) .named(expression_debug_string) } } -impl<'a, S, R> AssertDisplayString<'a, R> for Spec<'a, S, R> +impl<'a, S, R> AssertDisplayString for Spec<'a, S, R> where S: Display, R: FailingStrategy, { - fn display_string(self) -> Spec<'a, String, R> { + type DisplayString = Spec<'a, String, R>; + + fn display_string(self) -> Self::DisplayString { let expression_display_string = format!("{}'s display string", self.expression()); self.mapping(|subject| subject.to_string()) .named(expression_display_string) diff --git a/src/option/mod.rs b/src/option/mod.rs index 95302a7..1ef06b9 100644 --- a/src/option/mod.rs +++ b/src/option/mod.rs @@ -39,11 +39,13 @@ where } } -impl<'a, T, R> AssertOptionValue<'a, T, R> for Spec<'a, Option, R> +impl<'a, T, R> AssertOptionValue for Spec<'a, Option, R> where R: FailingStrategy, { - fn some(self) -> Spec<'a, T, R> { + type Some = Spec<'a, T, R>; + + fn some(self) -> Self::Some { self.mapping(|subject| match subject { None => { panic!("expected the subject to be `Some(_)`, but was `None`") @@ -53,11 +55,13 @@ where } } -impl<'a, T, R> AssertBorrowedOptionValue<'a, T, R> for Spec<'a, &'a Option, R> +impl<'a, T, R> AssertBorrowedOptionValue for Spec<'a, &'a Option, R> where R: FailingStrategy, { - fn some(self) -> Spec<'a, &'a T, R> { + type Some = Spec<'a, &'a T, R>; + + fn some(self) -> Self::Some { self.mapping(|subject| match subject { None => { panic!("expected the subject to be `Some(_)`, but was `None`") diff --git a/src/panic/mod.rs b/src/panic/mod.rs index cd01db2..7a08cd6 100644 --- a/src/panic/mod.rs +++ b/src/panic/mod.rs @@ -10,20 +10,22 @@ use crate::std::panic; const ONLY_ONE_EXPECTATION: &str = "only one expectation allowed when asserting closures!"; const UNKNOWN_PANIC_MESSAGE: &str = ""; -impl<'a, S, R> AssertCodePanics<'a, R> for Spec<'a, Code, R> +impl<'a, S, R> AssertCodePanics for Spec<'a, Code, R> where S: FnOnce(), R: FailingStrategy, { - fn does_not_panic(self) -> Spec<'a, (), R> { + type Mapped = Spec<'a, (), R>; + + fn does_not_panic(self) -> Self::Mapped { self.expecting(does_not_panic()).mapping(|_| ()) } - fn panics(self) -> Spec<'a, (), R> { + fn panics(self) -> Self::Mapped { self.expecting(does_panic()).mapping(|_| ()) } - fn panics_with_message(self, message: impl Into) -> Spec<'a, (), R> { + fn panics_with_message(self, message: impl Into) -> Self::Mapped { self.expecting(does_panic().with_message(message)) .mapping(|_| ()) } diff --git a/src/result/mod.rs b/src/result/mod.rs index 7e1c61a..155c098 100644 --- a/src/result/mod.rs +++ b/src/result/mod.rs @@ -47,12 +47,15 @@ where } } -impl<'a, T, E, R> AssertResultValue<'a, T, E, R> for Spec<'a, Result, R> +impl<'a, T, E, R> AssertResultValue for Spec<'a, Result, R> where T: Debug, E: Debug, { - fn ok(self) -> Spec<'a, T, R> { + type Ok = Spec<'a, T, R>; + type Err = Spec<'a, E, R>; + + fn ok(self) -> Self::Ok { self.mapping(|subject| match subject { Ok(value) => value, Err(error) => { @@ -61,7 +64,7 @@ where }) } - fn err(self) -> Spec<'a, E, R> { + fn err(self) -> Self::Err { self.mapping(|subject| match subject { Ok(value) => { panic!("expected the subject to be `Err(_)`, but was `Ok({value:?})`") @@ -71,12 +74,15 @@ where } } -impl<'a, T, E, R> AssertBorrowedResultValue<'a, T, E, R> for Spec<'a, &'a Result, R> +impl<'a, T, E, R> AssertBorrowedResultValue for Spec<'a, &'a Result, R> where T: Debug, E: Debug, { - fn ok(self) -> Spec<'a, &'a T, R> { + type Ok = Spec<'a, &'a T, R>; + type Err = Spec<'a, &'a E, R>; + + fn ok(self) -> Self::Ok { self.mapping(|subject| match subject { Ok(value) => value, Err(error) => { @@ -85,7 +91,7 @@ where }) } - fn err(self) -> Spec<'a, &'a E, R> { + fn err(self) -> Self::Err { self.mapping(|subject| match subject { Ok(value) => { panic!("expected the subject to be `Err(_)`, but was `Ok({value:?})`") @@ -143,7 +149,7 @@ where } } -impl<'a, T, E, X, R> AssertHasErrorMessage<'a, X, R> for Spec<'a, Result, R> +impl<'a, T, E, X, R> AssertHasErrorMessage for Spec<'a, Result, R> where T: Debug, E: Display, @@ -151,7 +157,9 @@ where String: PartialEq, R: FailingStrategy, { - fn has_error_message(self, expected: X) -> Spec<'a, String, R> { + type ErrorMessage = Spec<'a, String, R>; + + fn has_error_message(self, expected: X) -> Self::ErrorMessage { self.mapping(|result| match result { Ok(value) => panic!( r"expected the subject to be `Err(_)` with message {expected:?}, but was `Ok({value:?})`" @@ -163,7 +171,7 @@ where } } -impl<'a, T, E, X, R> AssertHasErrorMessage<'a, X, R> for Spec<'a, &Result, R> +impl<'a, T, E, X, R> AssertHasErrorMessage for Spec<'a, &Result, R> where T: Debug, E: Display, @@ -171,7 +179,9 @@ where String: PartialEq, R: FailingStrategy, { - fn has_error_message(self, expected: X) -> Spec<'a, String, R> { + type ErrorMessage = Spec<'a, String, R>; + + fn has_error_message(self, expected: X) -> Self::ErrorMessage { self.mapping(|result| match result { Ok(value) => panic!( r"expected the subject to be `Err(_)` with message {expected:?}, but was `Ok({value:?})`"