> = None;
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .has_value(vec![1, 2, 3, 5, 7])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject is some containing [1, 2, 3, 5, 7]\n \
+ but was: \u{1b}[31mNone\u{1b}[0m\n \
+ expected: \u{1b}[33mSome([1, 2, 3, 5, 7])\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+}
diff --git a/src/order/mod.rs b/src/order/mod.rs
index f474f2a..9f444ce 100644
--- a/src/order/mod.rs
+++ b/src/order/mod.rs
@@ -1,8 +1,9 @@
//! Implementation of order assertions.
use crate::assertions::AssertOrder;
+use crate::colored::{mark_missing, mark_unexpected};
use crate::expectations::{IsAtLeast, IsAtMost, IsGreaterThan, IsLessThan};
-use crate::spec::{Expectation, Expression, FailingStrategy, Spec};
+use crate::spec::{DiffFormat, Expectation, Expression, FailingStrategy, Spec};
use crate::std::fmt::Debug;
use crate::std::{format, string::String};
@@ -38,10 +39,12 @@ where
subject < &self.expected
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&self.expected, format);
format!(
- "expected {expression} is less than {:?}\n but was: {actual:?}\n expected: < {:?}",
- self.expected, self.expected,
+ "expected {expression} is less than {:?}\n but was: {marked_actual}\n expected: < {marked_expected}",
+ self.expected,
)
}
}
@@ -55,10 +58,12 @@ where
subject <= &self.expected
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&self.expected, format);
format!(
- "expected {expression} is at most {:?}\n but was: {actual:?}\n expected: <= {:?}",
- self.expected, self.expected,
+ "expected {expression} is at most {:?}\n but was: {marked_actual}\n expected: <= {marked_expected}",
+ self.expected,
)
}
}
@@ -72,10 +77,12 @@ where
subject > &self.expected
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&self.expected, format);
format!(
- "expected {expression} is greater than {:?}\n but was: {actual:?}\n expected: > {:?}",
- self.expected, self.expected,
+ "expected {expression} is greater than {:?}\n but was: {marked_actual}\n expected: > {marked_expected}",
+ self.expected,
)
}
}
@@ -89,10 +96,12 @@ where
subject >= &self.expected
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&self.expected, format);
format!(
- "expected {expression} is at least {:?}\n but was: {actual:?}\n expected: >= {:?}",
- self.expected, self.expected,
+ "expected {expression} is at least {:?}\n but was: {marked_actual}\n expected: >= {marked_expected}",
+ self.expected,
)
}
}
diff --git a/src/order/tests.rs b/src/order/tests.rs
index 03653b1..c782995 100644
--- a/src/order/tests.rs
+++ b/src/order/tests.rs
@@ -207,3 +207,82 @@ fn verify_char_is_at_least_other_char_fails() {
"]
);
}
+
+#[cfg(feature = "colored")]
+mod colored {
+ use crate::prelude::*;
+
+ #[test]
+ fn highlight_diffs_is_less_than() {
+ let subject = 3.781;
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .is_less_than(3.779)
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject is less than 3.779\n \
+ but was: \u{1b}[31m3.781\u{1b}[0m\n \
+ expected: < \u{1b}[32m3.779\u{1b}[0m\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_is_at_most() {
+ let subject = 3.781;
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .is_at_most(3.779)
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject is at most 3.779\n \
+ but was: \u{1b}[31m3.781\u{1b}[0m\n \
+ expected: <= \u{1b}[34m3.779\u{1b}[0m\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_is_greater_than() {
+ let subject = 3.781;
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .is_greater_than(3.782)
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject is greater than 3.782\n \
+ but was: \u{1b}[31m3.781\u{1b}[0m\n \
+ expected: > \u{1b}[33m3.782\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_is_at_least() {
+ let subject = 3.781;
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .is_at_least(3.782)
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject is at least 3.782\n \
+ but was: \u{1b}[31m3.781\u{1b}[0m\n \
+ expected: >= \u{1b}[34m3.782\u{1b}[0m\n\
+ "]
+ );
+ }
+}
diff --git a/src/panic/mod.rs b/src/panic/mod.rs
index 5cf06cf..9f950d8 100644
--- a/src/panic/mod.rs
+++ b/src/panic/mod.rs
@@ -1,8 +1,9 @@
//! Implementation of assertions for code that should or should not panic.
use crate::assertions::AssertCodePanics;
+use crate::colored::{mark_missing_substr, mark_unexpected_substr};
use crate::expectations::{DoesNotPanic, DoesPanic};
-use crate::spec::{Code, Expectation, Expression, FailingStrategy, Spec};
+use crate::spec::{Code, DiffFormat, Expectation, Expression, FailingStrategy, Spec};
use crate::std::any::Any;
use crate::std::panic;
@@ -47,15 +48,22 @@ where
}
}
- fn message(&self, expression: Expression<'_>, _actual: &Code) -> String {
+ fn message(
+ &self,
+ expression: Expression<'_>,
+ _actual: &Code,
+ format: &DiffFormat,
+ ) -> String {
let panic_message = read_panic_message(self.actual_message.as_ref())
.unwrap_or_else(|| UNKNOWN_PANIC_MESSAGE.to_string());
if panic_message == ONLY_ONE_EXPECTATION {
format!("error in test assertion: {ONLY_ONE_EXPECTATION}")
} else {
+ let marked_did_panic = mark_unexpected_substr("did panic", format);
+ let marked_panic_message = mark_unexpected_substr(&panic_message, format);
format!(
- "expected {expression} to not panic, but did panic\n with message: {panic_message:?}"
+ "expected {expression} to not panic, but {marked_did_panic}\n with message: \"{marked_panic_message}\""
)
}
}
@@ -89,17 +97,29 @@ where
}
}
- fn message(&self, expression: Expression<'_>, _actual: &Code) -> String {
+ fn message(
+ &self,
+ expression: Expression<'_>,
+ _actual: &Code,
+ format: &DiffFormat,
+ ) -> String {
if let Some(actual_message) = self.actual_message.as_ref() {
if actual_message == ONLY_ONE_EXPECTATION {
format!("error in test assertion: {ONLY_ONE_EXPECTATION}")
} else if let Some(expected_message) = &self.expected_message {
- format!("expected {expression} to panic with message {expected_message:?}\n but was: {actual_message:?}\n expected: {expected_message:?}")
+ let marked_expected_message = mark_missing_substr(expected_message, format);
+ let marked_actual_message = mark_unexpected_substr(actual_message, format);
+ format!("expected {expression} to panic with message {expected_message:?}\n but was: \"{marked_actual_message}\"\n expected: \"{marked_expected_message}\"")
} else {
+ // should be unreachable
format!("expected {expression} to panic, but did not panic")
}
+ } else if let Some(expected_message) = &self.expected_message {
+ let marked_did_not_panic = mark_unexpected_substr("did not panic", format);
+ format!("expected {expression} to panic with message {expected_message:?},\n but {marked_did_not_panic}")
} else {
- format!("expected {expression} to panic, but did not panic")
+ let marked_did_not_panic = mark_unexpected_substr("did not panic", format);
+ format!("expected {expression} to panic, but {marked_did_not_panic}")
}
}
}
diff --git a/src/panic/tests.rs b/src/panic/tests.rs
index 1bf5a59..74cb43a 100644
--- a/src/panic/tests.rs
+++ b/src/panic/tests.rs
@@ -48,7 +48,9 @@ fn code_does_panic_with_message_from_assertion() {
}
assert_that_code(|| {
- assert_that(add(2, 3)).is_equal_to(4);
+ assert_that(add(2, 3))
+ .with_diff_format(DIFF_FORMAT_NO_HIGHLIGHT)
+ .is_equal_to(4);
})
.panics_with_message(
"assertion failed: expected subject is equal to 4\n but was: 5\n expected: 4\n",
@@ -93,8 +95,9 @@ fn verify_code_does_panic_with_message_fails_because_code_does_not_panic() {
assert_eq!(
failures,
&[
- r"assertion failed: expected my_closure to panic, but did not panic
-"
+ r#"assertion failed: expected my_closure to panic with message "nam veniam ut et",
+ but did not panic
+"#
]
);
}
@@ -102,7 +105,9 @@ fn verify_code_does_panic_with_message_fails_because_code_does_not_panic() {
#[test]
fn verify_code_does_panic_with_message_fails_because_unexpected_panic_message() {
let failures = verify_that_code(|| {
- assert_that(2 + 3).is_equal_to(4);
+ assert_that(2 + 3)
+ .with_diff_format(DIFF_FORMAT_NO_HIGHLIGHT)
+ .is_equal_to(4);
})
.named("my_closure")
.panics_with_message("lobortis lorem aliquam ex")
@@ -111,10 +116,10 @@ fn verify_code_does_panic_with_message_fails_because_unexpected_panic_message()
assert_eq!(
failures,
&[
- r#"assertion failed: expected my_closure to panic with message "lobortis lorem aliquam ex"
- but was: "assertion failed: expected subject is equal to 4\n but was: 5\n expected: 4\n"
- expected: "lobortis lorem aliquam ex"
-"#
+ "assertion failed: expected my_closure to panic with message \"lobortis lorem aliquam ex\"\n \
+ but was: \"assertion failed: expected subject is equal to 4\n but was: 5\n expected: 4\n\"\n \
+ expected: \"lobortis lorem aliquam ex\"\n\
+"
]
);
}
@@ -137,3 +142,79 @@ fn verify_can_not_perform_two_assertions_on_same_code_subject() {
]
);
}
+
+#[cfg(feature = "colored")]
+mod colored {
+ use crate::prelude::*;
+
+ fn foo(message: Option<&str>) {
+ if let Some(message) = message {
+ panic!("{message}");
+ }
+ }
+
+ #[test]
+ fn highlight_diffs_code_does_not_panic() {
+ let failures = verify_that_code(|| foo(Some("foo does not work with message")))
+ .named("foo")
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .does_not_panic()
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected foo to not panic, but \u{1b}[31mdid panic\u{1b}[0m\n \
+ with message: \"\u{1b}[31mfoo does not work with message\u{1b}[0m\"\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_code_does_panic() {
+ let failures = verify_that_code(|| foo(None))
+ .named("foo")
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .panics()
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected foo to panic, but \u{1b}[31mdid not panic\u{1b}[0m\n"]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_code_does_panic_with_message_but_does_not_panic() {
+ let failures = verify_that_code(|| foo(None))
+ .named("foo")
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .panics_with_message("hendrerit sint tempor ipsum")
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected foo to panic with message \"hendrerit sint tempor ipsum\",\n \
+ but \u{1b}[31mdid not panic\u{1b}[0m\n"]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_code_does_panic_with_message() {
+ let failures = verify_that_code(|| foo(Some("foo does not work with message")))
+ .named("foo")
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .panics_with_message("hendrerit sint tempor ipsum")
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected foo to panic with message \"hendrerit sint tempor ipsum\"\n \
+ but was: \"\u{1b}[31mfoo does not work with message\u{1b}[0m\"\n \
+ expected: \"\u{1b}[32mhendrerit sint tempor ipsum\u{1b}[0m\"\n\
+ "
+ ]
+ );
+ }
+}
diff --git a/src/predicate/mod.rs b/src/predicate/mod.rs
index e1d072b..a87f68a 100644
--- a/src/predicate/mod.rs
+++ b/src/predicate/mod.rs
@@ -1,7 +1,7 @@
//! Implementation of the predicate assertion.
use crate::expectations::Predicate;
-use crate::spec::{Expectation, Expression};
+use crate::spec::{DiffFormat, Expectation, Expression};
use crate::std::{format, string::String};
impl Expectation for Predicate
@@ -12,7 +12,7 @@ where
(self.predicate)(subject)
}
- fn message(&self, expression: Expression<'_>, _actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, _actual: &S, _format: &DiffFormat) -> String {
self.message.clone().unwrap_or_else(|| {
format!("expected {expression} to satisfy the given predicate, but returned false")
})
diff --git a/src/prelude.rs b/src/prelude.rs
index c8b9f67..11d9b71 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -17,11 +17,17 @@
pub use super::{
assert_that,
assertions::*,
+ colored::{DEFAULT_DIFF_FORMAT, DIFF_FORMAT_NO_HIGHLIGHT},
properties::*,
spec::{assert_that, verify_that, CollectFailures, Location, PanicOnFail},
verify_that,
};
+#[cfg(feature = "colored")]
+pub use super::colored::{
+ DIFF_FORMAT_BOLD, DIFF_FORMAT_RED_BLUE, DIFF_FORMAT_RED_GREEN, DIFF_FORMAT_RED_YELLOW,
+};
+
#[cfg(feature = "panic")]
pub use super::{
assert_that_code,
diff --git a/src/range/mod.rs b/src/range/mod.rs
index 5f2cb49..013c7a1 100644
--- a/src/range/mod.rs
+++ b/src/range/mod.rs
@@ -1,9 +1,10 @@
//! Implementation of assertions for `Range` and `RangeInclusive` values.
use crate::assertions::AssertInRange;
+use crate::colored::{mark_missing, mark_unexpected};
use crate::expectations::{IsInRange, IsNotInRange};
use crate::properties::IsEmptyProperty;
-use crate::spec::{Expectation, Expression, FailingStrategy, Spec};
+use crate::spec::{DiffFormat, Expectation, Expression, FailingStrategy, Spec};
use crate::std::fmt::Debug;
use crate::std::ops::{Range, RangeBounds, RangeInclusive};
use crate::std::{format, string::String};
@@ -54,12 +55,21 @@ where
self.expected_range.contains(subject)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected_start = if actual < self.expected_range.start() {
+ mark_missing(self.expected_range.start(), format)
+ } else {
+ format!("{:?}", self.expected_range.start())
+ };
+ let marked_expected_end = if actual > self.expected_range.end() {
+ mark_missing(self.expected_range.end(), format)
+ } else {
+ format!("{:?}", self.expected_range.end())
+ };
format!(
- "expected {expression} is within range of {:?}\n but was: {actual:?}\n expected: {:?} <= x <= {:?}",
+ "expected {expression} is within range of {:?}\n but was: {marked_actual}\n expected: {marked_expected_start} <= x <= {marked_expected_end}",
self.expected_range,
- self.expected_range.start(),
- self.expected_range.end(),
)
}
}
@@ -73,12 +83,13 @@ where
!self.expected_range.contains(subject)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected_start = mark_missing(self.expected_range.start(), format);
+ let marked_expected_end = mark_missing(self.expected_range.end(), format);
format!(
- "expected {expression} is not within range of {:?}\n but was: {actual:?}\n expected: x < {:?} || x > {:?}",
+ "expected {expression} is not within range of {:?}\n but was: {marked_actual}\n expected: x < {marked_expected_start} || x > {marked_expected_end}",
self.expected_range,
- self.expected_range.start(),
- self.expected_range.end(),
)
}
}
diff --git a/src/range/tests.rs b/src/range/tests.rs
index 75880d0..1315d6a 100644
--- a/src/range/tests.rs
+++ b/src/range/tests.rs
@@ -148,3 +148,68 @@ fn inclusive_range_is_not_empty() {
assert_that(range.clone().count()).is_equal_to(1);
assert_that(range).is_not_empty();
}
+
+#[cfg(feature = "colored")]
+mod colored {
+ use crate::prelude::*;
+
+ #[test]
+ fn highlight_diffs_i64_is_in_range_above_upper_bound() {
+ let subject = 29_834;
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .is_in_range(-4321..=4321)
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject is within range of -4321..=4321\n \
+ but was: \u{1b}[31m29834\u{1b}[0m\n \
+ expected: -4321 <= x <= \u{1b}[34m4321\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_i64_is_in_range_below_lower_bound() {
+ let subject = -29_834;
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .is_in_range(-4321..=4321)
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject is within range of -4321..=4321\n \
+ but was: \u{1b}[31m-29834\u{1b}[0m\n \
+ expected: \u{1b}[34m-4321\u{1b}[0m <= x <= 4321\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_char_is_not_in_range() {
+ let subject = 'm';
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .is_not_in_range('a'..='z')
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject is not within range of 'a'..='z'\n \
+ but was: \u{1b}[31m'm'\u{1b}[0m\n \
+ expected: x < \u{1b}[32m'a'\u{1b}[0m || x > \u{1b}[32m'z'\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+}
diff --git a/src/result/mod.rs b/src/result/mod.rs
index 342ea73..875a555 100644
--- a/src/result/mod.rs
+++ b/src/result/mod.rs
@@ -1,9 +1,11 @@
//! Implementation of assertions for `Result` values.
-use crate::assertions::{AssertHasErrorMessage, AssertResult, AssertResultValue};
+use crate::assertions::{
+ AssertHasError, AssertHasErrorMessage, AssertHasValue, AssertResult, AssertResultValue,
+};
+use crate::colored::{mark_missing, mark_unexpected};
use crate::expectations::{HasError, HasValue, IsEqualTo, IsErr, IsOk};
-use crate::prelude::{AssertHasError, AssertHasValue};
-use crate::spec::{Expectation, Expression, FailingStrategy, Spec, Unknown};
+use crate::spec::{DiffFormat, Expectation, Expression, FailingStrategy, Spec, Unknown};
use crate::std::fmt::{Debug, Display};
use crate::std::{
format,
@@ -102,11 +104,17 @@ where
subject.is_ok()
}
- fn message(&self, expression: Expression<'_>, actual: &Result) -> String {
+ fn message(
+ &self,
+ expression: Expression<'_>,
+ actual: &Result,
+ format: &DiffFormat,
+ ) -> String {
+ let expected = Ok::<_, Unknown>(Unknown);
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&expected, format);
format!(
- "expected {expression} is {:?}\n but was: {actual:?}\n expected: {:?}",
- Ok::<_, Unknown>(Unknown),
- Ok::<_, Unknown>(Unknown),
+ "expected {expression} is {expected:?}\n but was: {marked_actual}\n expected: {marked_expected}"
)
}
}
@@ -120,11 +128,17 @@ where
subject.is_err()
}
- fn message(&self, expression: Expression<'_>, actual: &Result) -> String {
+ fn message(
+ &self,
+ expression: Expression<'_>,
+ actual: &Result,
+ format: &DiffFormat,
+ ) -> String {
+ let expected = Err::(Unknown);
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&expected, format);
format!(
- "expected {expression} is {:?}\n but was: {actual:?}\n expected: {:?}",
- Err::(Unknown),
- Err::(Unknown),
+ "expected {expression} is {expected:?}\n but was: {marked_actual}\n expected: {marked_expected}"
)
}
}
@@ -139,11 +153,17 @@ where
subject.as_ref().is_ok_and(|value| value == &self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &Result) -> String {
+ fn message(
+ &self,
+ expression: Expression<'_>,
+ actual: &Result,
+ format: &DiffFormat,
+ ) -> String {
+ let expected = &self.expected;
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&Ok::<_, E>(expected), format);
format!(
- "expected {expression} is ok containing {:?}\n but was: {actual:?}\n expected: {:?}",
- &self.expected,
- Ok::<_, E>(&self.expected),
+ "expected {expression} is ok containing {expected:?}\n but was: {marked_actual}\n expected: {marked_expected}"
)
}
}
@@ -158,11 +178,17 @@ where
subject.as_ref().is_err_and(|err| err == &self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &Result) -> String {
+ fn message(
+ &self,
+ expression: Expression<'_>,
+ actual: &Result,
+ format: &DiffFormat,
+ ) -> String {
+ let expected = &self.expected;
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&Err::(expected), format);
format!(
- "expected {expression} is error containing {:?}\n but was: {actual:?}\n expected: {:?}",
- &self.expected,
- Err::(&self.expected),
+ "expected {expression} is error containing {expected:?}\n but was: {marked_actual}\n expected: {marked_expected}"
)
}
}
diff --git a/src/result/tests.rs b/src/result/tests.rs
index e487ec8..a7efeee 100644
--- a/src/result/tests.rs
+++ b/src/result/tests.rs
@@ -230,3 +230,89 @@ fn verify_result_error_has_message_for_ok_value() {
r#"assertion failed: expected the subject to be `Err(_)` with message "vulputate voluptate sanctus quod", but was `Ok(())`"#,
);
}
+
+#[cfg(feature = "colored")]
+mod colored {
+ use crate::prelude::*;
+ use crate::std::{
+ string::{String, ToString},
+ vec,
+ vec::Vec,
+ };
+
+ #[test]
+ fn highlight_diffs_result_of_i64_is_ok() {
+ let subject: Result = Err("esse augue id esse".to_string());
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .is_ok()
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject is Ok(_)\n \
+ but was: \u{1b}[31mErr(\"esse augue id esse\")\u{1b}[0m\n \
+ expected: \u{1b}[34mOk(_)\u{1b}[0m\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_result_of_i64_is_err() {
+ let subject: Result = Ok(3500);
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .is_err()
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject is Err(_)\n \
+ but was: \u{1b}[31mOk(3500)\u{1b}[0m\n \
+ expected: \u{1b}[32mErr(_)\u{1b}[0m\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_option_of_vec_of_i32_has_value_but_is_err() {
+ let subject: Result, String> = Err("minim facer liber kasd".to_string());
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .has_value(vec![1, 2, 3, 5, 7])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject is ok containing [1, 2, 3, 5, 7]\n \
+ but was: \u{1b}[31mErr(\"minim facer liber kasd\")\u{1b}[0m\n \
+ expected: \u{1b}[33mOk([1, 2, 3, 5, 7])\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_option_of_vec_of_i32_has_error_but_is_ok() {
+ let subject: Result, String> = Ok(vec![1, 2, 3, 5, 7]);
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .has_error("at feugait nihil qui")
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject is error containing \"at feugait nihil qui\"\n \
+ but was: \u{1b}[31mOk([1, 2, 3, 5, 7])\u{1b}[0m\n \
+ expected: \u{1b}[33mErr(\"at feugait nihil qui\")\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+}
diff --git a/src/slice/mod.rs b/src/slice/mod.rs
index 3dd7f43..bbf0e90 100644
--- a/src/slice/mod.rs
+++ b/src/slice/mod.rs
@@ -1,6 +1,6 @@
//! Implementation of assertions for `slice` values.
-use crate::prelude::{IsEmptyProperty, LengthProperty};
+use crate::properties::{IsEmptyProperty, LengthProperty};
impl IsEmptyProperty for &[T] {
fn is_empty_property(&self) -> bool {
diff --git a/src/slice/tests.rs b/src/slice/tests.rs
index 829c184..770b37b 100644
--- a/src/slice/tests.rs
+++ b/src/slice/tests.rs
@@ -174,7 +174,7 @@ fn verify_slice_contains_any_of_fails() {
assert_eq!(
failures,
&[
- r"assertion failed: expected my_thing contains any of [0, 2, 4, 8, 16, 32, 64], but contained none of them
+ r"assertion failed: expected my_thing contains any of [0, 2, 4, 8, 16, 32, 64]
but was: [5, 7, 11, 13, 1, 11, 3, 17, 23, 23, 29, 31, 41, 37, 43]
expected: [0, 2, 4, 8, 16, 32, 64]
"
@@ -247,7 +247,7 @@ fn slice_contains_only_once() {
#[test]
fn verify_slice_contains_only_once_fails() {
- let subject: &[i32] = &[5, 11, 1, 3, 19, 17, 11, 43];
+ let subject: &[i32] = &[5, 11, 1, 3, 3, 19, 17, 11, 3, 43];
let failures = verify_that(subject)
.named("my_thing")
@@ -258,10 +258,10 @@ fn verify_slice_contains_only_once_fails() {
failures,
&[
r"assertion failed: expected my_thing contains only once [1, 3, 7, 11, 19]
- but was: [5, 11, 1, 3, 19, 17, 11, 43]
+ but was: [5, 11, 1, 3, 3, 19, 17, 11, 3, 43]
expected: [1, 3, 7, 11, 19]
extra: [5, 17, 43]
- duplicates: [11, 11]
+ duplicates: [11, 3, 3, 11, 3]
"
]
);
@@ -456,10 +456,10 @@ fn verify_slice_contains_sequence_fails() {
failures,
&[
r#"assertion failed: expected my_thing contains sequence ["two", "three", "four", "five", "six", "six", "four"]
- but was: ["one", "two", "two", "three", "four", "five", "six", "four", "two", "seven", "two", "three", "five", "four", "six", "four", "eight", "nine", "ten"]
- expected: ["two", "three", "four", "five", "six", "six", "four"]
- missing: ["six", "four"]
- extra: ["four", "two"]
+ but was: ["one", "two", "two", "three", "four", "five", "six", "four", "two", "seven", "two", "three", "five", "four", "six", "four", "eight", "nine", "ten"]
+ expected: ["two", "three", "four", "five", "six", "six", "four"]
+ missing: ["six", "four"]
+ extra: ["four", "two"]
"#
]
);
@@ -485,10 +485,10 @@ fn verify_slice_contains_sequence_fails_expected_longer_than_vec() {
failures,
&[
r#"assertion failed: expected my_thing contains sequence ["one", "two", "three", "four", "five", "six", "seven"]
- but was: ["one", "two", "three", "four", "five", "six"]
- expected: ["one", "two", "three", "four", "five", "six", "seven"]
- missing: ["seven"]
- extra: []
+ but was: ["one", "two", "three", "four", "five", "six"]
+ expected: ["one", "two", "three", "four", "five", "six", "seven"]
+ missing: ["seven"]
+ extra: []
"#
]
);
@@ -550,9 +550,9 @@ fn verify_slice_contains_all_in_order_fails() {
failures,
&[
r#"assertion failed: expected my_thing contains all of ["one", "two", "two", "seven", "two", "three", "six", "six", "ten"] in order
- but was: ["one", "two", "two", "three", "four", "five", "six", "four", "two", "seven", "two", "three", "five", "four", "six", "four", "eight", "nine", "ten"]
- expected: ["one", "two", "two", "seven", "two", "three", "six", "six", "ten"]
- missing: ["six"]
+ but was: ["one", "two", "two", "three", "four", "five", "six", "four", "two", "seven", "two", "three", "five", "four", "six", "four", "eight", "nine", "ten"]
+ expected: ["one", "two", "two", "seven", "two", "three", "six", "six", "ten"]
+ missing: ["six"]
"#
]
);
@@ -701,3 +701,227 @@ fn verify_empty_vec_ends_with_expected_sequence_longer_than_vec_fails() {
]
);
}
+
+#[cfg(feature = "colored")]
+mod colored {
+ use super::*;
+
+ #[test]
+ fn highlight_diffs_slice_contains() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .contains(&21)
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject to contain 21\n \
+ but was: [\u{1b}[31m13\u{1b}[0m, \u{1b}[31m5\u{1b}[0m, \u{1b}[31m7\u{1b}[0m, \u{1b}[31m19\u{1b}[0m, \u{1b}[31m1\u{1b}[0m, \u{1b}[31m3\u{1b}[0m, \u{1b}[31m11\u{1b}[0m, \u{1b}[31m29\u{1b}[0m, \u{1b}[31m23\u{1b}[0m, \u{1b}[31m31\u{1b}[0m, \u{1b}[31m37\u{1b}[0m]\n \
+ expected: \u{1b}[32m21\u{1b}[0m\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_slice_contains_exactly_in_any_order() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .contains_exactly_in_any_order(&[1, 2, 3, 13, 8, 7, 12, 15, 31, 19, 20, 11, 31])
+ .display_failures();
+
+ assert_eq!(failures, &[
+ "assertion failed: expected subject contains exactly in any order [1, 2, 3, 13, 8, 7, 12, 15, 31, 19, 20, 11, 31]\n \
+ but was: [13, \u{1b}[31m5\u{1b}[0m, 7, 19, 1, 3, 11, \u{1b}[31m29\u{1b}[0m, \u{1b}[31m23\u{1b}[0m, 31, \u{1b}[31m37\u{1b}[0m]\n \
+ expected: [1, \u{1b}[34m2\u{1b}[0m, 3, 13, \u{1b}[34m8\u{1b}[0m, 7, \u{1b}[34m12\u{1b}[0m, \u{1b}[34m15\u{1b}[0m, 31, 19, \u{1b}[34m20\u{1b}[0m, 11, \u{1b}[34m31\u{1b}[0m]\n \
+ missing: [2, 8, 12, 15, 20, 31]\n \
+ extra: [5, 29, 23, 37]\n\
+ "
+ ]);
+ }
+
+ #[test]
+ fn highlight_diffs_slice_contains_any_of() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .contains_any_of(&[2, 4, 6, 8, 9, 10, 12, 15, 32, 20, 18])
+ .display_failures();
+
+ assert_eq!(failures, &[
+ "assertion failed: expected subject contains any of [2, 4, 6, 8, 9, 10, 12, 15, 32, 20, 18]\n \
+ but was: [\u{1b}[31m13\u{1b}[0m, \u{1b}[31m5\u{1b}[0m, \u{1b}[31m7\u{1b}[0m, \u{1b}[31m19\u{1b}[0m, \u{1b}[31m1\u{1b}[0m, \u{1b}[31m3\u{1b}[0m, \u{1b}[31m11\u{1b}[0m, \u{1b}[31m29\u{1b}[0m, \u{1b}[31m23\u{1b}[0m, \u{1b}[31m31\u{1b}[0m, \u{1b}[31m37\u{1b}[0m]\n \
+ expected: [\u{1b}[34m2\u{1b}[0m, \u{1b}[34m4\u{1b}[0m, \u{1b}[34m6\u{1b}[0m, \u{1b}[34m8\u{1b}[0m, \u{1b}[34m9\u{1b}[0m, \u{1b}[34m10\u{1b}[0m, \u{1b}[34m12\u{1b}[0m, \u{1b}[34m15\u{1b}[0m, \u{1b}[34m32\u{1b}[0m, \u{1b}[34m20\u{1b}[0m, \u{1b}[34m18\u{1b}[0m]\n\
+ "
+ ]);
+ }
+
+ #[test]
+ fn highlight_diffs_slice_contains_all_of() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .contains_all_of(&[2, 3, 5, 20, 11, 13, 19, 37, 22])
+ .display_failures();
+
+ assert_eq!(failures, &[
+ "assertion failed: expected subject contains all of [2, 3, 5, 20, 11, 13, 19, 37, 22]\n \
+ but was: [13, 5, \u{1b}[31m7\u{1b}[0m, 19, \u{1b}[31m1\u{1b}[0m, 3, 11, \u{1b}[31m29\u{1b}[0m, \u{1b}[31m23\u{1b}[0m, \u{1b}[31m31\u{1b}[0m, 37]\n \
+ expected: [\u{1b}[34m2\u{1b}[0m, 3, 5, \u{1b}[34m20\u{1b}[0m, 11, 13, 19, 37, \u{1b}[34m22\u{1b}[0m]\n \
+ missing: [2, 20, 22]\n\
+ "
+ ]);
+ }
+
+ #[test]
+ fn highlight_diffs_slice_contains_only() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .contains_only(&[13, 3, 5, 20, 11, 13, 19, 37, 22])
+ .display_failures();
+
+ assert_eq!(failures, &[
+ "assertion failed: expected subject contains only [13, 3, 5, 20, 11, 13, 19, 37, 22]\n \
+ but was: [13, 5, \u{1b}[31m7\u{1b}[0m, 19, \u{1b}[31m1\u{1b}[0m, 3, 11, \u{1b}[31m29\u{1b}[0m, \u{1b}[31m23\u{1b}[0m, \u{1b}[31m31\u{1b}[0m, 37]\n \
+ expected: [13, 3, 5, \u{1b}[34m20\u{1b}[0m, 11, 13, 19, 37, \u{1b}[34m22\u{1b}[0m]\n \
+ extra: [7, 1, 29, 23, 31]\n\
+ "
+ ]);
+ }
+
+ #[test]
+ fn highlight_diffs_slice_contains_only_once() {
+ let subject: &[i32] = &[5, 11, 1, 3, 3, 19, 17, 11, 3, 43];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .contains_only_once(&[1, 3, 7, 11, 19])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject contains only once [1, 3, 7, 11, 19]\n \
+ but was: [\u{1b}[31m5\u{1b}[0m, \u{1b}[31m11\u{1b}[0m, 1, \u{1b}[31m3\u{1b}[0m, \u{1b}[31m3\u{1b}[0m, 19, \u{1b}[31m17\u{1b}[0m, \u{1b}[31m11\u{1b}[0m, \u{1b}[31m3\u{1b}[0m, \u{1b}[31m43\u{1b}[0m]\n \
+ expected: [1, \u{1b}[34m3\u{1b}[0m, \u{1b}[34m7\u{1b}[0m, \u{1b}[34m11\u{1b}[0m, 19]\n \
+ extra: [5, 17, 43]\n \
+ duplicates: [11, 3, 3, 11, 3]\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_slice_contains_exactly() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .contains_exactly(&[13, 20, 5, 19, 11, 29, 8, 1, 23, 31, 41])
+ .display_failures();
+
+ assert_eq!(failures, &[
+ "assertion failed: expected subject contains exactly in order [13, 20, 5, 19, 11, 29, 8, 1, 23, 31, 41]\n \
+ but was: [13, \u{1b}[31m5\u{1b}[0m, \u{1b}[31m7\u{1b}[0m, 19, \u{1b}[31m1\u{1b}[0m, \u{1b}[31m3\u{1b}[0m, \u{1b}[31m11\u{1b}[0m, \u{1b}[31m29\u{1b}[0m, 23, 31, \u{1b}[31m37\u{1b}[0m]\n \
+ expected: [13, \u{1b}[33m20\u{1b}[0m, \u{1b}[33m5\u{1b}[0m, 19, \u{1b}[33m11\u{1b}[0m, \u{1b}[33m29\u{1b}[0m, \u{1b}[33m8\u{1b}[0m, \u{1b}[33m1\u{1b}[0m, 23, 31, \u{1b}[33m41\u{1b}[0m]\n \
+ missing: [20, 8, 41]\n \
+ extra: [7, 3, 37]\n \
+ out-of-order: [5, 1, 11, 29]\n\
+ "
+ ]);
+ }
+
+ #[test]
+ fn highlight_diffs_slice_contains_sequence() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .contains_sequence(&[19, 3, 7, 11, 29])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject contains sequence [19, 3, 7, 11, 29]\n \
+ but was: [13, 5, 7, 19, \u{1b}[31m1\u{1b}[0m, \u{1b}[31m3\u{1b}[0m, 11, 29, 23, 31, 37]\n \
+ expected: [19, \u{1b}[33m3\u{1b}[0m, \u{1b}[33m7\u{1b}[0m, 11, 29]\n \
+ missing: [3, 7]\n \
+ extra: [1, 3]\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_slice_contains_all_in_order() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .contains_all_in_order(&[13, 3, 7, 22, 11, 20, 29, 37])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject contains all of [13, 3, 7, 22, 11, 20, 29, 37] in order\n \
+ but was: [13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37]\n \
+ expected: [13, 3, \u{1b}[33m7\u{1b}[0m, \u{1b}[33m22\u{1b}[0m, 11, \u{1b}[33m20\u{1b}[0m, 29, 37]\n \
+ missing: [7, 22, 20]\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_slice_starts_with() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .starts_with(&[13, 5, 8, 19, 4])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject starts with [13, 5, 8, 19, 4]\n \
+ but was: [13, 5, \u{1b}[31m7\u{1b}[0m, 19, \u{1b}[31m1\u{1b}[0m, 3, 11, 29, 23, 31, 37]\n \
+ expected: [13, 5, \u{1b}[33m8\u{1b}[0m, 19, \u{1b}[33m4\u{1b}[0m]\n \
+ missing: [8, 4]\n \
+ extra: [7, 1]\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_slice_ends_with() {
+ let subject: &[i64] = &[13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .ends_with(&[3, 11, 28, 29, 30, 37])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject ends with [3, 11, 28, 29, 30, 37]\n \
+ but was: [13, 5, 7, 19, 1, 3, 11, \u{1b}[31m29\u{1b}[0m, \u{1b}[31m23\u{1b}[0m, \u{1b}[31m31\u{1b}[0m, 37]\n \
+ expected: [3, 11, \u{1b}[33m28\u{1b}[0m, \u{1b}[33m29\u{1b}[0m, \u{1b}[33m30\u{1b}[0m, 37]\n \
+ missing: [28, 29, 30]\n \
+ extra: [29, 23, 31]\n\
+ "
+ ]
+ );
+ }
+}
diff --git a/src/spec/mod.rs b/src/spec/mod.rs
index bae9f53..1106332 100644
--- a/src/spec/mod.rs
+++ b/src/spec/mod.rs
@@ -1,5 +1,6 @@
//! This is the core of the `asserting` crate.
+use crate::colored;
use crate::expectations::Predicate;
use crate::std::error::Error as StdError;
use crate::std::fmt::{self, Debug, Display};
@@ -10,6 +11,8 @@ use crate::std::{
vec,
vec::Vec,
};
+#[cfg(feature = "panic")]
+use crate::std::{cell::RefCell, rc::Rc};
/// Starts an assertion for the given subject or expression in the
/// [`PanicOnFail`] mode.
@@ -236,7 +239,15 @@ macro_rules! verify_that_code {
/// ```
#[track_caller]
pub fn assert_that<'a, S>(subject: S) -> Spec<'a, S, PanicOnFail> {
- Spec::new(subject, PanicOnFail)
+ #[cfg(not(feature = "colored"))]
+ {
+ Spec::new(subject, PanicOnFail)
+ }
+ #[cfg(feature = "colored")]
+ {
+ use crate::colored::configured_diff_format;
+ Spec::new(subject, PanicOnFail).with_diff_format(configured_diff_format())
+ }
}
/// Starts an assertion for the given subject or expression in the
@@ -406,7 +417,7 @@ pub trait Expectation {
fn test(&mut self, subject: &S) -> bool;
/// Forms a failure message for this expectation.
- fn message(&self, expression: Expression<'_>, actual: &S) -> String;
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String;
}
/// A textual representation of the expression or subject that is being
@@ -570,24 +581,11 @@ pub struct Spec<'a, S, R> {
description: Option<&'a str>,
location: Option>,
failures: Vec,
+ diff_format: DiffFormat,
failing_strategy: R,
}
impl Spec<'_, S, R> {
- /// Constructs a new `Spec` for the given subject and with the specified
- /// failing strategy.
- #[must_use = "a spec does nothing unless an assertion method is called"]
- pub const fn new(subject: S, failing_strategy: R) -> Self {
- Self {
- subject,
- expression: None,
- description: None,
- location: None,
- failures: vec![],
- failing_strategy,
- }
- }
-
/// Returns the subject.
pub fn subject(&self) -> &S {
&self.subject
@@ -608,6 +606,11 @@ impl Spec<'_, S, R> {
self.description
}
+ /// Returns the diff format used with this assertion.
+ pub const fn diff_format(&self) -> &DiffFormat {
+ &self.diff_format
+ }
+
/// Returns the failing strategy that is used in case an assertion fails.
pub fn failing_strategy(&self) -> &R {
&self.failing_strategy
@@ -625,6 +628,24 @@ impl Spec<'_, S, R> {
}
impl<'a, S, R> Spec<'a, S, R> {
+ /// Constructs a new `Spec` for the given subject and with the specified
+ /// failing strategy.
+ ///
+ /// The diff format is set to "no highlighting". Failure messages will not
+ /// highlight differences between the actual and the expected value.
+ #[must_use = "a spec does nothing unless an assertion method is called"]
+ pub const fn new(subject: S, failing_strategy: R) -> Self {
+ Self {
+ subject,
+ expression: None,
+ description: None,
+ location: None,
+ failures: vec![],
+ diff_format: colored::DIFF_FORMAT_NO_HIGHLIGHT,
+ failing_strategy,
+ }
+ }
+
/// Sets the subject name or expression for this assertion.
#[must_use = "a spec does nothing unless an assertion method is called"]
pub const fn named(mut self, subject_name: &'a str) -> Self {
@@ -647,6 +668,18 @@ impl<'a, S, R> Spec<'a, S, R> {
self
}
+ /// Sets the diff format that is used to highlight differences between
+ /// the actual value and the expected value.
+ ///
+ /// Note: This method must be called before an assertion method is called to
+ /// have an effect on the failure message of the assertion as failure
+ /// messages are formatted immediately when an assertion is executed.
+ #[must_use = "a spec does nothing unless an assertion method is called"]
+ pub const fn with_diff_format(mut self, diff_format: DiffFormat) -> Self {
+ self.diff_format = diff_format;
+ self
+ }
+
/// Maps the current subject to some other value.
///
/// It takes a closure that maps the current subject to a new subject and
@@ -736,6 +769,7 @@ impl<'a, S, R> Spec<'a, S, R> {
description: self.description,
location: self.location,
failures: self.failures,
+ diff_format: self.diff_format,
failing_strategy: self.failing_strategy,
}
}
@@ -769,7 +803,7 @@ where
pub fn expecting(mut self, mut expectation: impl Expectation) -> Self {
if !expectation.test(&self.subject) {
let expression = self.expression.unwrap_or_default();
- let message = expectation.message(expression, &self.subject);
+ let message = expectation.message(expression, &self.subject, &self.diff_format);
self.do_fail_with_message(message);
}
self
@@ -924,6 +958,21 @@ impl AssertFailure {
}
}
+/// Start and end tag that marks a highlighted part of a string.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct Highlight {
+ pub(crate) start: &'static str,
+ pub(crate) end: &'static str,
+}
+
+/// Definition of format properties for highlighting differences between two
+/// values.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct DiffFormat {
+ pub(crate) unexpected: Highlight,
+ pub(crate) missing: Highlight,
+}
+
/// Defines the behavior when an assertion fails.
///
/// This crate provides two implementations:
@@ -991,9 +1040,7 @@ impl FailingStrategy for CollectFailures {
///
/// ```no_run
/// # use std::fmt::Debug;
-/// # use asserting::spec::Expectation;
-/// # use asserting::spec::Expression;
-/// # use asserting::spec::Unknown;
+/// # use asserting::spec::{DiffFormat, Expectation, Expression, Unknown};
/// # struct IsOk;
/// impl Expectation> for IsOk
/// where
@@ -1004,7 +1051,7 @@ impl FailingStrategy for CollectFailures {
/// subject.is_ok()
/// }
///
-/// fn message(&self, expression: Expression<'_>, actual: &Result) -> String {
+/// fn message(&self, expression: Expression<'_>, actual: &Result, _format: &DiffFormat) -> String {
/// format!(
/// "expected {expression} is {:?}\n but was: {actual:?}\n expected: {:?}",
/// Ok::<_, Unknown>(Unknown),
@@ -1028,17 +1075,16 @@ impl Display for Unknown {
}
}
+/// Wrapper type that holds a closure as code snippet.
#[cfg(feature = "panic")]
-pub use code::Code;
+pub struct Code(Rc>>);
#[cfg(feature = "panic")]
mod code {
+ use super::Code;
use std::cell::RefCell;
use std::rc::Rc;
- /// Wrapper type that holds a closure as code snippet.
- pub struct Code(Rc>>);
-
impl From for Code
where
F: FnOnce(),
diff --git a/src/spec/tests.rs b/src/spec/tests.rs
index b9b13bb..1010f1d 100644
--- a/src/spec/tests.rs
+++ b/src/spec/tests.rs
@@ -57,7 +57,9 @@ fn assert_that_macro_with_borrowed_str_subject() {
fn assert_that_macro_is_equal_to_with_integers_fails() {
let ultimate_answer = 51;
- assert_that!(ultimate_answer).is_equal_to(42);
+ assert_that!(ultimate_answer)
+ .with_diff_format(DIFF_FORMAT_NO_HIGHLIGHT)
+ .is_equal_to(42);
}
#[test]
diff --git a/src/string/mod.rs b/src/string/mod.rs
index ae6024e..3ef2ee0 100644
--- a/src/string/mod.rs
+++ b/src/string/mod.rs
@@ -7,13 +7,18 @@
//! * `CString` and `CStr`
use crate::assertions::{AssertStringContainsAnyOf, AssertStringPattern};
+use crate::colored::{
+ mark_missing, mark_missing_char, mark_missing_substr, mark_unexpected, mark_unexpected_substr,
+};
use crate::expectations::{StringContains, StringContainsAnyOf, StringEndsWith, StringStartWith};
-use crate::prelude::DefinedOrderProperty;
-use crate::properties::{IsEmptyProperty, LengthProperty};
-use crate::spec::{Expectation, Expression, FailingStrategy, Spec};
+use crate::properties::{DefinedOrderProperty, IsEmptyProperty, LengthProperty};
+use crate::spec::{DiffFormat, Expectation, Expression, FailingStrategy, Spec};
use crate::std::fmt::Debug;
use crate::std::str::Chars;
-use crate::std::{format, string::String};
+use crate::std::{
+ format,
+ string::{String, ToString},
+};
impl IsEmptyProperty for &str {
fn is_empty_property(&self) -> bool {
@@ -156,10 +161,12 @@ where
subject.as_ref().contains(self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected_substr(actual.as_ref(), format);
+ let marked_expected = mark_missing_substr(self.expected, format);
format!(
- "expected {expression} to contain {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to contain {:?}\n but was: \"{marked_actual}\"\n expected: \"{marked_expected}\"",
+ self.expected,
)
}
}
@@ -172,10 +179,12 @@ where
subject.as_ref().contains(&self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected_substr(actual.as_ref(), format);
+ let marked_expected = mark_missing_substr(self.expected.as_ref(), format);
format!(
- "expected {expression} to contain {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to contain {:?}\n but was: \"{marked_actual}\"\n expected: \"{marked_expected}\"",
+ self.expected,
)
}
}
@@ -188,10 +197,12 @@ where
subject.as_ref().contains(self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected_substr(actual.as_ref(), format);
+ let marked_expected = mark_missing_char(self.expected, format);
format!(
- "expected {expression} to contain {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to contain {:?}\n but was: \"{marked_actual}\"\n expected: '{marked_expected}'",
+ self.expected,
)
}
}
@@ -204,10 +215,23 @@ where
subject.as_ref().starts_with(self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let expected_char_len = self.expected.chars().count();
+ let actual_start = actual
+ .as_ref()
+ .chars()
+ .take(expected_char_len)
+ .collect::();
+ let actual_rest = actual
+ .as_ref()
+ .chars()
+ .skip(expected_char_len)
+ .collect::();
+ let marked_actual_start = mark_unexpected_substr(&actual_start, format);
+ let marked_expected = mark_missing_substr(self.expected, format);
format!(
- "expected {expression} to start with {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to start with {:?}\n but was: \"{marked_actual_start}{actual_rest}\"\n expected: \"{marked_expected}\"",
+ self.expected,
)
}
}
@@ -220,10 +244,23 @@ where
subject.as_ref().starts_with(&self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let expected_char_len = self.expected.chars().count();
+ let actual_start = actual
+ .as_ref()
+ .chars()
+ .take(expected_char_len)
+ .collect::();
+ let actual_rest = actual
+ .as_ref()
+ .chars()
+ .skip(expected_char_len)
+ .collect::();
+ let marked_actual_start = mark_unexpected_substr(&actual_start, format);
+ let marked_expected = mark_missing_substr(&self.expected, format);
format!(
- "expected {expression} to start with {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to start with {:?}\n but was: \"{marked_actual_start}{actual_rest}\"\n expected: \"{marked_expected}\"",
+ self.expected,
)
}
}
@@ -236,10 +273,14 @@ where
subject.as_ref().starts_with(self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let actual_first_char = actual.as_ref().chars().take(1).collect::();
+ let actual_rest = actual.as_ref().chars().skip(1).collect::();
+ let marked_actual_start = mark_unexpected_substr(&actual_first_char, format);
+ let marked_expected = mark_missing_char(self.expected, format);
format!(
- "expected {expression} to start with {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to start with {:?}\n but was: \"{marked_actual_start}{actual_rest}\"\n expected: '{marked_expected}'",
+ self.expected,
)
}
}
@@ -252,10 +293,25 @@ where
subject.as_ref().ends_with(self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let actual_char_len = actual.as_ref().chars().count();
+ let expected_char_len = self.expected.chars().count();
+ let split_point = actual_char_len.saturating_sub(expected_char_len);
+ let actual_start = actual
+ .as_ref()
+ .chars()
+ .take(split_point)
+ .collect::();
+ let actual_end = actual
+ .as_ref()
+ .chars()
+ .skip(split_point)
+ .collect::();
+ let marked_actual_end = mark_unexpected_substr(&actual_end, format);
+ let marked_expected = mark_missing_substr(self.expected, format);
format!(
- "expected {expression} to end with {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to end with {:?}\n but was: \"{actual_start}{marked_actual_end}\"\n expected: \"{marked_expected}\"",
+ self.expected,
)
}
}
@@ -268,10 +324,25 @@ where
subject.as_ref().ends_with(&self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let actual_char_len = actual.as_ref().chars().count();
+ let expected_char_len = self.expected.chars().count();
+ let split_point = actual_char_len.saturating_sub(expected_char_len);
+ let actual_start = actual
+ .as_ref()
+ .chars()
+ .take(split_point)
+ .collect::();
+ let actual_end = actual
+ .as_ref()
+ .chars()
+ .skip(split_point)
+ .collect::();
+ let marked_actual_end = mark_unexpected_substr(&actual_end, format);
+ let marked_expected = mark_missing_substr(&self.expected, format);
format!(
- "expected {expression} to end with {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to end with {:?}\n but was: \"{actual_start}{marked_actual_end}\"\n expected: \"{marked_expected}\"",
+ self.expected,
)
}
}
@@ -284,10 +355,20 @@ where
subject.as_ref().ends_with(self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let actual_last_char = actual
+ .as_ref()
+ .chars()
+ .last()
+ .map(|c| c.to_string())
+ .unwrap_or_default();
+ let mut actual_start = actual.as_ref().to_string();
+ actual_start.pop();
+ let marked_actual_end = mark_unexpected_substr(&actual_last_char, format);
+ let marked_expected = mark_missing_char(self.expected, format);
format!(
- "expected {expression} to end with {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to end with {:?}\n but was: \"{actual_start}{marked_actual_end}\"\n expected: '{marked_expected}'",
+ self.expected,
)
}
}
@@ -336,10 +417,12 @@ where
subject.as_ref().contains(self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&self.expected, format);
format!(
- "expected {expression} to contain any of {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to contain any of {:?}\n but was: {marked_actual}\n expected: {marked_expected}",
+ self.expected,
)
}
}
@@ -352,10 +435,12 @@ where
subject.as_ref().contains(self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&self.expected, format);
format!(
- "expected {expression} to contain any of {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to contain any of {:?}\n but was: {marked_actual}\n expected: {marked_expected}",
+ self.expected,
)
}
}
@@ -368,10 +453,12 @@ where
subject.as_ref().contains(self.expected)
}
- fn message(&self, expression: Expression<'_>, actual: &S) -> String {
+ fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
+ let marked_actual = mark_unexpected(actual, format);
+ let marked_expected = mark_missing(&self.expected, format);
format!(
- "expected {expression} to contain any of {:?}\n but was: {actual:?}\n expected: {:?}",
- self.expected, self.expected
+ "expected {expression} to contain any of {:?}\n but was: {marked_actual}\n expected: {marked_expected}",
+ self.expected,
)
}
}
diff --git a/src/string/tests.rs b/src/string/tests.rs
index 40966e9..0751bf8 100644
--- a/src/string/tests.rs
+++ b/src/string/tests.rs
@@ -681,3 +681,351 @@ fn verify_string_ends_with_char_fails() {
"#]
);
}
+
+#[cfg(feature = "colored")]
+mod colored {
+ use crate::prelude::*;
+ use crate::std::string::ToString;
+
+ #[test]
+ fn highlight_diffs_is_equal_to_for_strings() {
+ let failures = verify_that("invidunt wisi facilisis exercitation")
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .is_equal_to("invi wisi exercitation anim placerat")
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject is equal to \"invi wisi exercitation anim placerat\"\n \
+ but was: \"invi\u{1b}[31mdunt\u{1b}[0m wisi \u{1b}[31mfacilisis \u{1b}[0mexercitation\"\n \
+ expected: \"invi wisi exercitation\u{1b}[34m anim placerat\u{1b}[0m\"\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_is_not_equal_to_for_strings() {
+ let failures = verify_that("aute aliquip culpa blandit")
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .is_not_equal_to("aute aliquip culpa blandit")
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject is not equal to \"aute aliquip culpa blandit\"\n \
+ but was: \"aute aliquip culpa blandit\"\n \
+ expected: \"aute aliquip culpa blandit\"\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_is_empty() {
+ let subject = "voluptua quod quis dignissim";
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .is_empty()
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject is empty\n \
+ but was: \u{1b}[31m\"voluptua quod quis dignissim\"\u{1b}[0m\n \
+ expected: \n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_is_not_empty() {
+ let subject = "";
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .is_not_empty()
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject is not empty\n \
+ but was: \u{1b}[31m\"\"\u{1b}[0m\n \
+ expected: \n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_has_length() {
+ let subject = "feugiat mazim vero vero";
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .has_length(29)
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject has length 29\n \
+ but was: \u{1b}[31m23\u{1b}[0m\n \
+ expected: \u{1b}[32m29\u{1b}[0m\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_has_length_in_range() {
+ let subject = "dignissim nisl erat possim";
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .has_length_in_range(8..=20)
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject has length in range 8..=20\n \
+ but was: \u{1b}[31m26\u{1b}[0m\n \
+ expected: \u{1b}[32m8..=20\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_contains_str() {
+ let subject = "sanctus stet eiusmod odio".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .contains("status")
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject to contain \"status\"\n \
+ but was: \"\u{1b}[31msanctus stet eiusmod odio\u{1b}[0m\"\n \
+ expected: \"\u{1b}[33mstatus\u{1b}[0m\"\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_contains_string() {
+ let subject = "sanctus stet eiusmod odio".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .contains("status".to_string())
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject to contain \"status\"\n \
+ but was: \"\u{1b}[31msanctus stet eiusmod odio\u{1b}[0m\"\n \
+ expected: \"\u{1b}[33mstatus\u{1b}[0m\"\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_contains_char() {
+ let subject = "sanctus stet eiusmod odio".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_YELLOW)
+ .contains('E')
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject to contain 'E'\n \
+ but was: \"\u{1b}[31msanctus stet eiusmod odio\u{1b}[0m\"\n \
+ expected: '\u{1b}[33mE\u{1b}[0m'\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_starts_with_str() {
+ let subject = "nulla feugiat illum culpa".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .starts_with("una")
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject to start with \"una\"\n \
+ but was: \"\u{1b}[31mnul\u{1b}[0mla feugiat illum culpa\"\n \
+ expected: \"\u{1b}[32muna\u{1b}[0m\"\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_starts_with_string() {
+ let subject = "nulla feugiat illum culpa".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .starts_with("una".to_string())
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject to start with \"una\"\n \
+ but was: \"\u{1b}[31mnul\u{1b}[0mla feugiat illum culpa\"\n \
+ expected: \"\u{1b}[32muna\u{1b}[0m\"\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_starts_with_char() {
+ let subject = "commodo sadipscing id imperdiet".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .starts_with('o')
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject to start with 'o'\n \
+ but was: \"\u{1b}[31mc\u{1b}[0mommodo sadipscing id imperdiet\"\n \
+ expected: '\u{1b}[32mo\u{1b}[0m'\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_ends_with_str() {
+ let subject = "nulla feugiat illum culpa".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .ends_with("innocence")
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject to end with \"innocence\"\n \
+ but was: \"nulla feugiat il\u{1b}[31mlum culpa\u{1b}[0m\"\n \
+ expected: \"\u{1b}[32minnocence\u{1b}[0m\"\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_ends_with_string() {
+ let subject = "nulla feugiat illum culpa".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .ends_with("innocence".to_string())
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject to end with \"innocence\"\n \
+ but was: \"nulla feugiat il\u{1b}[31mlum culpa\u{1b}[0m\"\n \
+ expected: \"\u{1b}[32minnocence\u{1b}[0m\"\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_ends_with_char() {
+ let subject = "commodo sadipscing id imperdiet".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_GREEN)
+ .ends_with('e')
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &["assertion failed: expected subject to end with 'e'\n \
+ but was: \"commodo sadipscing id imperdie\u{1b}[31mt\u{1b}[0m\"\n \
+ expected: '\u{1b}[32me\u{1b}[0m'\n\
+ "]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_contains_any_of_a_char_slice() {
+ let subject = "proident tempor est sed".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .contains_any_of(&['a', 'b', 'c'][..])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject to contain any of ['a', 'b', 'c']\n \
+ but was: \u{1b}[31m\"proident tempor est sed\"\u{1b}[0m\n \
+ expected: \u{1b}[34m['a', 'b', 'c']\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_contains_any_of_a_char_array() {
+ let subject = "proident tempor est sed".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .contains_any_of(['a', 'b', 'c'])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject to contain any of ['a', 'b', 'c']\n \
+ but was: \u{1b}[31m\"proident tempor est sed\"\u{1b}[0m\n \
+ expected: \u{1b}[34m['a', 'b', 'c']\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+
+ #[test]
+ fn highlight_diffs_string_contains_any_of_a_borrowed_char_array() {
+ let subject = "proident tempor est sed".to_string();
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .contains_any_of(&['a', 'b', 'c'])
+ .display_failures();
+
+ assert_eq!(
+ failures,
+ &[
+ "assertion failed: expected subject to contain any of ['a', 'b', 'c']\n \
+ but was: \u{1b}[31m\"proident tempor est sed\"\u{1b}[0m\n \
+ expected: \u{1b}[34m['a', 'b', 'c']\u{1b}[0m\n\
+ "
+ ]
+ );
+ }
+}
diff --git a/src/vec/tests.rs b/src/vec/tests.rs
index 10f3dc9..5cee152 100644
--- a/src/vec/tests.rs
+++ b/src/vec/tests.rs
@@ -142,7 +142,7 @@ fn verify_vec_contains_any_of_fails() {
assert_eq!(
failures,
&[
- r"assertion failed: expected my_thing contains any of [0, 2, 4, 8, 16, 32, 64], but contained none of them
+ r"assertion failed: expected my_thing contains any of [0, 2, 4, 8, 16, 32, 64]
but was: [5, 7, 11, 13, 1, 11, 3, 17, 23, 23, 29, 31, 41, 37, 43]
expected: [0, 2, 4, 8, 16, 32, 64]
"
@@ -424,10 +424,10 @@ fn verify_vec_contains_sequence_fails() {
failures,
&[
r#"assertion failed: expected my_thing contains sequence ["two", "three", "four", "five", "six", "six", "four"]
- but was: ["one", "two", "two", "three", "four", "five", "six", "four", "two", "seven", "two", "three", "five", "four", "six", "four", "eight", "nine", "ten"]
- expected: ["two", "three", "four", "five", "six", "six", "four"]
- missing: ["six", "four"]
- extra: ["four", "two"]
+ but was: ["one", "two", "two", "three", "four", "five", "six", "four", "two", "seven", "two", "three", "five", "four", "six", "four", "eight", "nine", "ten"]
+ expected: ["two", "three", "four", "five", "six", "six", "four"]
+ missing: ["six", "four"]
+ extra: ["four", "two"]
"#
]
);
@@ -453,10 +453,10 @@ fn verify_vec_contains_sequence_fails_expected_longer_than_vec() {
failures,
&[
r#"assertion failed: expected my_thing contains sequence ["one", "two", "three", "four", "five", "six", "seven"]
- but was: ["one", "two", "three", "four", "five", "six"]
- expected: ["one", "two", "three", "four", "five", "six", "seven"]
- missing: ["seven"]
- extra: []
+ but was: ["one", "two", "three", "four", "five", "six"]
+ expected: ["one", "two", "three", "four", "five", "six", "seven"]
+ missing: ["seven"]
+ extra: []
"#
]
);
@@ -518,9 +518,9 @@ fn verify_vec_contains_all_in_order_fails() {
failures,
&[
r#"assertion failed: expected my_thing contains all of ["one", "two", "two", "seven", "two", "three", "six", "six", "ten"] in order
- but was: ["one", "two", "two", "three", "four", "five", "six", "four", "two", "seven", "two", "three", "five", "four", "six", "four", "eight", "nine", "ten"]
- expected: ["one", "two", "two", "seven", "two", "three", "six", "six", "ten"]
- missing: ["six"]
+ but was: ["one", "two", "two", "three", "four", "five", "six", "four", "two", "seven", "two", "three", "five", "four", "six", "four", "eight", "nine", "ten"]
+ expected: ["one", "two", "two", "seven", "two", "three", "six", "six", "ten"]
+ missing: ["six"]
"#
]
);
@@ -669,3 +669,26 @@ fn verify_empty_vec_ends_with_expected_sequence_longer_than_vec_fails() {
]
);
}
+
+#[cfg(feature = "colored")]
+mod colored {
+ use super::*;
+
+ #[ignore = "TODO: we need some kind of specialized implementation of marked diffs for slices and Vec"]
+ #[test]
+ fn highlight_diffs_vec_is_equal_to_slice() {
+ let subject: Vec = vec![13, 5, 7, 19, 1, 3, 11, 29, 23, 31, 37];
+
+ let failures = verify_that(subject)
+ .with_diff_format(DIFF_FORMAT_RED_BLUE)
+ .is_equal_to([1, 3, 5, 7, 11, 13, 19, 23, 29, 31, 37])
+ .display_failures();
+
+ assert_eq!(failures, &[
+ "assertion failed: expected subject is equal to [1, 3, 5, 7, 11, 13, 19, 23, 29, 31, 37]\n \
+ but was: [\u{1b}[31m13\u{1b}[0m, 5, 7, \u{1b}[31m19\u{1b}[0m, \u{1b}[31m1\u{1b}[0m, \u{1b}[31m3\u{1b}[0m, 11, \u{1b}[31m29\u{1b}[0m, 23, 31, 37]
+ expected: [\u{1b}[34m1\u{1b}[0m, \u{1b}[34m3\u{1b}[0m, 5, 7, 11, \u{1b}[34m13\u{1b}[0m, \u{1b}[34m19\u{1b}[0m, 23, \u{1b}[34m29\u{1b}[0m, 31, 37]
+ "
+ ]);
+ }
+}
diff --git a/tests/version_numbers.rs b/tests/version_numbers.rs
index a46bb24..d387091 100644
--- a/tests/version_numbers.rs
+++ b/tests/version_numbers.rs
@@ -9,6 +9,10 @@ mod dummy_extern_uses {
#[cfg(feature = "float")]
use float_cmp as _;
use hashbrown as _;
+ use proptest as _;
+ #[cfg(feature = "colored")]
+ use sdiff as _;
+ use serial_test as _;
}
#[test]