Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,15 @@ for types that implement `core::fmt::Debug`:
|----------------------------|----------------------------------------------------------------------------|
| has_debug_string | verify that a type formatted for debug is equal to the expected string |
| does_not_have_debug_string | verify that a type formatted for debug is not equal to the expected string |
| debug_string | map the subject to its debug string representation |

for types that implement `core::fmt::Display`:

| assertion | description |
|------------------------------|------------------------------------------------------------------------------|
| has_display_string | verify that a type formatted for display is equal to the expected string |
| does_not_have_display_string | verify that a type formatted for display is not equal to the expected string |
| display_string | map the subject to its display string representation |

### Emptiness

Expand Down
92 changes: 92 additions & 0 deletions src/assertions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2332,6 +2332,47 @@ pub trait AssertHasDebugString<E> {
fn does_not_have_debug_string(self, expected: E) -> Self;
}

/// Mapping the subject into its debug string representation to do assertions on
/// its debug string.
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// #[derive(Debug)]
/// struct Foo {
/// hello: String,
/// }
///
/// let subject = Foo { hello: "World".into() };
///
/// assert_that!(&subject).debug_string().contains("World");
/// assert_that!(&subject).debug_string().does_not_start_with("Bar");
/// ```
pub trait AssertDebugString<'a, R> {
/// Maps the subject into its debug string representation to do assertions
/// on its debug string.
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// #[derive(Debug)]
/// struct Foo {
/// hello: String,
/// }
///
/// let subject = Foo { hello: "World".into() };
///
/// assert_that!(&subject).debug_string().contains("World");
/// assert_that!(&subject).debug_string().does_not_start_with("Bar");
/// ```
#[track_caller]
fn debug_string(self) -> Spec<'a, String, R>;
}

/// Assert a type formatted into a display string.
///
/// The subject's type must implement `Display` and the expected type must
Expand Down Expand Up @@ -2409,6 +2450,57 @@ pub trait AssertHasDisplayString<E> {
fn does_not_have_display_string(self, expected: E) -> Self;
}

/// Mapping the subject into its display string representation to do assertions
/// on its display string.
///
/// # Examples
///
/// ```
/// use core::fmt::{self, Display};
/// use asserting::prelude::*;
///
/// struct Foo {
/// hello: String,
/// }
///
/// impl Display for Foo {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// write!(f, "Hello, {}", self.hello)
/// }
/// }
///
/// let subject = Foo { hello: "World".into() };
///
/// assert_that!(&subject).display_string().is_equal_to("Hello, World");
/// assert_that!(&subject).display_string().does_not_end_with('!');
/// ```
pub trait AssertDisplayString<'a, R> {
/// Maps the subject into its display string representation to do assertions
/// on its display string.
///
/// # Examples
///
/// ```
/// use core::fmt::{self, Display};
/// use asserting::prelude::*;
///
/// struct Foo {
/// hello: String,
/// }
///
/// impl Display for Foo {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// write!(f, "Hello, {}", self.hello)
/// }
/// }
///
/// let subject = Foo { hello: "World".into() };
///
/// assert_that!(&subject).display_string().is_equal_to("Hello, World");
/// assert_that!(&subject).display_string().does_not_end_with('!');
/// ```
#[track_caller]
fn display_string(self) -> Spec<'a, String, R>;
}

/// Assert that a string contains a substring or character.
///
/// # Examples
Expand Down
67 changes: 67 additions & 0 deletions src/error/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,3 +359,70 @@ mod colored {
);
}
}

#[cfg(feature = "regex")]
mod with_regex {
use super::*;

#[test]
fn error_has_debug_string_matching_regex() {
let error = SuperError {
source: SourceError::Bar,
};

assert_that(error).debug_string().matches(r"SuperError.*");
}

#[test]
fn verify_error_has_debug_string_matching_regex_fails() {
let error = SuperError {
source: SourceError::Bar,
};

let failures = verify_that(error)
.debug_string()
.matches(r"SuperError \{ (source|target): Foo \}")
.display_failures();

assert_eq!(
failures,
&[
r"expected subject's debug string to match the regex SuperError \{ (source|target): Foo \}
but was: SuperError { source: Bar }
does not match regex: SuperError \{ (source|target): Foo \}
"
]
);
}

#[test]
fn error_has_display_string_matching_regex() {
let error = SuperError {
source: SourceError::Bar,
};

assert_that(error).display_string().matches(r".*-error .*");
}

#[test]
fn verify_error_has_display_string_matching_regex_fails() {
let error = SuperError {
source: SourceError::Bar,
};

let failures = verify_that(error)
.display_string()
.matches(r".*-error-caused.*")
.display_failures();

assert_eq!(
failures,
&[
r"expected subject's display string to match the regex .*-error-caused.*
but was: super-error caused by bar error
does not match regex: .*-error-caused.*
"
]
);
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,7 @@ mod integer;
mod iterator;
mod length;
mod map;
mod mapping;
#[cfg(feature = "num-bigint")]
mod num_bigint;
mod number;
Expand Down
29 changes: 29 additions & 0 deletions src/mapping.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::assertions::{AssertDebugString, AssertDisplayString};
use crate::spec::{FailingStrategy, Spec};
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>
where
S: Debug,
R: FailingStrategy,
{
fn debug_string(self) -> Spec<'a, String, R> {
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>
where
S: Display,
R: FailingStrategy,
{
fn display_string(self) -> Spec<'a, String, R> {
let expression_display_string = format!("{}'s display string", self.expression());
self.mapping(|subject| subject.to_string())
.named(expression_display_string)
}
}
Loading