diff --git a/README.md b/README.md
index e7e825b..a395b8a 100644
--- a/README.md
+++ b/README.md
@@ -17,19 +17,21 @@ result. Fluent assertions read like natural English.
Features of `asserting`:
-1. assertions are convenient to write and easy to read
-2. helpful error messages in case of failing assertions
-3. colored diffs between expected and actual values
- (see ["Highlighted differences"](#highlighted-differences))
-4. chaining of multiple assertions on the same subject (see ["Chaining assertions"])
-5. concise and expressive assertions for more complex types like collections
-6. field-by-field recursive comparison (see ["Field-by-field recursive comparison"]) :new:
-7. soft assertions (execute multiple assertions before panicking) (see ["Soft assertions"])
-8. support for asserting custom types with provided assertions (see ["Asserting custom types"])
-9. provide a reasonable number of assertions out of the box
-10. do not require that asserted types have to implement traits if it is not absolutely necessary
-11. custom assertions (see ["Custom assertions"](#custom-assertions))
-12. support no-std environments
+* assertions are convenient to write and easy to read
+* helpful error messages in case of failing assertions
+* colored diffs between expected and actual values
+ (see ["Highlighted differences"](#highlighted-differences))
+* chaining of multiple assertions on the same subject (see ["Chaining assertions"])
+* concise and expressive assertions for more complex types like collections
+* field-by-field recursive comparison (see ["Field-by-field recursive comparison"]) :new:
+* soft assertions (execute multiple assertions before panicking) (see ["Soft assertions"])
+* support for asserting custom types with provided assertions (see ["Asserting custom types"])
+* custom representation of values in failure reports or if a (foreign) type does not implement
+ [`Debug`] (see ["Type formatting (aka Representation)"])
+* provide a reasonable number of assertions out of the box
+* do not require that asserted types have to implement traits if it is not absolutely necessary
+* custom assertions (see ["Custom assertions"](#custom-assertions))
+* support no-std environments
For an overview of the provided features and many examples on how to use `asserting` see the
[crate-level documentation][docs-url].
@@ -71,8 +73,9 @@ default.
## Highlighted differences
-`asserting` can highlight the differences between the expected value(s) and the actual value(s) when
-printing assertion failures to the terminal. The colored diffs in assertion failures look like this:
+`asserting` can highlight the differences between the expected value (s) and the actual value (s)
+when printing assertion failures to the terminal. The colored diffs in assertion failures look like
+this:

@@ -89,9 +92,9 @@ It supports different variants of how differences are highlighted.
| red-yellow | Differences are printed in the colors yellow and red. |
| off | Switches off highlighting. The differences are not highlighted at all. |
-The mode can be configured by setting the environment variable `ASSERTING_HIGHLIGHT_DIFFS` to one
-of the modes in the table above. The value is case-insensitive. E.g., setting the environment
-variable to values like `Red-Blue`, `Bold` or `OFF` works as well.
+The mode can be configured by setting the environment variable `ASSERTING_HIGHLIGHT_DIFFS` to one of
+the modes in the table above. The value is case-insensitive. E.g., setting the environment variable
+to values like `Red-Blue`, `Bold` or `OFF` works as well.
The intended way for configuring the highlighting mode is to set the environment variable in the
configuration for `Cargo` by adding it to the `[env]` section in your `~/.cargo/config.toml` file:
@@ -127,8 +130,7 @@ for all types that implement `PartialEq` with `E` being the type of the expec
| is_equal_to | verify that the subject is equal to an expected value |
| is_not_equal_to | verify that the subject is not equal to a specific value |
-for all types that implement `PartialEq` and the subject is of the same type as the expected
-value:
+for all types that implement `PartialEq` and the subject is of the same type as the expected value:
| assertion | description |
|----------------|-----------------------------------------------------------------------------------------------|
@@ -459,10 +461,10 @@ To start assertions on code, use the `assert_that_code!()` macro.
`asserting` provides three kinds of custom assertions:
1. use any predicate function as a custom assertion (see "[predicate as custom assertion]")
-2. property-based assertions can be used with any type that implements the related property
- (see "[property-based assertions]")
-3. write custom assertion methods by defining and implementing an extension trait
- (see "[custom assertions]")
+2. property-based assertions can be used with any type that implements the related property (see
+ "[property-based assertions]")
+3. write custom assertion methods by defining and implementing an extension trait (see
+ "[custom assertions]")
The mentioned references link to a chapter in the crate's documentation that describes the
possibilities for custom assertions, including examples.
@@ -491,6 +493,8 @@ possibilities for custom assertions, including examples.
["Field-by-field recursive comparison"]: https://docs.rs/asserting/latest/asserting/#field-by-field-recursive-comparison
+["Type formatting (aka Representation)"]: https://docs.rs/asserting/latest/asserting/#type-formatting-aka-representation
+
["soft assertions"]: https://docs.rs/asserting/#soft-assertions
[custom assertions]: https://docs.rs/asserting/#custom-assertions
diff --git a/examples/custom_assertion_reusing_existing.rs b/examples/custom_assertion_reusing_existing.rs
index 5e384c5..656e67c 100644
--- a/examples/custom_assertion_reusing_existing.rs
+++ b/examples/custom_assertion_reusing_existing.rs
@@ -62,7 +62,7 @@ trait AssertSnake {
// we implement the `AssertSnake` trait for a generic `S: Borrow` so that
// the assertion method `has_body` can be called on owned and borrowed `Snake`
// instances.
-impl AssertSnake for Spec<'_, S, R>
+impl AssertSnake for Spec<'_, S, D, R>
where
S: Borrow,
R: FailingStrategy,
diff --git a/src/assertions.rs b/src/assertions.rs
index f2f2d43..5c0edad 100644
--- a/src/assertions.rs
+++ b/src/assertions.rs
@@ -10,8 +10,7 @@
//! assertions.
#![allow(clippy::wrong_self_convention, clippy::return_self_not_must_use)]
-use crate::spec::{CollectFailures, GetFailures, Spec};
-use crate::std::fmt::Debug;
+use crate::spec::{CollectFailures, DebugRepresentation, GetFailures, Represent, Spec};
use crate::std::ops::RangeBounds;
use crate::std::string::String;
@@ -572,7 +571,7 @@ pub trait AssertOrder {
/// assert_that!('r').is_in_range('H'..);
/// assert_that!('N').is_in_range(..'n');
/// ```
-pub trait AssertInRange {
+pub trait AssertInRange {
/// Verifies that the subject is within the expected range.
///
/// # Examples
@@ -596,7 +595,8 @@ pub trait AssertInRange {
#[track_caller]
fn is_in_range(self, range: R) -> Self
where
- R: RangeBounds + Debug;
+ R: RangeBounds,
+ D: Represent;
/// Verifies that the subject is not within the expected range.
///
@@ -617,7 +617,8 @@ pub trait AssertInRange {
#[track_caller]
fn is_not_in_range(self, range: R) -> Self
where
- R: RangeBounds + Debug;
+ R: RangeBounds,
+ D: Represent;
}
/// Assert whether a numeric value is negative or positive.
@@ -1364,7 +1365,7 @@ pub trait AssertEmptiness {
/// assert_that!(&some_map).has_length(4);
/// # }
/// ```
-pub trait AssertHasLength {
+pub trait AssertHasLength {
/// Verifies that the subject has the expected length.
///
/// # Examples
@@ -1475,7 +1476,8 @@ pub trait AssertHasLength {
#[track_caller]
fn has_length_in_range(self, expected_range: U) -> Self
where
- U: RangeBounds + Debug;
+ U: RangeBounds,
+ D: Represent;
/// Verifies that the subject has a length that is less than the expected
/// length.
@@ -1708,7 +1710,7 @@ pub trait AssertHasLength {
/// assert_that!(subject).has_at_least_char_count(20);
/// assert_that!(subject).has_at_least_char_count(25);
/// ```
-pub trait AssertHasCharCount {
+pub trait AssertHasCharCount {
/// Verifies that the subject contains the expected number of characters.
///
/// # Examples
@@ -1744,7 +1746,8 @@ pub trait AssertHasCharCount {
#[track_caller]
fn has_char_count_in_range(self, range: U) -> Self
where
- U: RangeBounds + Debug;
+ U: RangeBounds,
+ D: Represent;
/// Verifies that the subject contains less than the expected number of
/// characters.
@@ -3934,7 +3937,7 @@ where
#[track_caller]
fn each_element(self, assert: A) -> Self::Output
where
- A: Fn(Spec<'a, ::Item, CollectFailures>) -> B,
+ A: Fn(Spec<'a, ::Item, DebugRepresentation, CollectFailures>) -> B,
B: GetFailures;
/// Iterates over the elements of a collection or an iterator and executes
@@ -3982,7 +3985,7 @@ where
#[track_caller]
fn any_element(self, assert: A) -> Self::Output
where
- A: Fn(Spec<'a, ::Item, CollectFailures>) -> B,
+ A: Fn(Spec<'a, ::Item, DebugRepresentation, CollectFailures>) -> B,
B: GetFailures;
}
diff --git a/src/boolean/mod.rs b/src/boolean/mod.rs
index 6f91481..0fbb0d5 100644
--- a/src/boolean/mod.rs
+++ b/src/boolean/mod.rs
@@ -4,13 +4,15 @@ use crate::assertions::AssertBoolean;
use crate::colored::{mark_missing, mark_unexpected};
use crate::expectations::{IsFalse, IsTrue, is_false, is_true};
use crate::spec::{
- DiffFormat, Expectation, Expecting, Expression, FailingStrategy, Invertible, Spec,
+ DiffFormat, Expectation, Expecting, Expression, FailingStrategy, Invertible, Represent,
+ Represented, Spec,
};
use crate::std::format;
use crate::std::string::String;
-impl AssertBoolean for Spec<'_, bool, R>
+impl AssertBoolean for Spec<'_, bool, D, R>
where
+ D: Represent,
R: FailingStrategy,
{
fn is_true(self) -> Self {
@@ -22,7 +24,10 @@ where
}
}
-impl Expectation for IsTrue {
+impl Expectation for IsTrue
+where
+ D: Represent,
+{
fn test(&mut self, subject: &bool) -> bool {
*subject
}
@@ -32,20 +37,24 @@ impl Expectation for IsTrue {
expression: &Expression<'_>,
actual: &bool,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- let marked_actual = mark_unexpected(&actual, format);
- let marked_expected = mark_missing(&!inverted, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
+ let marked_expected = mark_missing(&!inverted, representation, format);
+ let represented_expected = Represented::from((&true, representation));
format!(
- "expected {expression} to be {:?}\n but was: {marked_actual}\n expected: {marked_expected}",
- true
+ "expected {expression} to be {represented_expected:?}\n but was: {marked_actual}\n expected: {marked_expected}",
)
}
}
impl Invertible for IsTrue {}
-impl Expectation for IsFalse {
+impl Expectation for IsFalse
+where
+ D: Represent,
+{
fn test(&mut self, subject: &bool) -> bool {
!*subject
}
@@ -55,13 +64,14 @@ impl Expectation for IsFalse {
expression: &Expression<'_>,
actual: &bool,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- let marked_actual = mark_unexpected(actual, format);
- let marked_expected = mark_missing(&inverted, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
+ let marked_expected = mark_missing(&inverted, representation, format);
+ let represented_expected = Represented::from((&false, representation));
format!(
- "expected {expression} to be {:?}\n but was: {marked_actual}\n expected: {marked_expected}",
- false
+ "expected {expression} to be {represented_expected:?}\n but was: {marked_actual}\n expected: {marked_expected}",
)
}
}
diff --git a/src/char/mod.rs b/src/char/mod.rs
index 907151c..48644c1 100644
--- a/src/char/mod.rs
+++ b/src/char/mod.rs
@@ -1,18 +1,20 @@
use crate::assertions::AssertChar;
-use crate::colored::{mark_missing_string, mark_unexpected_char};
+use crate::colored::{mark_missing, mark_unexpected};
use crate::expectations::{
IsAlphabetic, IsAlphanumeric, IsAscii, IsControlChar, IsDigit, IsLowerCase, IsUpperCase,
IsWhitespace, is_alphabetic, is_alphanumeric, is_ascii, is_control_char, is_digit,
is_lower_case, is_upper_case, is_whitespace,
};
use crate::spec::{
- DiffFormat, Expectation, Expecting, Expression, FailingStrategy, Invertible, Spec,
+ DiffFormat, DisplayRepresentation, Expectation, Expecting, Expression, FailingStrategy,
+ Invertible, Represent, Spec,
};
use crate::std::format;
use crate::std::string::{String, ToString};
-impl AssertChar for Spec<'_, char, R>
+impl AssertChar for Spec<'_, char, D, R>
where
+ D: Represent + Represent,
R: FailingStrategy,
{
fn is_lowercase(self) -> Self {
@@ -48,8 +50,9 @@ where
}
}
-impl AssertChar for Spec<'_, &char, R>
+impl AssertChar for Spec<'_, &char, D, R>
where
+ D: Represent + Represent,
R: FailingStrategy,
{
fn is_lowercase(self) -> Self {
@@ -85,7 +88,10 @@ where
}
}
-impl Expectation for IsLowerCase {
+impl Expectation for IsLowerCase
+where
+ D: Represent,
+{
fn test(&mut self, subject: &char) -> bool {
subject.is_lowercase()
}
@@ -95,6 +101,7 @@ impl Expectation for IsLowerCase {
expression: &Expression<'_>,
actual: &char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let (not, expected) = if inverted {
@@ -102,19 +109,22 @@ impl Expectation for IsLowerCase {
} else {
("", actual.to_lowercase().to_string())
};
- let marked_actual = mark_unexpected_char(*actual, format);
- let marked_expected = mark_missing_string(&expected, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
+ let marked_expected = mark_missing(&expected, &DisplayRepresentation, format);
format!(
- "expected {expression} to be {not}lowercase\n but was: {marked_actual}\n expected: {marked_expected}"
+ "expected {expression} to be {not}lowercase\n but was: {marked_actual}\n expected: '{marked_expected}'"
)
}
}
impl Invertible for IsLowerCase {}
-impl Expectation<&char> for IsLowerCase {
+impl Expectation<&char, D> for IsLowerCase
+where
+ D: Represent,
+{
fn test(&mut self, subject: &&char) -> bool {
- >::test(self, subject)
+ >::test(self, subject)
}
fn message(
@@ -122,13 +132,24 @@ impl Expectation<&char> for IsLowerCase {
expression: &Expression<'_>,
actual: &&char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- >::message(self, expression, actual, inverted, format)
+ >::message(
+ self,
+ expression,
+ actual,
+ inverted,
+ representation,
+ format,
+ )
}
}
-impl Expectation for IsUpperCase {
+impl Expectation for IsUpperCase
+where
+ D: Represent,
+{
fn test(&mut self, subject: &char) -> bool {
subject.is_uppercase()
}
@@ -138,6 +159,7 @@ impl Expectation for IsUpperCase {
expression: &Expression<'_>,
actual: &char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let (not, expected) = if inverted {
@@ -145,19 +167,22 @@ impl Expectation for IsUpperCase {
} else {
("", actual.to_uppercase().to_string())
};
- let marked_actual = mark_unexpected_char(*actual, format);
- let marked_expected = mark_missing_string(&expected, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
+ let marked_expected = mark_missing(&expected, &DisplayRepresentation, format);
format!(
- "expected {expression} to be {not}uppercase\n but was: {marked_actual}\n expected: {marked_expected}"
+ "expected {expression} to be {not}uppercase\n but was: {marked_actual}\n expected: '{marked_expected}'"
)
}
}
impl Invertible for IsUpperCase {}
-impl Expectation<&char> for IsUpperCase {
+impl Expectation<&char, D> for IsUpperCase
+where
+ D: Represent,
+{
fn test(&mut self, subject: &&char) -> bool {
- >::test(self, subject)
+ >::test(self, subject)
}
fn message(
@@ -165,13 +190,24 @@ impl Expectation<&char> for IsUpperCase {
expression: &Expression<'_>,
actual: &&char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- >::message(self, expression, actual, inverted, format)
+ >::message(
+ self,
+ expression,
+ actual,
+ inverted,
+ representation,
+ format,
+ )
}
}
-impl Expectation for IsAscii {
+impl Expectation for IsAscii
+where
+ D: Represent,
+{
fn test(&mut self, subject: &char) -> bool {
subject.is_ascii()
}
@@ -181,10 +217,11 @@ impl Expectation for IsAscii {
expression: &Expression<'_>,
actual: &char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let not = if inverted { "not " } else { "" };
- let marked_actual = mark_unexpected_char(*actual, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
format!(
"expected {expression} to be {not}an ASCII character\n but was: {marked_actual}\n expected: {not}an ASCII character"
)
@@ -193,9 +230,12 @@ impl Expectation for IsAscii {
impl Invertible for IsAscii {}
-impl Expectation<&char> for IsAscii {
+impl Expectation<&char, D> for IsAscii
+where
+ D: Represent,
+{
fn test(&mut self, subject: &&char) -> bool {
- >::test(self, subject)
+ >::test(self, subject)
}
fn message(
@@ -203,13 +243,24 @@ impl Expectation<&char> for IsAscii {
expression: &Expression<'_>,
actual: &&char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- >::message(self, expression, actual, inverted, format)
+ >::message(
+ self,
+ expression,
+ actual,
+ inverted,
+ representation,
+ format,
+ )
}
}
-impl Expectation for IsAlphabetic {
+impl Expectation for IsAlphabetic
+where
+ D: Represent,
+{
fn test(&mut self, subject: &char) -> bool {
subject.is_alphabetic()
}
@@ -219,10 +270,11 @@ impl Expectation for IsAlphabetic {
expression: &Expression<'_>,
actual: &char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let not = if inverted { "not " } else { "" };
- let marked_actual = mark_unexpected_char(*actual, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
format!(
"expected {expression} to be {not}an alphabetic character\n but was: {marked_actual}\n expected: {not}an alphabetic character"
)
@@ -231,9 +283,12 @@ impl Expectation for IsAlphabetic {
impl Invertible for IsAlphabetic {}
-impl Expectation<&char> for IsAlphabetic {
+impl Expectation<&char, D> for IsAlphabetic
+where
+ D: Represent,
+{
fn test(&mut self, subject: &&char) -> bool {
- >::test(self, subject)
+ >::test(self, subject)
}
fn message(
@@ -241,13 +296,24 @@ impl Expectation<&char> for IsAlphabetic {
expression: &Expression<'_>,
actual: &&char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- >::message(self, expression, actual, inverted, format)
+ >::message(
+ self,
+ expression,
+ actual,
+ inverted,
+ representation,
+ format,
+ )
}
}
-impl Expectation for IsAlphanumeric {
+impl Expectation for IsAlphanumeric
+where
+ D: Represent,
+{
fn test(&mut self, subject: &char) -> bool {
subject.is_alphanumeric()
}
@@ -257,10 +323,11 @@ impl Expectation for IsAlphanumeric {
expression: &Expression<'_>,
actual: &char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let not = if inverted { "not " } else { "" };
- let marked_actual = mark_unexpected_char(*actual, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
format!(
"expected {expression} to be {not}an alphanumeric character\n but was: {marked_actual}\n expected: {not}an alphanumeric character"
)
@@ -269,9 +336,12 @@ impl Expectation for IsAlphanumeric {
impl Invertible for IsAlphanumeric {}
-impl Expectation<&char> for IsAlphanumeric {
+impl Expectation<&char, D> for IsAlphanumeric
+where
+ D: Represent,
+{
fn test(&mut self, subject: &&char) -> bool {
- >::test(self, subject)
+ >::test(self, subject)
}
fn message(
@@ -279,13 +349,24 @@ impl Expectation<&char> for IsAlphanumeric {
expression: &Expression<'_>,
actual: &&char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- >::message(self, expression, actual, inverted, format)
+ >::message(
+ self,
+ expression,
+ actual,
+ inverted,
+ representation,
+ format,
+ )
}
}
-impl Expectation for IsControlChar {
+impl Expectation for IsControlChar
+where
+ D: Represent,
+{
fn test(&mut self, subject: &char) -> bool {
subject.is_control()
}
@@ -295,10 +376,11 @@ impl Expectation for IsControlChar {
expression: &Expression<'_>,
actual: &char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let not = if inverted { "not " } else { "" };
- let marked_actual = mark_unexpected_char(*actual, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
format!(
"expected {expression} to be {not}a control character\n but was: {marked_actual}\n expected: {not}a control character"
)
@@ -307,9 +389,12 @@ impl Expectation for IsControlChar {
impl Invertible for IsControlChar {}
-impl Expectation<&char> for IsControlChar {
+impl Expectation<&char, D> for IsControlChar
+where
+ D: Represent,
+{
fn test(&mut self, subject: &&char) -> bool {
- >::test(self, subject)
+ >::test(self, subject)
}
fn message(
@@ -317,13 +402,24 @@ impl Expectation<&char> for IsControlChar {
expression: &Expression<'_>,
actual: &&char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- >::message(self, expression, actual, inverted, format)
+ >::message(
+ self,
+ expression,
+ actual,
+ inverted,
+ representation,
+ format,
+ )
}
}
-impl Expectation for IsDigit {
+impl Expectation for IsDigit
+where
+ D: Represent,
+{
fn test(&mut self, subject: &char) -> bool {
subject.is_digit(self.radix)
}
@@ -333,11 +429,12 @@ impl Expectation for IsDigit {
expression: &Expression<'_>,
actual: &char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let not = if inverted { "not " } else { "" };
let radix = self.radix;
- let marked_actual = mark_unexpected_char(*actual, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
format!(
"expected {expression} to be {not}a digit in the radix {radix}\n but was: {marked_actual}\n expected: {not}a digit in the radix {radix}"
)
@@ -346,9 +443,12 @@ impl Expectation for IsDigit {
impl Invertible for IsDigit {}
-impl Expectation<&char> for IsDigit {
+impl Expectation<&char, D> for IsDigit
+where
+ D: Represent,
+{
fn test(&mut self, subject: &&char) -> bool {
- >::test(self, subject)
+ >::test(self, subject)
}
fn message(
@@ -356,13 +456,24 @@ impl Expectation<&char> for IsDigit {
expression: &Expression<'_>,
actual: &&char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- >::message(self, expression, actual, inverted, format)
+ >::message(
+ self,
+ expression,
+ actual,
+ inverted,
+ representation,
+ format,
+ )
}
}
-impl Expectation for IsWhitespace {
+impl Expectation for IsWhitespace
+where
+ D: Represent,
+{
fn test(&mut self, subject: &char) -> bool {
subject.is_whitespace()
}
@@ -372,10 +483,11 @@ impl Expectation for IsWhitespace {
expression: &Expression<'_>,
actual: &char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let not = if inverted { "not " } else { "" };
- let marked_actual = mark_unexpected_char(*actual, format);
+ let marked_actual = mark_unexpected(actual, representation, format);
format!(
"expected {expression} to be {not}whitespace\n but was: {marked_actual}\n expected: {not}whitespace"
)
@@ -384,9 +496,12 @@ impl Expectation for IsWhitespace {
impl Invertible for IsWhitespace {}
-impl Expectation<&char> for IsWhitespace {
+impl Expectation<&char, D> for IsWhitespace
+where
+ D: Represent,
+{
fn test(&mut self, subject: &&char) -> bool {
- >::test(self, subject)
+ >::test(self, subject)
}
fn message(
@@ -394,9 +509,17 @@ impl Expectation<&char> for IsWhitespace {
expression: &Expression<'_>,
actual: &&char,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
- >::message(self, expression, actual, inverted, format)
+ >::message(
+ self,
+ expression,
+ actual,
+ inverted,
+ representation,
+ format,
+ )
}
}
diff --git a/src/char/tests.rs b/src/char/tests.rs
index 8899b35..24b5121 100644
--- a/src/char/tests.rs
+++ b/src/char/tests.rs
@@ -13,8 +13,8 @@ fn verify_char_is_lowercase_fails() {
assert_eq!(
failures,
&[r"expected subject to be lowercase
- but was: M
- expected: m
+ but was: 'M'
+ expected: 'm'
"]
);
}
@@ -31,8 +31,8 @@ fn verify_borrowed_char_is_lowercase_fails() {
assert_eq!(
failures,
&[r"expected subject to be lowercase
- but was: M
- expected: m
+ but was: 'M'
+ expected: 'm'
"]
);
}
@@ -49,8 +49,8 @@ fn verify_char_is_uppercase_fails() {
assert_eq!(
failures,
&[r"expected subject to be uppercase
- but was: k
- expected: K
+ but was: 'k'
+ expected: 'K'
"]
);
}
@@ -67,8 +67,8 @@ fn verify_borrowed_char_is_uppercase_fails() {
assert_eq!(
failures,
&[r"expected subject to be uppercase
- but was: x
- expected: X
+ but was: 'x'
+ expected: 'X'
"]
);
}
@@ -85,7 +85,7 @@ fn verify_char_is_ascii_fails() {
assert_eq!(
failures,
&[r"expected subject to be an ASCII character
- but was: €
+ but was: '€'
expected: an ASCII character
"]
);
@@ -103,7 +103,7 @@ fn verify_borrowed_char_is_ascii_fails() {
assert_eq!(
failures,
&[r"expected subject to be an ASCII character
- but was: ❤
+ but was: '❤'
expected: an ASCII character
"]
);
@@ -121,7 +121,7 @@ fn verify_char_is_alphabetic_fails() {
assert_eq!(
failures,
&[r"expected subject to be an alphabetic character
- but was: 1
+ but was: '1'
expected: an alphabetic character
"]
);
@@ -139,7 +139,7 @@ fn verify_borrowed_char_is_alphabetic_fails() {
assert_eq!(
failures,
&[r"expected subject to be an alphabetic character
- but was: @
+ but was: '@'
expected: an alphabetic character
"]
);
@@ -158,7 +158,7 @@ fn verify_char_is_alphanumeric_fails() {
assert_eq!(
failures,
&[r"expected subject to be an alphanumeric character
- but was: @
+ but was: '@'
expected: an alphanumeric character
"]
);
@@ -177,7 +177,7 @@ fn verify_borrowed_char_is_alphanumeric_fails() {
assert_eq!(
failures,
&[r"expected subject to be an alphanumeric character
- but was: +
+ but was: '+'
expected: an alphanumeric character
"]
);
@@ -195,7 +195,7 @@ fn verify_char_is_control_char_fails() {
assert_eq!(
failures,
&[r"expected subject to be a control character
- but was: [
+ but was: '['
expected: a control character
"]
);
@@ -213,7 +213,7 @@ fn verify_borrowed_char_is_control_char_fails() {
assert_eq!(
failures,
&[r"expected subject to be a control character
- but was: @
+ but was: '@'
expected: a control character
"]
);
@@ -231,7 +231,7 @@ fn verify_char_is_digit_in_radix_10_fails() {
assert_eq!(
failures,
&[r"expected subject to be a digit in the radix 10
- but was: A
+ but was: 'A'
expected: a digit in the radix 10
"]
);
@@ -249,7 +249,7 @@ fn verify_borrowed_char_is_digit_in_radix_10_fails() {
assert_eq!(
failures,
&[r"expected subject to be a digit in the radix 10
- but was: F
+ but was: 'F'
expected: a digit in the radix 10
"]
);
@@ -267,7 +267,7 @@ fn verify_char_is_digit_in_radix_16_fails() {
assert_eq!(
failures,
&[r"expected subject to be a digit in the radix 16
- but was: G
+ but was: 'G'
expected: a digit in the radix 16
"]
);
@@ -285,7 +285,7 @@ fn verify_borrowed_char_is_digit_in_radix_16_fails() {
assert_eq!(
failures,
&[r"expected subject to be a digit in the radix 16
- but was: g
+ but was: 'g'
expected: a digit in the radix 16
"]
);
@@ -303,7 +303,7 @@ fn verify_char_is_digit_in_radix_7_fails() {
assert_eq!(
failures,
&[r"expected subject to be a digit in the radix 7
- but was: 7
+ but was: '7'
expected: a digit in the radix 7
"]
);
@@ -321,7 +321,7 @@ fn verify_borrowed_char_is_digit_in_radix_7_fails() {
assert_eq!(
failures,
&[r"expected subject to be a digit in the radix 7
- but was: 9
+ but was: '9'
expected: a digit in the radix 7
"]
);
@@ -339,7 +339,7 @@ fn verify_char_is_whitespace_fails() {
assert_eq!(
failures,
&[r"expected subject to be whitespace
- but was: _
+ but was: '_'
expected: whitespace
"]
);
@@ -357,7 +357,7 @@ fn verify_borrowed_char_is_whitespace_fails() {
assert_eq!(
failures,
&[r"expected subject to be whitespace
- but was: =
+ but was: '='
expected: whitespace
"]
);
diff --git a/src/char_count.rs b/src/char_count.rs
index 1029e0e..c760341 100644
--- a/src/char_count.rs
+++ b/src/char_count.rs
@@ -8,15 +8,17 @@ use crate::expectations::{
has_char_count, has_char_count_greater_than, has_char_count_in_range, has_char_count_less_than,
};
use crate::properties::CharCountProperty;
-use crate::spec::{DiffFormat, Expectation, Expecting, Expression, FailingStrategy, Spec};
-use crate::std::fmt::Debug;
+use crate::spec::{
+ DiffFormat, Expectation, Expecting, Expression, FailingStrategy, Represent, Represented, Spec,
+};
use crate::std::format;
use crate::std::ops::RangeBounds;
use crate::std::string::String;
-impl AssertHasCharCount for Spec<'_, S, R>
+impl AssertHasCharCount for Spec<'_, S, D, R>
where
- S: CharCountProperty + Debug,
+ S: CharCountProperty,
+ D: Represent,
R: FailingStrategy,
{
fn has_char_count(self, expected_char_count: usize) -> Self {
@@ -25,7 +27,8 @@ where
fn has_char_count_in_range(self, expected_range: U) -> Self
where
- U: RangeBounds + Debug,
+ U: RangeBounds,
+ D: Represent,
{
self.expecting(has_char_count_in_range(expected_range))
}
@@ -47,9 +50,10 @@ where
}
}
-impl Expectation for HasCharCount
+impl Expectation for HasCharCount
where
- S: CharCountProperty + Debug,
+ S: CharCountProperty,
+ D: Represent,
{
fn test(&mut self, subject: &S) -> bool {
subject.char_count_property() == self.expected_char_count
@@ -60,22 +64,24 @@ where
expression: &Expression<'_>,
actual: &S,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let not = if inverted { "not in " } else { "" };
- let marked_actual = mark_unexpected(&actual.char_count_property(), format);
- let marked_expected = mark_missing(&self.expected_char_count, format);
+ let marked_actual = mark_unexpected(&actual.char_count_property(), representation, format);
+ let marked_expected = mark_missing(&self.expected_char_count, representation, format);
+ let expected_char_count = Represented::from((&self.expected_char_count, representation));
format!(
- "expected {expression} to {not}have a char count of {:?}\n but was: {marked_actual}\n expected: {not}{marked_expected}",
- self.expected_char_count
+ "expected {expression} to {not}have a char count of {expected_char_count:?}\n but was: {marked_actual}\n expected: {not}{marked_expected}",
)
}
}
-impl Expectation for HasCharCountInRange
+impl Expectation for HasCharCountInRange
where
- S: CharCountProperty + Debug,
- R: RangeBounds + Debug,
+ S: CharCountProperty,
+ R: RangeBounds,
+ D: Represent + Represent,
{
fn test(&mut self, subject: &S) -> bool {
self.expected_range.contains(&subject.char_count_property())
@@ -86,21 +92,23 @@ where
expression: &Expression<'_>,
actual: &S,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let not = if inverted { "not in " } else { "" };
- let marked_actual = mark_unexpected(&actual.char_count_property(), format);
- let marked_expected = mark_missing(&self.expected_range, format);
+ let marked_actual = mark_unexpected(&actual.char_count_property(), representation, format);
+ let marked_expected = mark_missing(&self.expected_range, representation, format);
+ let expected_range = Represented::from((&self.expected_range, representation));
format!(
- "expected {expression} to {not}have a char count within {:?}\n but was: {marked_actual}\n expected: {not}{marked_expected}",
- self.expected_range,
+ "expected {expression} to {not}have a char count within {expected_range:?}\n but was: {marked_actual}\n expected: {not}{marked_expected}",
)
}
}
-impl Expectation for HasCharCountLessThan
+impl Expectation for HasCharCountLessThan
where
- S: CharCountProperty + Debug,
+ S: CharCountProperty,
+ D: Represent,
{
fn test(&mut self, subject: &S) -> bool {
subject.char_count_property() < self.expected_char_count
@@ -111,11 +119,12 @@ where
expression: &Expression<'_>,
actual: &S,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let (not, cmp) = if inverted { ("not ", ">=") } else { ("", "<") };
- let marked_actual = mark_unexpected(&actual.char_count_property(), format);
- let marked_expected = mark_missing(&self.expected_char_count, format);
+ let marked_actual = mark_unexpected(&actual.char_count_property(), representation, format);
+ let marked_expected = mark_missing(&self.expected_char_count, representation, format);
format!(
"expected {expression} to {not}have a char count less than {:?}\n but was: {marked_actual}\n expected: {cmp} {marked_expected}",
self.expected_char_count,
@@ -123,9 +132,10 @@ where
}
}
-impl Expectation for HasCharCountGreaterThan
+impl Expectation for HasCharCountGreaterThan
where
- S: CharCountProperty + Debug,
+ S: CharCountProperty,
+ D: Represent,
{
fn test(&mut self, subject: &S) -> bool {
subject.char_count_property() > self.expected_char_count
@@ -136,21 +146,23 @@ where
expression: &Expression<'_>,
actual: &S,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let (not, cmp) = if inverted { ("not ", "<=") } else { ("", ">") };
- let marked_actual = mark_unexpected(&actual.char_count_property(), format);
- let marked_expected = mark_missing(&self.expected_char_count, format);
+ let marked_actual = mark_unexpected(&actual.char_count_property(), representation, format);
+ let marked_expected = mark_missing(&self.expected_char_count, representation, format);
+ let expected_char_count = Represented::from((&self.expected_char_count, representation));
format!(
- "expected {expression} to {not}have a char count greater than {:?}\n but was: {marked_actual}\n expected: {cmp} {marked_expected}",
- self.expected_char_count,
+ "expected {expression} to {not}have a char count greater than {expected_char_count:?}\n but was: {marked_actual}\n expected: {cmp} {marked_expected}",
)
}
}
-impl Expectation for HasAtMostCharCount
+impl Expectation for HasAtMostCharCount
where
- S: CharCountProperty + Debug,
+ S: CharCountProperty,
+ D: Represent,
{
fn test(&mut self, subject: &S) -> bool {
subject.char_count_property() <= self.expected_char_count
@@ -161,21 +173,23 @@ where
expression: &Expression<'_>,
actual: &S,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let (not, cmp) = if inverted { ("not ", ">") } else { ("", "<=") };
- let marked_actual = mark_unexpected(&actual.char_count_property(), format);
- let marked_expected = mark_missing(&self.expected_char_count, format);
+ let marked_actual = mark_unexpected(&actual.char_count_property(), representation, format);
+ let marked_expected = mark_missing(&self.expected_char_count, representation, format);
+ let expected_char_count = Represented::from((&self.expected_char_count, representation));
format!(
- "expected {expression} to {not}have at most a char count of {:?}\n but was: {marked_actual}\n expected: {cmp} {marked_expected}",
- self.expected_char_count,
+ "expected {expression} to {not}have at most a char count of {expected_char_count:?}\n but was: {marked_actual}\n expected: {cmp} {marked_expected}",
)
}
}
-impl Expectation for HasAtLeastCharCount
+impl Expectation for HasAtLeastCharCount
where
S: CharCountProperty,
+ D: Represent,
{
fn test(&mut self, subject: &S) -> bool {
subject.char_count_property() >= self.expected_char_count
@@ -186,14 +200,15 @@ where
expression: &Expression<'_>,
actual: &S,
inverted: bool,
+ representation: &D,
format: &DiffFormat,
) -> String {
let (not, cmp) = if inverted { ("not ", "<") } else { ("", ">=") };
- let marked_actual = mark_unexpected(&actual.char_count_property(), format);
- let marked_expected = mark_missing(&self.expected_char_count, format);
+ let marked_actual = mark_unexpected(&actual.char_count_property(), representation, format);
+ let marked_expected = mark_missing(&self.expected_char_count, representation, format);
+ let expected_char_count = Represented::from((&self.expected_char_count, representation));
format!(
- "expected {expression} to {not}have at least a char count of {:?}\n but was: {marked_actual}\n expected: {cmp} {marked_expected}",
- self.expected_char_count,
+ "expected {expression} to {not}have at least a char count of {expected_char_count:?}\n but was: {marked_actual}\n expected: {cmp} {marked_expected}",
)
}
}
diff --git a/src/colored/mod.rs b/src/colored/mod.rs
index 1b80053..a583f5b 100644
--- a/src/colored/mod.rs
+++ b/src/colored/mod.rs
@@ -51,23 +51,18 @@ pub use with_colored_feature::{
diff_format_for_mode,
};
-use crate::spec::{DiffFormat, Highlight};
-use crate::std::fmt::Debug;
+use crate::spec::{DiffFormat, DisplayRepresentation, Highlight, Represent, Represented};
use crate::std::format;
use crate::std::string::{String, ToString};
use crate::std::vec::Vec;
use hashbrown::HashSet;
#[cfg(feature = "colored")]
use with_colored_feature::{
- configured_diff_format_impl, mark_diff_impl, mark_missing_char_impl, mark_missing_impl,
- mark_missing_string_impl, mark_unexpected_char_impl, mark_unexpected_impl,
- mark_unexpected_string_impl,
+ configured_diff_format_impl, mark_diff_impl, mark_missing_impl, mark_unexpected_impl,
};
#[cfg(not(feature = "colored"))]
use without_colored_feature::{
- configured_diff_format_impl, mark_diff_impl, mark_missing_char_impl, mark_missing_impl,
- mark_missing_string_impl, mark_unexpected_char_impl, mark_unexpected_impl,
- mark_unexpected_string_impl,
+ configured_diff_format_impl, mark_diff_impl, mark_missing_impl, mark_unexpected_impl,
};
const NO_HIGHLIGHT: Highlight = Highlight { start: "", end: "" };
@@ -131,7 +126,7 @@ pub fn configured_diff_format() -> DiffFormat {
}
/// Highlights differences between the expected and the actual value and returns
-/// the debug formatted values with marked differences.
+/// the debug-formatted values with marked differences.
///
/// The style for marking differences is determined by the provided
/// [`DiffFormat`].
@@ -144,7 +139,7 @@ pub fn configured_diff_format() -> DiffFormat {
///
/// It returns a tuple of two `String`s. The first string contains the actual
/// value, and the second one contains the expected value. Both strings
-/// represent their according value as debug formatted string with differences
+/// represent their according value as debug-formatted string with differences
/// highlighted.
///
/// # Examples
@@ -154,12 +149,20 @@ pub fn configured_diff_format() -> DiffFormat {
/// # fn main() {}
/// # #[cfg(feature = "colored")]
/// # fn main() {
-/// use asserting::colored::{mark_diff, DIFF_FORMAT_RED_GREEN};
+/// use asserting::{
+/// colored::{mark_diff, DIFF_FORMAT_RED_GREEN},
+/// spec::DebugRepresentation,
+/// };
///
/// let actual = "Hello Welt!";
/// let expected = "Hello World!";
///
-/// let (marked_actual, marked_expected) = mark_diff(&actual, &expected, &DIFF_FORMAT_RED_GREEN);
+/// let (marked_actual, marked_expected) = mark_diff(
+/// &actual,
+/// &expected,
+/// &DebugRepresentation,
+/// &DIFF_FORMAT_RED_GREEN
+/// );
///
/// assert_eq!(marked_actual, "\"Hello W\u{1b}[31me\u{1b}[0ml\u{1b}[31mt\u{1b}[0m!\"");
/// assert_eq!(marked_expected, "\"Hello W\u{1b}[32mor\u{1b}[0ml\u{1b}[32md\u{1b}[0m!\"");
@@ -171,7 +174,10 @@ pub fn configured_diff_format() -> DiffFormat {
/// # fn main() {}
/// # #[cfg(feature = "colored")]
/// # fn main() {
-/// use asserting::colored::{mark_diff, DIFF_FORMAT_RED_BLUE};
+/// use asserting::{
+/// colored::{mark_diff, DIFF_FORMAT_RED_BLUE},
+/// spec::DebugRepresentation,
+/// };
///
/// #[derive(Debug)]
/// struct Pos {
@@ -182,17 +188,30 @@ pub fn configured_diff_format() -> DiffFormat {
/// let actual = Pos { x: 45, y: -21 };
/// let expected = Pos { x: -45, y: -33 };
///
-/// let (marked_actual, marked_expected) = mark_diff(&actual, &expected, &DIFF_FORMAT_RED_BLUE);
+/// let (marked_actual, marked_expected) = mark_diff(
+/// &actual,
+/// &expected,
+/// &DebugRepresentation,
+/// &DIFF_FORMAT_RED_BLUE
+/// );
///
/// assert_eq!(marked_actual, "Pos { x: 45, y: -\u{1b}[31m21\u{1b}[0m }");
/// assert_eq!(marked_expected, "Pos { x: \u{1b}[34m-\u{1b}[0m45, y: -\u{1b}[34m33\u{1b}[0m }");
/// # }
/// ```
-pub fn mark_diff(actual: &S, expected: &E, format: &DiffFormat) -> (String, String)
+pub fn mark_diff(
+ actual: &S,
+ expected: &E,
+ representation: &D,
+ format: &DiffFormat,
+) -> (String, String)
where
- S: Debug + ?Sized,
- E: Debug + ?Sized,
+ S: ?Sized,
+ E: ?Sized,
+ D: Represent + Represent,
{
+ let actual = Represented::from((actual, representation));
+ let expected = Represented::from((expected, representation));
let actual = format!("{actual:?}");
let expected = format!("{expected:?}");
mark_diff_impl(&actual, &expected, format)
@@ -218,60 +237,22 @@ pub fn mark_diff_str(actual: &str, expected: &str, format: &DiffFormat) -> (Stri
/// Highlights the given value as "unexpected value" using the color for
/// unexpected values or bold as specified by the given [`DiffFormat`].
-pub fn mark_unexpected(value: &T, format: &DiffFormat) -> String
+pub fn mark_unexpected(value: &T, representation: &D, format: &DiffFormat) -> String
where
- T: Debug + ?Sized,
+ T: ?Sized,
+ D: Represent,
{
- mark_unexpected_impl(value, format)
+ mark_unexpected_impl(value, representation, format)
}
/// Highlights the given value as "missing value" using the color for
/// "missing values" as specified by the given [`DiffFormat`].
-pub fn mark_missing(value: &T, format: &DiffFormat) -> String
+pub fn mark_missing(value: &T, representation: &D, format: &DiffFormat) -> String
where
- T: Debug + ?Sized,
+ T: ?Sized,
+ D: Represent,
{
- mark_missing_impl(value, format)
-}
-
-/// Highlights the given string as "unexpected value" using the color for
-/// unexpected values or bold as specified by the given [`DiffFormat`].
-///
-/// When using this function in comparison to [`mark_unexpected`], the returned
-/// string does not contain quotes at the start and end of the string as they
-/// appear in the debug formatted string returned by [`mark_unexpected`].
-pub fn mark_unexpected_string(string: &str, format: &DiffFormat) -> String {
- mark_unexpected_string_impl(string, format)
-}
-
-/// Highlights the given string as "missing value" using the color for
-/// missing values as specified by the given [`DiffFormat`].
-///
-/// When using this function in comparison to [`mark_missing`], the returned
-/// string does not contain quotes at the start and end of the string as they
-/// appear in the debug formatted string returned by [`mark_missing`].
-pub fn mark_missing_string(string: &str, format: &DiffFormat) -> String {
- mark_missing_string_impl(string, format)
-}
-
-/// Highlights the given character as "unexpected value" using the color for
-/// unexpected values or bold as specified by the given [`DiffFormat`].
-///
-/// When using this function in comparison to [`mark_unexpected`], the returned
-/// string does not contain single quotes around the character as they
-/// appear in the debug formatted string returned by [`mark_unexpected`].
-pub fn mark_unexpected_char(character: char, format: &DiffFormat) -> String {
- mark_unexpected_char_impl(character, format)
-}
-
-/// Highlights the given character as "missing value" using the color for
-/// missing values as specified by the given [`DiffFormat`].
-///
-/// When using this function in comparison to [`mark_missing`], the returned
-/// string does not contain single quotes around the character as they
-/// appear in the debug formatted string returned by [`mark_missing`].
-pub fn mark_missing_char(character: char, format: &DiffFormat) -> String {
- mark_missing_char_impl(character, format)
+ mark_missing_impl(value, representation, format)
}
/// Highlights a substring within a string using the color for unexpected values
@@ -303,7 +284,14 @@ pub fn mark_unexpected_substring_in_string(
substring: &str,
format: &DiffFormat,
) -> String {
- mark_substring_in_string(string, substring, format, mark_unexpected_string)
+ mark_substring_in_string(
+ string,
+ substring,
+ format,
+ |string, _: &DisplayRepresentation, format| {
+ mark_unexpected(string, &DisplayRepresentation, format)
+ },
+ )
}
/// Highlights a substring within a string using the color for missing values
@@ -335,7 +323,14 @@ pub fn mark_missing_substring_in_string(
substring: &str,
format: &DiffFormat,
) -> String {
- mark_substring_in_string(string, substring, format, mark_missing_string)
+ mark_substring_in_string(
+ string,
+ substring,
+ format,
+ |string, _: &DisplayRepresentation, format| {
+ mark_missing(string, &DisplayRepresentation, format)
+ },
+ )
}
fn mark_substring_in_string(
@@ -345,13 +340,13 @@ fn mark_substring_in_string(
mark: F,
) -> String
where
- F: Fn(&str, &DiffFormat) -> String,
+ F: Fn(&str, &DisplayRepresentation, &DiffFormat) -> String,
{
if let Some(position) = string.find(substring) {
let length = substring.len();
let begin = &string[..position];
let end = &string[position + length..];
- let marked_substr = mark(substring, format);
+ let marked_substr = mark(substring, &DisplayRepresentation, format);
format!("{begin}{marked_substr}{end}")
} else {
string.to_string()
@@ -387,7 +382,9 @@ pub fn mark_unexpected_char_in_string(
character: char,
format: &DiffFormat,
) -> String {
- mark_char_in_string(string, character, format, mark_unexpected_string)
+ mark_char_in_string(string, character, format, |string, format| {
+ mark_unexpected(string, &DisplayRepresentation, format)
+ })
}
/// Highlights all occurences of a character within a string using the color for
@@ -415,7 +412,9 @@ pub fn mark_unexpected_char_in_string(
/// # }
/// ```
pub fn mark_missing_char_in_string(string: &str, character: char, format: &DiffFormat) -> String {
- mark_char_in_string(string, character, format, mark_missing_string)
+ mark_char_in_string(string, character, format, |string, format| {
+ mark_missing(string, &DisplayRepresentation, format)
+ })
}
fn mark_char_in_string(string: &str, character: char, format: &DiffFormat, mark: F) -> String
@@ -562,7 +561,10 @@ fn mark_selected_chars_in_string(
/// # fn main() {}
/// # #[cfg(feature = "colored")]
/// # fn main() {
-/// use asserting::colored::{mark_missing, mark_selected_items_in_collection, DIFF_FORMAT_RED_BLUE};
+/// use asserting::{
+/// colored::{mark_missing, mark_selected_items_in_collection, DIFF_FORMAT_RED_BLUE},
+/// spec::DebugRepresentation,
+/// };
/// use hashbrown::HashSet;
///
/// let collection = [1, 2, 3, 4, 5];
@@ -571,6 +573,7 @@ fn mark_selected_chars_in_string(
/// let marked_collection = mark_selected_items_in_collection(
/// &collection,
/// &selected_items,
+/// &DebugRepresentation,
/// &DIFF_FORMAT_RED_BLUE,
/// mark_missing
/// );
@@ -578,15 +581,16 @@ fn mark_selected_chars_in_string(
/// assert_eq!(marked_collection, "[1, \u{1b}[34m2\u{1b}[0m, \u{1b}[34m3\u{1b}[0m, 4, \u{1b}[34m5\u{1b}[0m]");
/// # }
/// ```
-pub fn mark_selected_items_in_collection(
+pub fn mark_selected_items_in_collection(
collection: &[T],
selected_indices: &HashSet,
+ representation: &D,
format: &DiffFormat,
mark: F,
) -> String
where
- T: Debug,
- F: Fn(&T, &DiffFormat) -> String,
+ D: Represent,
+ F: Fn(&T, &D, &DiffFormat) -> String,
{
let mut marked_collection = String::with_capacity(collection.len() + 2);
marked_collection.push('[');
@@ -595,8 +599,9 @@ where
.enumerate()
.map(|(index, item)| {
if selected_indices.contains(&index) {
- mark(item, format)
+ mark(item, representation, format)
} else {
+ let item = Represented::from((item, representation));
format!("{item:?}")
}
})
@@ -627,13 +632,17 @@ where
/// # fn main() {}
/// # #[cfg(feature = "colored")]
/// # fn main() {
-/// use asserting::colored::{mark_all_items_in_collection, mark_unexpected, DIFF_FORMAT_RED_BLUE};
+/// use asserting::{
+/// colored::{mark_all_items_in_collection, mark_unexpected, DIFF_FORMAT_RED_BLUE},
+/// spec::DebugRepresentation,
+/// };
/// use hashbrown::HashSet;
///
/// let collection = [1, 2, 3, 4, 5];
///
/// let marked_collection = mark_all_items_in_collection(
/// &collection,
+/// &DebugRepresentation,
/// &DIFF_FORMAT_RED_BLUE,
/// mark_unexpected
/// );
@@ -641,16 +650,20 @@ where
/// assert_eq!(marked_collection, "[\u{1b}[31m1\u{1b}[0m, \u{1b}[31m2\u{1b}[0m, \u{1b}[31m3\u{1b}[0m, \u{1b}[31m4\u{1b}[0m, \u{1b}[31m5\u{1b}[0m]");
/// # }
/// ```
-pub fn mark_all_items_in_collection(collection: &[T], format: &DiffFormat, mark: F) -> String
+pub fn mark_all_items_in_collection(
+ collection: &[T],
+ representation: &D,
+ format: &DiffFormat,
+ mark: F,
+) -> String
where
- T: Debug,
- F: Fn(&T, &DiffFormat) -> String,
+ F: Fn(&T, &D, &DiffFormat) -> String,
{
let mut marked_collection = String::with_capacity(collection.len() + 2);
marked_collection.push('[');
collection
.iter()
- .map(|item| mark(item, format))
+ .map(|item| mark(item, representation, format))
.for_each(|item| {
marked_collection.push_str(&item);
marked_collection.push_str(", ");
@@ -678,7 +691,8 @@ where
/// # fn main() {}
/// # #[cfg(all(feature = "colored", feature = "std"))]
/// # fn main() {
-/// use asserting::colored::{mark_missing_string, mark_selected_entries_in_map, DIFF_FORMAT_RED_BLUE};
+/// use asserting::colored::{mark_missing, mark_selected_entries_in_map, DIFF_FORMAT_RED_BLUE};
+/// use asserting::spec::DebugRepresentation;
/// use hashbrown::HashSet;
/// use std::collections::BTreeMap;
///
@@ -689,23 +703,24 @@ where
/// let marked_map = mark_selected_entries_in_map(
/// &map_entries,
/// &selected_entries,
+/// &DebugRepresentation,
/// &DIFF_FORMAT_RED_BLUE,
-/// mark_missing_string
+/// mark_missing,
/// );
///
/// assert_eq!(marked_map, "{\u{1b}[34m1: \"one\"\u{1b}[0m, 2: \"two\", \u{1b}[34m3: \"three\"\u{1b}[0m, 4: \"four\"}");
/// # }
/// ```
-pub fn mark_selected_entries_in_map(
- map_entries: &[(K, V)],
+pub fn mark_selected_entries_in_map(
+ map_entries: &[(&K, &V)],
selected_indices: &HashSet,
+ representation: &D,
format: &DiffFormat,
mark: F,
) -> String
where
- K: Debug,
- V: Debug,
- F: Fn(&str, &DiffFormat) -> String,
+ F: Fn(&str, &DisplayRepresentation, &DiffFormat) -> String,
+ D: Represent + Represent,
{
let mut marked_map_entries = String::with_capacity(map_entries.len() + 2);
marked_map_entries.push('{');
@@ -713,9 +728,11 @@ where
.iter()
.enumerate()
.map(|(index, entry)| {
- let key_value_pair = format!("{:?}: {:?}", entry.0, entry.1);
+ let represented_key = Represented::from((entry.0, representation));
+ let represented_value = Represented::from((entry.1, representation));
+ let key_value_pair = format!("{represented_key:?}: {represented_value:?}");
if selected_indices.contains(&index) {
- mark(&key_value_pair, format)
+ mark(&key_value_pair, &DisplayRepresentation, format)
} else {
key_value_pair
}
@@ -747,7 +764,8 @@ where
/// # fn main() {}
/// # #[cfg(all(feature = "colored", feature = "std"))]
/// # fn main() {
-/// use asserting::colored::{mark_all_entries_in_map, mark_unexpected_string, DIFF_FORMAT_RED_BLUE};
+/// use asserting::colored::{mark_all_entries_in_map, mark_unexpected, DIFF_FORMAT_RED_BLUE};
+/// use asserting::spec::DebugRepresentation;
/// use std::collections::BTreeMap;
///
/// let map: BTreeMap<_, _> = [(1, "one"), (2, "two"), (3, "three"), (4, "four")].into();
@@ -755,30 +773,33 @@ where
/// let map_entries: Vec<_> = map.iter().collect();
/// let marked_map = mark_all_entries_in_map(
/// &map_entries,
+/// &DebugRepresentation,
/// &DIFF_FORMAT_RED_BLUE,
-/// mark_unexpected_string
+/// mark_unexpected,
/// );
///
/// assert_eq!(marked_map, "{\u{1b}[31m1: \"one\"\u{1b}[0m, \u{1b}[31m2: \"two\"\u{1b}[0m, \u{1b}[31m3: \"three\"\u{1b}[0m, \u{1b}[31m4: \"four\"\u{1b}[0m}");
/// # }
/// ```
-pub fn mark_all_entries_in_map(
- map_entries: &[(K, V)],
+pub fn mark_all_entries_in_map(
+ map_entries: &[(&K, &V)],
+ representation: &D,
format: &DiffFormat,
mark: F,
) -> String
where
- K: Debug,
- V: Debug,
- F: Fn(&str, &DiffFormat) -> String,
+ F: Fn(&str, &DisplayRepresentation, &DiffFormat) -> String,
+ D: Represent + Represent,
{
let mut marked_map_entries = String::with_capacity(map_entries.len() + 2);
marked_map_entries.push('{');
map_entries
.iter()
.map(|entry| {
- let key_value_pair = format!("{:?}: {:?}", entry.0, entry.1);
- mark(&key_value_pair, format)
+ let represented_key = Represented::from((entry.0, representation));
+ let represented_value = Represented::from((entry.1, representation));
+ let key_value_pair = format!("{represented_key:?}: {represented_value:?}");
+ mark(&key_value_pair, &DisplayRepresentation, format)
})
.for_each(|entry| {
marked_map_entries.push_str(&entry);
@@ -795,9 +816,8 @@ where
#[cfg(not(feature = "colored"))]
mod without_colored_feature {
use super::DIFF_FORMAT_NO_HIGHLIGHT;
- use crate::spec::DiffFormat;
+ use crate::spec::{DiffFormat, Represent, Represented};
use crate::std::{
- fmt::Debug,
format,
string::{String, ToString},
};
@@ -817,47 +837,31 @@ mod without_colored_feature {
}
#[inline]
- pub fn mark_unexpected_impl(value: &T, _format: &DiffFormat) -> String
+ pub fn mark_unexpected_impl(value: &T, representation: &D, _format: &DiffFormat) -> String
where
- T: Debug + ?Sized,
+ T: ?Sized,
+ D: Represent,
{
+ let value = Represented::from((value, representation));
format!("{value:?}")
}
#[inline]
- pub fn mark_missing_impl(value: &T, _format: &DiffFormat) -> String
+ pub fn mark_missing_impl(value: &T, representation: &D, _format: &DiffFormat) -> String
where
- T: Debug + ?Sized,
+ T: ?Sized,
+ D: Represent,
{
+ let value = Represented::from((value, representation));
format!("{value:?}")
}
-
- #[inline]
- pub fn mark_unexpected_string_impl(string: &str, _format: &DiffFormat) -> String {
- string.to_string()
- }
-
- #[inline]
- pub fn mark_missing_string_impl(string: &str, _format: &DiffFormat) -> String {
- string.to_string()
- }
-
- #[inline]
- pub fn mark_unexpected_char_impl(character: char, _format: &DiffFormat) -> String {
- format!("{character}")
- }
-
- #[inline]
- pub fn mark_missing_char_impl(character: char, _format: &DiffFormat) -> String {
- format!("{character}")
- }
}
#[cfg(feature = "colored")]
mod with_colored_feature {
use super::DIFF_FORMAT_NO_HIGHLIGHT;
- use crate::spec::{DiffFormat, Highlight};
- use crate::std::{fmt::Debug, format, string::String};
+ use crate::spec::{DiffFormat, Highlight, Represent, Represented};
+ use crate::std::{format, string::String};
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
@@ -1079,48 +1083,26 @@ mod with_colored_feature {
}
#[inline]
- pub fn mark_unexpected_impl(value: &T, format: &DiffFormat) -> String
+ pub fn mark_unexpected_impl(value: &T, representation: &D, format: &DiffFormat) -> String
where
- T: Debug + ?Sized,
+ T: ?Sized,
+ D: Represent,
{
+ let value = Represented::from((value, representation));
format!(
- "{}{value:?}{}",
+ "{}{value}{}",
format.unexpected.start, format.unexpected.end
)
}
#[inline]
- pub fn mark_missing_impl(value: &T, format: &DiffFormat) -> String
+ pub fn mark_missing_impl(value: &T, representation: &D, format: &DiffFormat) -> String
where
- T: Debug + ?Sized,
+ T: ?Sized,
+ D: Represent,
{
- format!("{}{value:?}{}", format.missing.start, format.missing.end)
- }
-
- #[inline]
- pub fn mark_unexpected_string_impl(string: &str, format: &DiffFormat) -> String {
- format!(
- "{}{string}{}",
- format.unexpected.start, format.unexpected.end
- )
- }
-
- #[inline]
- pub fn mark_missing_string_impl(string: &str, format: &DiffFormat) -> String {
- format!("{}{string}{}", format.missing.start, format.missing.end)
- }
-
- #[inline]
- pub fn mark_unexpected_char_impl(character: char, format: &DiffFormat) -> String {
- format!(
- "{}{character}{}",
- format.unexpected.start, format.unexpected.end
- )
- }
-
- #[inline]
- pub fn mark_missing_char_impl(character: char, format: &DiffFormat) -> String {
- format!("{}{character}{}", format.missing.start, format.missing.end)
+ let value = Represented::from((value, representation));
+ format!("{}{value}{}", format.missing.start, format.missing.end)
}
}
diff --git a/src/colored/tests.rs b/src/colored/tests.rs
index fe1c74f..36aa85b 100644
--- a/src/colored/tests.rs
+++ b/src/colored/tests.rs
@@ -28,6 +28,7 @@ mod without_colored_feature {
#[cfg(feature = "colored")]
mod with_colored_feature {
use super::*;
+ use crate::spec::DebugRepresentation;
use hashbrown::HashMap;
#[test]
@@ -72,56 +73,72 @@ mod with_colored_feature {
#[test]
fn mark_unexpected_highlights_a_string_with_double_quotes() {
- let marked_string = mark_unexpected("blandit invidunt", &DIFF_FORMAT_RED_YELLOW);
+ let marked_string = mark_unexpected(
+ "blandit invidunt",
+ &DebugRepresentation,
+ &DIFF_FORMAT_RED_YELLOW,
+ );
assert_that(marked_string).is_equal_to("\u{1b}[31m\"blandit invidunt\"\u{1b}[0m");
}
#[test]
fn mark_missing_highlights_a_string_with_double_quotes() {
- let marked_string = mark_missing("blandit invidunt", &DIFF_FORMAT_RED_YELLOW);
+ let marked_string = mark_missing(
+ "blandit invidunt",
+ &DebugRepresentation,
+ &DIFF_FORMAT_RED_YELLOW,
+ );
assert_that(marked_string).is_equal_to("\u{1b}[33m\"blandit invidunt\"\u{1b}[0m");
}
#[test]
fn mark_unexpected_string_highlights_a_string_without_double_quotes() {
- let marked_string = mark_unexpected_string("blandit invidunt", &DIFF_FORMAT_RED_YELLOW);
+ let marked_string = mark_unexpected(
+ "blandit invidunt",
+ &DisplayRepresentation,
+ &DIFF_FORMAT_RED_YELLOW,
+ );
assert_that(marked_string).is_equal_to("\u{1b}[31mblandit invidunt\u{1b}[0m");
}
#[test]
fn mark_missing_string_highlights_a_string_without_double_quotes() {
- let marked_string = mark_missing_string("blandit invidunt", &DIFF_FORMAT_RED_YELLOW);
+ let marked_string = mark_missing(
+ "blandit invidunt",
+ &DisplayRepresentation,
+ &DIFF_FORMAT_RED_YELLOW,
+ );
assert_that(marked_string).is_equal_to("\u{1b}[33mblandit invidunt\u{1b}[0m");
}
#[test]
fn mark_unexpected_highlights_a_char_with_single_quotes() {
- let marked_char = mark_unexpected(&'R', &DIFF_FORMAT_RED_GREEN);
+ let marked_char = mark_unexpected(&'R', &DebugRepresentation, &DIFF_FORMAT_RED_GREEN);
assert_that(marked_char).is_equal_to("\u{1b}[31m'R'\u{1b}[0m");
}
#[test]
fn mark_missing_highlights_a_char_with_single_quotes() {
- let marked_char = mark_missing(&'R', &DIFF_FORMAT_RED_GREEN);
+ let marked_char = mark_missing(&'R', &DebugRepresentation, &DIFF_FORMAT_RED_GREEN);
assert_that(marked_char).is_equal_to("\u{1b}[32m'R'\u{1b}[0m");
}
#[test]
fn mark_unexpected_char_highlights_char_without_single_quotes() {
- let marked_char = mark_unexpected_char('R', &DIFF_FORMAT_RED_GREEN);
+ let marked_char = mark_unexpected(&'R', &DisplayRepresentation, &DIFF_FORMAT_RED_GREEN);
assert_that(marked_char).is_equal_to("\u{1b}[31mR\u{1b}[0m");
}
#[test]
fn mark_missing_char_highlights_char_without_single_quotes() {
- let marked_char = mark_missing_char('R', &DIFF_FORMAT_RED_GREEN);
+ let marked_char = mark_missing(&'R', &DisplayRepresentation, &DIFF_FORMAT_RED_GREEN);
assert_that(marked_char).is_equal_to("\u{1b}[32mR\u{1b}[0m");
}
@@ -267,6 +284,7 @@ mod with_colored_feature {
let marked_collection = mark_selected_items_in_collection(
collection,
&selected,
+ &DebugRepresentation,
&DIFF_FORMAT_RED_GREEN,
mark_missing,
);
@@ -278,8 +296,12 @@ mod with_colored_feature {
fn mark_all_items_in_collection_for_empty_collection() {
let collection: &[usize] = &[];
- let marked_collection =
- mark_all_items_in_collection(collection, &DIFF_FORMAT_RED_GREEN, mark_missing);
+ let marked_collection = mark_all_items_in_collection(
+ collection,
+ &DebugRepresentation,
+ &DIFF_FORMAT_RED_GREEN,
+ mark_missing,
+ );
assert_that(marked_collection).is_equal_to("[]");
}
@@ -293,6 +315,7 @@ mod with_colored_feature {
let marked_map = mark_selected_entries_in_map(
&map_entries,
&selected,
+ &DebugRepresentation,
&DIFF_FORMAT_RED_GREEN,
mark_missing,
);
@@ -300,16 +323,59 @@ mod with_colored_feature {
assert_that(marked_map).is_equal_to("{}");
}
+ #[test]
+ fn mark_selected_entries_in_map_with_entries() {
+ let key1 = 1;
+ let val1 = "one";
+ let key2 = 2;
+ let val2 = "two";
+ let map_entries = [(&key1, &val1), (&key2, &val2)];
+ let selected: HashSet = [0].into();
+
+ let marked_map = mark_selected_entries_in_map(
+ &map_entries,
+ &selected,
+ &DebugRepresentation,
+ &DIFF_FORMAT_RED_BLUE,
+ mark_missing,
+ );
+
+ assert_that(marked_map).is_equal_to("{\u{1b}[34m1: \"one\"\u{1b}[0m, 2: \"two\"}");
+ }
+
#[test]
fn mark_all_entries_in_map_for_empty_map() {
let map: HashMap = HashMap::new();
let map_entries: Vec<_> = map.iter().collect();
- let marked_map =
- mark_all_entries_in_map(&map_entries, &DIFF_FORMAT_RED_GREEN, mark_missing);
+ let marked_map = mark_all_entries_in_map(
+ &map_entries,
+ &DebugRepresentation,
+ &DIFF_FORMAT_RED_GREEN,
+ mark_missing,
+ );
assert_that(marked_map).is_equal_to("{}");
}
+
+ #[test]
+ fn mark_all_entries_in_map_with_entries() {
+ let key1 = 1;
+ let val1 = "one";
+ let key2 = 2;
+ let val2 = "two";
+ let map_entries = [(&key1, &val1), (&key2, &val2)];
+
+ let marked_map = mark_all_entries_in_map(
+ &map_entries,
+ &DebugRepresentation,
+ &DIFF_FORMAT_RED_BLUE,
+ mark_unexpected,
+ );
+
+ assert_that(marked_map)
+ .is_equal_to("{\u{1b}[31m1: \"one\"\u{1b}[0m, \u{1b}[31m2: \"two\"\u{1b}[0m}");
+ }
}
#[cfg(all(feature = "colored", not(feature = "std")))]
diff --git a/src/derived_spec/mod.rs b/src/derived_spec/mod.rs
index 2a4f9d6..9579024 100644
--- a/src/derived_spec/mod.rs
+++ b/src/derived_spec/mod.rs
@@ -35,11 +35,15 @@ use crate::properties::{
MultiplicativeIdentityProperty, SignumProperty,
};
use crate::spec::{
- And, AssertFailure, CollectFailures, DiffFormat, DoFail, Expectation, Expecting, Expression,
- FailingStrategy, GetFailures, GetLocation, Location, PanicOnFail, Satisfies, SoftPanic, Spec,
+ AdHocRepresentation, And, AssertFailure, CollectFailures, DebugRepresentation, DiffFormat,
+ DoFail, Expectation, Expecting, Expression, FailingStrategy, GetFailures, GetLocation,
+ Location, PanicOnFail, Represent, Represented, RepresentedAs, RepresentedBy, Satisfies,
+ SoftPanic, Spec,
};
use crate::std::borrow::{Cow, ToOwned};
+use crate::std::boxed::Box;
use crate::std::error::Error;
+use crate::std::fmt;
use crate::std::fmt::{Debug, Display};
use crate::std::format;
use crate::std::ops::RangeBounds;
@@ -59,14 +63,20 @@ use hashbrown::HashSet;
/// reports.
///
/// [`Spec`]: Spec
-pub struct DerivedSpec<'a, O, S> {
+pub struct DerivedSpec<'a, O, S, D> {
original: O,
subject: S,
expression: Expression<'a>,
diff_format: DiffFormat,
+ representation: D,
}
-impl DerivedSpec<'_, O, S> {
+impl DerivedSpec<'_, O, S, D> {
+ /// Returns the subject.
+ pub fn subject(&self) -> &S {
+ &self.subject
+ }
+
/// Returns the expression (or subject name) if one has been set.
pub fn expression(&self) -> &Expression<'_> {
&self.expression
@@ -76,9 +86,15 @@ impl