From a29ee481061546701d546728cff5ab99c615a70d Mon Sep 17 00:00:00 2001 From: Lukas Potthast Date: Sun, 22 Jun 2025 15:42:26 +0200 Subject: [PATCH 1/9] Add `assert`, `assert_ref`, `must`, `must_ref`, `should` and `should_ref` functions with which an assertion context can be created; Remove `AssertingThat` and `AssertingThatRef` traits; Add `assert_that!` macro which can automatically handle references; Add be* and have* style alternative assertions --- Cargo.lock | 7 + assertr/Cargo.toml | 1 + assertr/src/assertions/alloc/string.rs | 49 ++++-- assertr/src/assertions/core/debug.rs | 48 ++++-- assertr/src/assertions/core/display.rs | 15 +- assertr/src/assertions/core/option.rs | 38 ++++- assertr/src/assertions/core/partial_eq.rs | 13 +- assertr/src/assertions/core/ref_cell.rs | 26 ++-- assertr/src/assertions/core/result.rs | 67 +++++++-- assertr/src/assertions/std/hashmap.rs | 68 ++++++--- assertr/src/assertions/std/mutex.rs | 6 +- assertr/src/assertions/tokio/rw_lock.rs | 28 ++-- assertr/src/lib.rs | 175 ++++++++++++++-------- assertr/src/mode.rs | 15 ++ assertr/tests/detail_messages.rs | 6 +- 15 files changed, 393 insertions(+), 169 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c1c8bf..e2549af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,6 +42,7 @@ version = "0.3.1" dependencies = [ "assertr", "assertr-derive", + "impls", "indoc", "jiff", "libm", @@ -603,6 +604,12 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "impls" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a46645bbd70538861a90d0f26c31537cdf1e44aae99a794fb75a664b70951bc" + [[package]] name = "indexmap" version = "2.9.0" diff --git a/assertr/Cargo.toml b/assertr/Cargo.toml index bc31606..4e5a018 100644 --- a/assertr/Cargo.toml +++ b/assertr/Cargo.toml @@ -35,6 +35,7 @@ serde = { version = "1.0.218", optional = true, features = ["derive"] } serde_json = { version = "1.0.140", optional = true } toml = { version = "0.8.20", optional = true } tokio = { version = "1.43.0", optional = true, features = ["full"] } +impls = "1.0.3" [dev-dependencies] assertr = { path = ".", features = ["std", "derive", "jiff", "reqwest", "tokio", "serde"] } diff --git a/assertr/src/assertions/alloc/string.rs b/assertr/src/assertions/alloc/string.rs index 5ad30cb..e882e1c 100644 --- a/assertr/src/assertions/alloc/string.rs +++ b/assertr/src/assertions/alloc/string.rs @@ -5,28 +5,49 @@ use crate::{AssertThat, Mode}; /// Assertions for heap-allocated, owned [String]s. pub trait StringAssertions { - fn contains(self, expected: impl AsRef) -> Self; + fn contain(self, expected: impl AsRef) -> Self; - fn starts_with(self, expected: impl AsRef) -> Self; + fn contains(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.contain(expected) + } + + fn start_with(self, expected: impl AsRef) -> Self; + + fn starts_with(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.start_with(expected) + } + + fn end_with(self, expected: impl AsRef) -> Self; - fn ends_with(self, expected: impl AsRef) -> Self; + fn ends_with(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.end_with(expected) + } } impl StringAssertions for AssertThat<'_, String, M> { #[track_caller] - fn contains(self, expected: impl AsRef) -> Self { + fn contain(self, expected: impl AsRef) -> Self { self.derive(|actual| actual.as_str()).contains(expected); self } #[track_caller] - fn starts_with(self, expected: impl AsRef) -> Self { + fn start_with(self, expected: impl AsRef) -> Self { self.derive(|actual| actual.as_str()).starts_with(expected); self } #[track_caller] - fn ends_with(self, expected: impl AsRef) -> Self { + fn end_with(self, expected: impl AsRef) -> Self { self.derive(|actual| actual.as_str()).ends_with(expected); self } @@ -34,15 +55,15 @@ impl StringAssertions for AssertThat<'_, String, M> { #[cfg(test)] mod tests { - mod contains { + mod contain { use crate::prelude::*; use indoc::formatdoc; #[test] fn succeeds_when_expected_is_contained() { - assert_that(String::from("foobar")).contains("foo"); - assert_that(String::from("foobar")).contains("bar"); - assert_that(String::from("foobar")).contains("oob"); + String::from("foobar").must().contain("foo"); + String::from("foobar").must().contain("bar"); + String::from("foobar").must().contain("oob"); } #[test] @@ -65,13 +86,13 @@ mod tests { } } - mod starts_with { + mod start_with { use crate::prelude::*; use indoc::formatdoc; #[test] fn succeeds_when_start_matches() { - assert_that(String::from("foo bar baz")).starts_with("foo b"); + String::from("foo bar baz").must().start_with("foo b"); } #[test] @@ -94,13 +115,13 @@ mod tests { } } - mod ends_with { + mod end_with { use crate::prelude::*; use indoc::formatdoc; #[test] fn succeeds_when_start_matches() { - assert_that(String::from("foo bar baz")).ends_with("r baz"); + String::from("foo bar baz").must().end_with("r baz"); } #[test] diff --git a/assertr/src/assertions/core/debug.rs b/assertr/src/assertions/core/debug.rs index 8d115a2..0fa4d3d 100644 --- a/assertr/src/assertions/core/debug.rs +++ b/assertr/src/assertions/core/debug.rs @@ -6,15 +6,31 @@ use core::fmt::Debug; /// Assertions for values implementing [Debug]. pub trait DebugAssertions { /// Test that actual has the `expected` `Debug` representation. - fn has_debug_string(self, expected: impl AsRef) -> Self; + fn have_debug_string(self, expected: impl AsRef) -> Self; + + /// Test that actual has the `expected` `Debug` representation. + fn has_debug_string(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.have_debug_string(expected) + } /// Test that actual and expected have the same `Debug` representation. - fn has_debug_value(self, expected: impl Debug) -> Self; + fn have_debug_value(self, expected: impl Debug) -> Self; + + /// Test that actual and expected have the same `Debug` representation. + fn has_debug_value(self, expected: impl Debug) -> Self + where + Self: Sized, + { + self.have_debug_value(expected) + } } impl DebugAssertions for AssertThat<'_, T, M> { #[track_caller] - fn has_debug_string(self, expected: impl AsRef) -> Self { + fn have_debug_string(self, expected: impl AsRef) -> Self { self.track_assertion(); let actual_string = format!("{:?}", self.actual()); @@ -37,7 +53,7 @@ impl DebugAssertions for AssertThat<'_, T, M> { } #[track_caller] - fn has_debug_value(self, expected: impl Debug) -> Self { + fn have_debug_value(self, expected: impl Debug) -> Self { self.track_assertion(); let actual_string = format!("{:?}", self.actual()); @@ -63,15 +79,15 @@ mod tests { #[test] fn succeeds_when_equal() { - assert_that(42).has_debug_string("42"); - assert_that(42).has_debug_string(&"42"); - assert_that(42).has_debug_string("42".to_string()); - assert_that(42).has_debug_string(&"42".to_string()); + 42.must().have_debug_string("42"); + 42.must().have_debug_string(&"42"); + 42.must().have_debug_string("42".to_string()); + 42.must().have_debug_string(&"42".to_string()); } #[test] fn succeeds_when_equal_on_static_string_containing_escaped_characters() { - assert_that("\n").has_debug_string(r#"\n"#); + "\n".must().have_debug_string(r#"\n"#); } #[test] @@ -79,7 +95,7 @@ mod tests { #[derive(Debug)] struct Data(#[expect(unused)] &'static str); - assert_that(Data("\n")).has_debug_string(r#"Data("\n")"#); + Data("\n").must().have_debug_string(r#"Data("\n")"#); } #[test] @@ -103,17 +119,17 @@ mod tests { #[test] fn succeeds_when_equal_using_same_value() { - assert_that(42).has_debug_value(42); - assert_that(42).has_debug_value(&42); + 42.must().have_debug_value(42); + 42.must().have_debug_value(&42); } // Although `has_debug_string` should be used instead! #[test] fn succeeds_when_equal_using_string_representation() { - assert_that(42).has_debug_value("42"); - assert_that(42).has_debug_value(&"42"); - assert_that(42).has_debug_value("42".to_string()); - assert_that(42).has_debug_value(&"42".to_string()); + 42.must().have_debug_value("42"); + 42.must().have_debug_value(&"42"); + 42.must().have_debug_value("42".to_string()); + 42.must().have_debug_value(&"42".to_string()); } #[test] diff --git a/assertr/src/assertions/core/display.rs b/assertr/src/assertions/core/display.rs index 0eb4b67..54a4471 100644 --- a/assertr/src/assertions/core/display.rs +++ b/assertr/src/assertions/core/display.rs @@ -5,12 +5,19 @@ use crate::assertions::core::strip_quotation_marks; use crate::{AssertThat, Mode, tracking::AssertionTracking}; pub trait DisplayAssertions { - fn has_display_value(self, expected: impl Display) -> Self; + fn have_display_value(self, expected: impl Display) -> Self; + + fn has_display_value(self, expected: impl Display) -> Self + where + Self: Sized, + { + self.have_display_value(expected) + } } impl DisplayAssertions for AssertThat<'_, T, M> { #[track_caller] - fn has_display_value(self, expected: impl Display) -> Self { + fn have_display_value(self, expected: impl Display) -> Self { self.track_assertion(); let actual_string = format!("{}", self.actual()); @@ -39,12 +46,12 @@ mod tests { #[test] fn succeeds_when_equal_using_same_value() { - assert_that(42).has_display_value(42); + 42.must().have_display_value(42); } #[test] fn succeeds_when_equal_using_string_representation() { - assert_that(42).has_display_value("42"); + 42.must().have_display_value("42"); } #[test] diff --git a/assertr/src/assertions/core/option.rs b/assertr/src/assertions/core/option.rs index 68bef76..aefe061 100644 --- a/assertr/src/assertions/core/option.rs +++ b/assertr/src/assertions/core/option.rs @@ -4,11 +4,30 @@ use core::option::Option; /// Assertions for generic optional values. pub trait OptionAssertions<'t, T, M: Mode> { + /// Test if this option is of the `Some` variant. + /// This is a terminal operation on the contained `Option`, + /// as there is nothing meaningful to do with the option if its variant was ensured. + /// This allows you to chain additional expectations on the contained success value. + fn be_some(self) -> AssertThat<'t, T, M> + where + T: Debug; + /// Test if this option is of the `Some` variant. /// This is a terminal operation on the contained `Option`, /// as there is nothing meaningful to do with the option if its variant was ensured. /// This allows you to chain additional expectations on the contained success value. fn is_some(self) -> AssertThat<'t, T, M> + where + T: Debug, + Self: Sized, + { + self.be_some() + } + + /// Test if this option is of the `None` variant. + /// This is a terminal operation on the contained `Option`, + /// as there is nothing meaningful to do with the option after its variant was ensured. + fn be_none(self) -> AssertThat<'t, (), M> where T: Debug; @@ -17,12 +36,16 @@ pub trait OptionAssertions<'t, T, M: Mode> { /// as there is nothing meaningful to do with the option after its variant was ensured. fn is_none(self) -> AssertThat<'t, (), M> where - T: Debug; + T: Debug, + Self: Sized, + { + self.be_none() + } } impl<'t, T, M: Mode> OptionAssertions<'t, T, M> for AssertThat<'t, Option, M> { #[track_caller] - fn is_some(self) -> AssertThat<'t, T, M> + fn be_some(self) -> AssertThat<'t, T, M> where T: Debug, { @@ -42,7 +65,7 @@ impl<'t, T, M: Mode> OptionAssertions<'t, T, M> for AssertThat<'t, Option, M> } #[track_caller] - fn is_none(self) -> AssertThat<'t, (), M> + fn be_none(self) -> AssertThat<'t, (), M> where T: Debug, { @@ -67,9 +90,7 @@ mod tests { #[test] fn succeeds_when_some() { - assert_that(Option::::Some(42)) - .is_some() - .is_equal_to(42); + Option::::Some(42).must().be_some().be_equal_to(42); } #[test] @@ -103,9 +124,10 @@ mod tests { #[test] fn panics_when_some() { assert_that_panic_by(|| { - assert_that(Option::::Some(42)) + Option::::Some(42) + .must() .with_location(false) - .is_none() + .be_none() }) .has_type::() .is_equal_to(formatdoc! {" diff --git a/assertr/src/assertions/core/partial_eq.rs b/assertr/src/assertions/core/partial_eq.rs index 4fdef9c..d2f7d13 100644 --- a/assertr/src/assertions/core/partial_eq.rs +++ b/assertr/src/assertions/core/partial_eq.rs @@ -6,11 +6,20 @@ use indoc::writedoc; use crate::{AssertThat, AssertrPartialEq, EqContext, Mode, tracking::AssertionTracking}; pub trait PartialEqAssertions { - fn is_equal_to(self, expected: E) -> Self + fn be_equal_to(self, expected: E) -> Self where T: AssertrPartialEq + Debug, E: Debug; + fn is_equal_to(self, expected: E) -> Self + where + T: AssertrPartialEq + Debug, + E: Debug, + Self: Sized, + { + self.be_equal_to(expected) + } + fn is_not_equal_to(self, expected: E) -> Self where T: AssertrPartialEq + Debug, @@ -19,7 +28,7 @@ pub trait PartialEqAssertions { impl PartialEqAssertions for AssertThat<'_, T, M> { #[track_caller] - fn is_equal_to(self, expected: E) -> Self + fn be_equal_to(self, expected: E) -> Self where T: AssertrPartialEq + Debug, E: Debug, diff --git a/assertr/src/assertions/core/ref_cell.rs b/assertr/src/assertions/core/ref_cell.rs index 664c5c9..fdaa4ab 100644 --- a/assertr/src/assertions/core/ref_cell.rs +++ b/assertr/src/assertions/core/ref_cell.rs @@ -13,7 +13,15 @@ pub trait RefCellAssertions { fn is_mutably_borrowed(self) -> Self; /// Check that the RefCell is not mutably borrowed, wither by being not borrowed at all, or only borrowed immutably. - fn is_not_mutably_borrowed(self) -> Self; + fn not_be_mutably_borrowed(self) -> Self; + + /// Check that the RefCell is not mutably borrowed, wither by being not borrowed at all, or only borrowed immutably. + fn is_not_mutably_borrowed(self) -> Self + where + Self: Sized, + { + self.not_be_mutably_borrowed() + } } impl RefCellAssertions for AssertThat<'_, RefCell, M> { @@ -50,7 +58,7 @@ impl RefCellAssertions for AssertThat<'_, RefCell, M> { } #[track_caller] - fn is_not_mutably_borrowed(self) -> Self { + fn not_be_mutably_borrowed(self) -> Self { self.track_assertion(); let actual = self.actual(); if actual.try_borrow_mut().is_ok() { @@ -78,7 +86,7 @@ mod tests { fn succeeds_when_borrowed() { let cell = RefCell::new(42); let borrow = cell.borrow(); - assert_that_ref(&cell).is_borrowed(); + assert_that!(&cell).is_borrowed(); drop(borrow); } @@ -86,14 +94,14 @@ mod tests { fn succeeds_when_mutably_borrowed() { let cell = RefCell::new(42); let borrow = cell.borrow_mut(); - assert_that_ref(&cell).is_borrowed(); + assert_that!(&cell).is_borrowed(); drop(borrow); } #[test] fn panics_when_not_borrowed() { let cell = RefCell::new(42); - assert_that_panic_by(|| assert_that_ref(&cell).with_location(false).is_borrowed()) + assert_that_panic_by(|| assert_that!(&cell).with_location(false).is_borrowed()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -115,8 +123,8 @@ mod tests { fn succeeds_when_mutably_borrowed() { let cell = RefCell::new(42); let borrow = cell.borrow_mut(); - assert_that_ref(&cell).is_borrowed(); - assert_that_ref(&cell).is_mutably_borrowed(); + assert_that!(&cell).is_borrowed(); + assert_that!(&cell).is_mutably_borrowed(); drop(borrow); } } @@ -129,7 +137,7 @@ mod tests { fn succeeds_when_not_borrowed_at_all() { let cell = RefCell::new(42); let borrow = cell.borrow(); - assert_that_ref(&cell).is_not_mutably_borrowed(); + cell.must_ref().not_be_mutably_borrowed(); drop(borrow); } @@ -137,7 +145,7 @@ mod tests { fn succeeds_when_immutably_borrowed() { let cell = RefCell::new(42); let borrow = cell.borrow(); - assert_that_ref(&cell).is_not_mutably_borrowed(); + assert_that!(&cell).is_not_mutably_borrowed(); drop(borrow); } } diff --git a/assertr/src/assertions/core/result.rs b/assertr/src/assertions/core/result.rs index cada627..da4bdd3 100644 --- a/assertr/src/assertions/core/result.rs +++ b/assertr/src/assertions/core/result.rs @@ -2,7 +2,21 @@ use crate::{AssertThat, actual::Actual, mode::Mode, tracking::AssertionTracking} use core::fmt::Debug; pub trait ResultAssertions<'t, M: Mode, T, E> { + fn be_ok(self) -> AssertThat<'t, T, M> + where + T: Debug, + E: Debug; + fn is_ok(self) -> AssertThat<'t, T, M> + where + T: Debug, + E: Debug, + Self: Sized, + { + self.be_ok() + } + + fn be_err(self) -> AssertThat<'t, E, M> where T: Debug, E: Debug; @@ -10,19 +24,43 @@ pub trait ResultAssertions<'t, M: Mode, T, E> { fn is_err(self) -> AssertThat<'t, E, M> where T: Debug, - E: Debug; + E: Debug, + Self: Sized, + { + self.be_err() + } - fn is_ok_satisfying(self, assertions: A) -> Self + fn be_ok_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, A: for<'a> FnOnce(AssertThat<'a, &'a T, M>); - fn is_err_satisfying(self, assertions: A) -> Self + fn is_ok_satisfying(self, assertions: A) -> Self + where + T: Debug, + E: Debug, + A: for<'a> FnOnce(AssertThat<'a, &'a T, M>), + Self: Sized, + { + self.be_ok_satisfying(assertions) + } + + fn be_err_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, A: for<'a> FnOnce(AssertThat<'a, &'a E, M>); + + fn is_err_satisfying(self, assertions: A) -> Self + where + T: Debug, + E: Debug, + A: for<'a> FnOnce(AssertThat<'a, &'a E, M>), + Self: Sized, + { + self.be_err_satisfying(assertions) + } } // Assertions for generic result values. @@ -31,7 +69,7 @@ impl<'t, M: Mode, T, E> ResultAssertions<'t, M, T, E> for AssertThat<'t, Result< /// as there is little meaningful to do with the result if its variant was ensured. /// This allows you to chain additional expectations on the contained success value. #[track_caller] - fn is_ok(self) -> AssertThat<'t, T, M> + fn be_ok(self) -> AssertThat<'t, T, M> where T: Debug, E: Debug, @@ -56,7 +94,7 @@ impl<'t, M: Mode, T, E> ResultAssertions<'t, M, T, E> for AssertThat<'t, Result< /// as there is little meaningful to do with the result if its variant was ensured. /// This allows you to chain additional expectations on the contained error value. #[track_caller] - fn is_err(self) -> AssertThat<'t, E, M> + fn be_err(self) -> AssertThat<'t, E, M> where T: Debug, E: Debug, @@ -78,7 +116,7 @@ impl<'t, M: Mode, T, E> ResultAssertions<'t, M, T, E> for AssertThat<'t, Result< } #[track_caller] - fn is_ok_satisfying(self, assertions: A) -> Self + fn be_ok_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, @@ -98,7 +136,7 @@ impl<'t, M: Mode, T, E> ResultAssertions<'t, M, T, E> for AssertThat<'t, Result< } #[track_caller] - fn is_err_satisfying(self, assertions: A) -> Self + fn be_err_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, @@ -126,15 +164,16 @@ mod tests { #[test] fn is_ok_succeeds_when_ok() { - assert_that(Result::<(), ()>::Ok(())).is_ok(); + Result::<(), ()>::Ok(()).must().be_ok(); } #[test] fn is_ok_panics_when_error() { assert_that_panic_by(|| { - assert_that(Result::::Err("someError".to_owned())) + Result::::Err("someError".to_owned()) + .must() .with_location(false) - .is_ok(); + .be_ok(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -150,7 +189,7 @@ mod tests { #[test] fn is_err_succeeds_when_error() { - assert_that(Result::<(), ()>::Err(())).is_err(); + Result::<(), ()>::Err(()).must().be_err(); } #[test] @@ -174,14 +213,14 @@ mod tests { #[test] fn is_ok_satisfying_succeeds_when_ok() { - assert_that(Result::::Ok(42)) + Result::::Ok(42) + .should() .with_location(false) - .with_capture() .is_ok_satisfying(|ok_value| { ok_value.is_greater_than(&9000); }) .capture_failures() - .assert_that_it() + .assert() .contains_exactly::([formatdoc! {" -------- assertr -------- Actual: 42 diff --git a/assertr/src/assertions/std/hashmap.rs b/assertr/src/assertions/std/hashmap.rs index 1003eba..cfe96b9 100644 --- a/assertr/src/assertions/std/hashmap.rs +++ b/assertr/src/assertions/std/hashmap.rs @@ -17,17 +17,37 @@ pub trait HashMapAssertions { K: Eq + Hash + Debug, V: Debug; + fn contain_value(self, expected: E) -> Self + where + K: Debug, + V: AssertrPartialEq + Debug, + E: Debug; + fn contains_value(self, expected: E) -> Self where K: Debug, V: AssertrPartialEq + Debug, + E: Debug, + Self: Sized, + { + self.contain_value(expected) + } + + fn contain_entry(self, key: impl Borrow, value: impl Borrow) -> Self + where + K: Eq + Hash + Debug, + V: AssertrPartialEq + Debug, E: Debug; fn contains_entry(self, key: impl Borrow, value: impl Borrow) -> Self where K: Eq + Hash + Debug, V: AssertrPartialEq + Debug, - E: Debug; + E: Debug, + Self: Sized, + { + self.contain_entry(key, value) + } } impl HashMapAssertions for AssertThat<'_, HashMap, M> { @@ -76,7 +96,7 @@ impl HashMapAssertions for AssertThat<'_, HashMap, M> } #[track_caller] - fn contains_value(self, expected: E) -> Self + fn contain_value(self, expected: E) -> Self where K: Debug, V: AssertrPartialEq + Debug, @@ -101,7 +121,7 @@ impl HashMapAssertions for AssertThat<'_, HashMap, M> } #[track_caller] - fn contains_entry(self, key: impl Borrow, value: impl Borrow) -> Self + fn contain_entry(self, key: impl Borrow, value: impl Borrow) -> Self where K: Eq + Hash + Debug, V: AssertrPartialEq + Debug, @@ -217,9 +237,9 @@ mod tests { mod contains_value { use std::collections::HashMap; - use indoc::formatdoc; - + use crate::IntoAssertContext; use crate::prelude::*; + use indoc::formatdoc; #[test] fn succeeds_when_value_is_present() { @@ -253,21 +273,33 @@ mod tests { map.insert("foo", "bar"); assert_that(map).contains_value("bar".to_string()); } - } - mod contains_entry { - use std::collections::HashMap; + #[test] + fn can_check_for_derived_type() { + #[derive(Debug, PartialEq, AssertrEq)] + struct Data { + data: u32, + } - use indoc::formatdoc; + let mut map = HashMap::new(); + map.insert("foo", Data { data: 0 }); + map.must_ref().contain_value(Data { data: 0 }); + map.must().contain_value(Data { data: 0 }); + } + } + mod contains_entry { + use crate::IntoAssertContext; use crate::prelude::*; + use indoc::formatdoc; + use std::collections::HashMap; #[test] fn succeeds_when_value_is_present() { let mut map = HashMap::new(); map.insert("foo", "bar"); // TODO: Can we get rid of the requirement to explicitly define E as `&str` here? - assert_that(map).contains_entry::<&str>("foo", "bar"); + map.must().contains_entry::<&str>("foo", "bar"); } #[test] @@ -278,9 +310,11 @@ mod tests { } let mut map = HashMap::<&str, Person>::new(); map.insert("foo", Person { age: 42 }); - assert_that_ref(&map).contains_entry("foo", &Person { age: 42 }); - assert_that_ref(&map).contains_entry("foo", Person { age: 42 }); - assert_that_ref(&map).contains_entry("foo", Box::new(Person { age: 42 })); + (&map).must().contain_entry("foo", &Person { age: 42 }); + (&map).must().contain_entry("foo", Person { age: 42 }); + (&map) + .must() + .contain_entry("foo", Box::new(Person { age: 42 })); } #[test] @@ -288,9 +322,9 @@ mod tests { assert_that_panic_by(|| { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map) + map.must() .with_location(false) - .contains_entry::<&str>("baz", "someValue"); + .contain_entry::<&str>("baz", "someValue"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -309,9 +343,9 @@ mod tests { assert_that_panic_by(|| { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map) + map.must() .with_location(false) - .contains_entry::<&str>("foo", "someValue"); + .contain_entry::<&str>("foo", "someValue"); }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/std/mutex.rs b/assertr/src/assertions/std/mutex.rs index 30f98fc..23e16c6 100644 --- a/assertr/src/assertions/std/mutex.rs +++ b/assertr/src/assertions/std/mutex.rs @@ -73,14 +73,14 @@ mod tests { fn succeeds_when_locked() { let mutex = Mutex::new(42); let guard = mutex.lock(); - assert_that_ref(&mutex).is_locked(); + mutex.assert_ref().is_locked(); drop(guard); } #[test] fn panics_when_not_locked() { let mutex = Mutex::new(42); - assert_that_panic_by(|| assert_that(mutex).with_location(false).is_locked()) + assert_that_panic_by(|| mutex.assert().with_location(false).is_locked()) .has_type::() .is_equal_to(formatdoc! {" -------- assertr -------- @@ -108,7 +108,7 @@ mod tests { fn panics_when_locked() { let mutex = Mutex::new(42); let guard = mutex.lock(); - assert_that_panic_by(|| assert_that_ref(&mutex).with_location(false).is_not_locked()) + assert_that_panic_by(|| mutex.assert_ref().with_location(false).is_not_locked()) .has_type::() .is_equal_to(formatdoc! {" -------- assertr -------- diff --git a/assertr/src/assertions/tokio/rw_lock.rs b/assertr/src/assertions/tokio/rw_lock.rs index 5ea604f..46d3264 100644 --- a/assertr/src/assertions/tokio/rw_lock.rs +++ b/assertr/src/assertions/tokio/rw_lock.rs @@ -157,6 +157,7 @@ mod tests { } mod is_read_locked { + use crate::IntoAssertContext; use crate::prelude::*; use indoc::formatdoc; use tokio::sync::RwLock; @@ -165,7 +166,7 @@ mod tests { async fn succeeds_when_read_locked() { let rw_lock = RwLock::new(42); let rw_lock_read_guard = rw_lock.read().await; - assert_that_ref(&rw_lock).is_read_locked(); + rw_lock.assert_ref().is_read_locked(); drop(rw_lock_read_guard); } @@ -174,13 +175,9 @@ mod tests { let rw_lock = RwLock::new(42); let rw_lock_write_guard = rw_lock.write().await; - assert_that_panic_by(|| { - assert_that_ref(&rw_lock) - .with_location(false) - .is_read_locked() - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| rw_lock.assert_ref().with_location(false).is_read_locked()) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Actual: RwLock {{ data: }} @@ -212,6 +209,7 @@ mod tests { } mod is_write_locked { + use crate::IntoAssertContext; use crate::prelude::*; use indoc::formatdoc; use tokio::sync::RwLock; @@ -220,7 +218,7 @@ mod tests { async fn succeeds_when_write_locked() { let rw_lock = RwLock::new(42); let rw_lock_write_guard = rw_lock.write().await; - assert_that_ref(&rw_lock).is_write_locked(); + rw_lock.assert_ref().is_write_locked(); drop(rw_lock_write_guard); } @@ -229,13 +227,9 @@ mod tests { let rw_lock = RwLock::new(42); let rw_lock_read_guard = rw_lock.read().await; - assert_that_panic_by(|| { - assert_that_ref(&rw_lock) - .with_location(false) - .is_write_locked() - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| rw_lock.assert_ref().with_location(false).is_write_locked()) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Actual: RwLock {{ data: 42 }} @@ -252,7 +246,7 @@ mod tests { fn panics_when_not_write_locked() { let rw_lock = RwLock::new(42); - assert_that_panic_by(|| assert_that(rw_lock).with_location(false).is_write_locked()) + assert_that_panic_by(|| rw_lock.assert().with_location(false).is_write_locked()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- diff --git a/assertr/src/lib.rs b/assertr/src/lib.rs index 666b4b5..ca2b3ee 100644 --- a/assertr/src/lib.rs +++ b/assertr/src/lib.rs @@ -36,8 +36,7 @@ pub mod prelude { pub use assertr_derive::AssertrEq; pub use crate::AssertThat; - pub use crate::AssertingThat; - pub use crate::AssertingThatRef; + pub use crate::IntoAssertContext; pub use crate::any; pub use crate::assert_that; #[cfg(feature = "std")] @@ -92,13 +91,101 @@ pub struct PanicValue(Box); #[track_caller] #[must_use] pub fn assert_that<'t, T>(actual: T) -> AssertThat<'t, T, Panic> { - AssertThat::new(Actual::Owned(actual)) + AssertThat::new_panicking(Actual::Owned(actual)) } #[track_caller] #[must_use] pub fn assert_that_ref(actual: &T) -> AssertThat { - AssertThat::new(Actual::Borrowed(actual)) + AssertThat::new_panicking(Actual::Borrowed(actual)) +} + +/// Entrypoint that handles references. +#[macro_export] +macro_rules! assert_that { + ($expr:expr) => { + $crate::IntoAssertContext::assert($expr) + }; +} + +pub trait IntoAssertContext<'t, T> { + fn assert(self) -> AssertThat<'t, T, Panic>; + fn assert_ref(&'t self) -> AssertThat<'t, T, Panic>; + + fn must(self) -> AssertThat<'t, T, Panic>; + fn must_ref(&'t self) -> AssertThat<'t, T, Panic>; + + fn should(self) -> AssertThat<'t, T, Capture>; + fn should_ref(&'t self) -> AssertThat<'t, T, Capture>; +} + +impl<'t, T> IntoAssertContext<'t, T> for T { + fn assert(self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Owned(self)) + } + fn assert_ref(&'t self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + + fn must(self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Owned(self)) + } + fn must_ref(&'t self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + + fn should(self) -> AssertThat<'t, T, Capture> { + AssertThat::new_capturing(Actual::Owned(self)) + } + fn should_ref(&'t self) -> AssertThat<'t, T, Capture> { + AssertThat::new_capturing(Actual::Borrowed(self)) + } +} + +impl<'t, T> IntoAssertContext<'t, T> for &'t T { + fn assert(self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + fn assert_ref(&'t self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + + fn must(self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + fn must_ref(&'t self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + + fn should(self) -> AssertThat<'t, T, Capture> { + AssertThat::new_capturing(Actual::Borrowed(self)) + } + fn should_ref(&'t self) -> AssertThat<'t, T, Capture> { + AssertThat::new_capturing(Actual::Borrowed(self)) + } +} + +impl<'t, T> IntoAssertContext<'t, T> for &'t mut T { + fn assert(self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + fn assert_ref(&'t self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + + fn must(self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + fn must_ref(&'t self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Borrowed(self)) + } + + fn should(self) -> AssertThat<'t, T, Capture> { + AssertThat::new_capturing(Actual::Borrowed(self)) + } + fn should_ref(&'t self) -> AssertThat<'t, T, Capture> { + AssertThat::new_capturing(Actual::Borrowed(self)) + } } #[track_caller] @@ -131,64 +218,11 @@ impl Type { } pub fn assert_that_type() -> AssertThat<'static, Type, Panic> { - AssertThat::new(Actual::Owned(Type { + AssertThat::new_panicking(Actual::Owned(Type { phantom: Default::default(), })) } -pub trait AssertingThat { - fn assert_that<'t, U>(self, map: impl Fn(Self) -> U) -> AssertThat<'t, U, Panic> - where - Self: Sized; - - fn assert_that_it<'t>(self) -> AssertThat<'t, Self, Panic> - where - Self: Sized; -} - -impl AssertingThat for T { - fn assert_that<'t, U>(self, map: impl Fn(T) -> U) -> AssertThat<'t, U, Panic> - where - Self: Sized, - { - assert_that(map(self)) - } - - fn assert_that_it<'t>(self) -> AssertThat<'t, Self, Panic> { - assert_that(self) - } -} - -pub trait AssertingThatRef { - type Owned; - - fn assert_that(&self, map: impl Fn(&Self) -> &U) -> AssertThat - where - Self: Sized; - - fn assert_that_it(&self) -> AssertThat - where - Self: Sized; -} - -impl AssertingThatRef for &T { - type Owned = T; - - fn assert_that(&self, map: impl Fn(&Self) -> &U) -> AssertThat - where - Self: Sized, - { - assert_that_ref(map(self)) - } - - fn assert_that_it(&self) -> AssertThat - where - Self: Sized, - { - assert_that_ref(self) - } -} - /// `AssertThat` is the core structure used for assertions. It allows developers to perform /// assertions on actual values in a fluent and expressive manner, supporting detailed messages /// as well as different modes of operation, such as panic or capture modes. @@ -258,7 +292,23 @@ impl RefUnwindSafe for AssertThat<'_, T, M> {} impl<'t, T> AssertThat<'t, T, Panic> { #[track_caller] - pub(crate) const fn new(actual: Actual<'t, T>) -> Self { + pub(crate) const fn new_panicking(actual: Actual<'t, T>) -> Self { + AssertThat { + parent: None, + actual, + subject_name: None, + detail_messages: RefCell::new(Vec::new()), + print_location: true, + number_of_assertions: RefCell::new(NumberOfAssertions::new()), + failures: RefCell::new(Vec::new()), + mode: RefCell::new(Panic::const_default()), + } + } +} + +impl<'t, T> AssertThat<'t, T, Capture> { + #[track_caller] + pub(crate) const fn new_capturing(actual: Actual<'t, T>) -> Self { AssertThat { parent: None, actual, @@ -267,7 +317,7 @@ impl<'t, T> AssertThat<'t, T, Panic> { print_location: true, number_of_assertions: RefCell::new(NumberOfAssertions::new()), failures: RefCell::new(Vec::new()), - mode: RefCell::new(Panic { derived: false }), + mode: RefCell::new(Capture::const_default()), } } } @@ -653,7 +703,8 @@ mod tests { } #[test] - fn asserting_that_this_allows_entering_assertion_context() { - 42.assert_that_it().is_equal_to(42); + fn allows_fluent_entry_into_assertion_context() { + 42.assert_ref().is_equal_to(42); + 42.assert().is_equal_to(42); } } diff --git a/assertr/src/mode.rs b/assertr/src/mode.rs index de274e0..ad75c0a 100644 --- a/assertr/src/mode.rs +++ b/assertr/src/mode.rs @@ -23,12 +23,27 @@ pub struct Panic { pub(crate) derived: bool, } +impl Panic { + pub(crate) const fn const_default() -> Self { + Self { derived: false } + } +} + #[derive(Debug, Default, PartialEq, Clone)] pub struct Capture { pub(crate) derived: bool, pub(crate) captured: bool, } +impl Capture { + pub(crate) const fn const_default() -> Self { + Self { + derived: false, + captured: false, + } + } +} + impl Mode for Panic { fn set_derived(&mut self) { self.derived = true; diff --git a/assertr/tests/detail_messages.rs b/assertr/tests/detail_messages.rs index ce828c6..6bbad8a 100644 --- a/assertr/tests/detail_messages.rs +++ b/assertr/tests/detail_messages.rs @@ -1,6 +1,6 @@ -use indoc::formatdoc; - +use assertr::IntoAssertContext; use assertr::prelude::*; +use indoc::formatdoc; #[derive(Debug, PartialEq)] struct Person { @@ -22,7 +22,7 @@ fn test() { }, ) .capture_failures() - .assert_that_it() + .assert() .contains_exactly::([ formatdoc! {r#" -------- assertr -------- From b06bfdeeac4e5fcbf77631588b69612648a67c9f Mon Sep 17 00:00:00 2001 From: Lukas Potthast Date: Tue, 24 Jun 2025 15:06:37 +0200 Subject: [PATCH 2/9] Add to/be/have style functions on VecAssertions --- assertr/src/assertions/alloc/vec.rs | 37 +++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/assertr/src/assertions/alloc/vec.rs b/assertr/src/assertions/alloc/vec.rs index e2dd5e5..bea2e21 100644 --- a/assertr/src/assertions/alloc/vec.rs +++ b/assertr/src/assertions/alloc/vec.rs @@ -4,25 +4,52 @@ use core::fmt::Debug; use crate::{AssertThat, AssertrPartialEq, Mode, prelude::SliceAssertions}; pub trait VecAssertions<'t, T: Debug> { + fn contain(self, expected: E) -> Self + where + E: Debug, + T: AssertrPartialEq + Debug; + fn contains(self, expected: E) -> Self where E: Debug, + T: AssertrPartialEq + Debug, + Self: Sized, + { + self.contain(expected) + } + + fn contain_exactly(self, expected: impl AsRef<[E]>) -> Self + where + E: Debug + 't, T: AssertrPartialEq + Debug; fn contains_exactly(self, expected: impl AsRef<[E]>) -> Self where E: Debug + 't, - T: AssertrPartialEq + Debug; + T: AssertrPartialEq + Debug, + Self: Sized, + { + self.contain_exactly(expected) + } /// [P] - Predicate - fn contains_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self + fn contain_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self where P: Fn(&T) -> bool; + + /// [P] - Predicate + fn contains_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self + where + P: Fn(&T) -> bool, + Self: Sized, + { + self.contain_exactly_matching_in_any_order(expected) + } } impl<'t, T: Debug, M: Mode> VecAssertions<'t, T> for AssertThat<'t, Vec, M> { #[track_caller] - fn contains(self, expected: E) -> Self + fn contain(self, expected: E) -> Self where E: Debug, T: AssertrPartialEq + Debug, @@ -32,7 +59,7 @@ impl<'t, T: Debug, M: Mode> VecAssertions<'t, T> for AssertThat<'t, Vec, M> { } #[track_caller] - fn contains_exactly(self, expected: impl AsRef<[E]>) -> Self + fn contain_exactly(self, expected: impl AsRef<[E]>) -> Self where E: Debug + 't, T: AssertrPartialEq + Debug, @@ -42,7 +69,7 @@ impl<'t, T: Debug, M: Mode> VecAssertions<'t, T> for AssertThat<'t, Vec, M> { } #[track_caller] - fn contains_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self + fn contain_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self where P: Fn(&T) -> bool, // predicate { From 33fd214f3b603f2211343e7b2f16dc8aecc3a6e9 Mon Sep 17 00:00:00 2001 From: Lukas Potthast Date: Wed, 25 Jun 2025 01:58:32 +0200 Subject: [PATCH 3/9] Update doc comment; Add more to/be/have style functions --- assertr/src/assertions/core/length.rs | 11 +++++++++-- assertr/src/assertions/num/mod.rs | 22 +++++++++++++++++++--- assertr/src/lib.rs | 13 ++++++------- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/assertr/src/assertions/core/length.rs b/assertr/src/assertions/core/length.rs index c0ab348..4aae2c1 100644 --- a/assertr/src/assertions/core/length.rs +++ b/assertr/src/assertions/core/length.rs @@ -11,7 +11,14 @@ pub trait LengthAssertions { fn is_not_empty(self) -> Self; - fn has_length(self, expected: usize) -> Self; + fn have_length(self, expected: usize) -> Self; + + fn has_length(self, expected: usize) -> Self + where + Self: Sized, + { + self.have_length(expected) + } } impl LengthAssertions for AssertThat<'_, T, M> { @@ -50,7 +57,7 @@ impl LengthAssertions for AssertThat<'_, T, M> { } #[track_caller] - fn has_length(self, expected: usize) -> Self { + fn have_length(self, expected: usize) -> Self { self.track_assertion(); let actual_len = self.actual().length(); if actual_len != expected { diff --git a/assertr/src/assertions/num/mod.rs b/assertr/src/assertions/num/mod.rs index 1e3c9d1..e2966af 100644 --- a/assertr/src/assertions/num/mod.rs +++ b/assertr/src/assertions/num/mod.rs @@ -19,13 +19,29 @@ pub trait NumAssertions { fn is_multiplicative_identity(self) -> Self; + fn be_negative(self) -> Self + where + T: Signed; + fn is_negative(self) -> Self + where + T: Signed, + Self: Sized, + { + self.be_negative() + } + + fn be_positive(self) -> Self where T: Signed; fn is_positive(self) -> Self where - T: Signed; + T: Signed, + Self: Sized, + { + self.be_positive() + } /// Fails if actual is not in the range /// `[expected - allowed_deviation, expected + allowed_deviation]`. @@ -107,7 +123,7 @@ impl NumAssertions for AssertThat<'_, T, M> { } #[track_caller] - fn is_negative(self) -> Self + fn be_negative(self) -> Self where T: Signed, { @@ -126,7 +142,7 @@ impl NumAssertions for AssertThat<'_, T, M> { } #[track_caller] - fn is_positive(self) -> Self + fn be_positive(self) -> Self where T: Signed, { diff --git a/assertr/src/lib.rs b/assertr/src/lib.rs index 2b8898f..51866df 100644 --- a/assertr/src/lib.rs +++ b/assertr/src/lib.rs @@ -315,13 +315,12 @@ impl AssertThat<'_, T, Capture> { /// ```rust /// use assertr::prelude::*; /// - /// assert_that(42) - /// .with_capture() - /// .is_negative() - /// .is_equal_to(43) - /// .capture_failures() - /// .assert_that_it() - /// .has_length(2); + /// let failures = 42.should() + /// .be_negative() + /// .be_equal_to(43) + /// .capture_failures(); + /// + /// failures.must().have_length(2); /// ``` #[must_use] pub fn capture_failures(mut self) -> Vec { From 16aead6a494c10aad0866ca64a38b50fb2642d0c Mon Sep 17 00:00:00 2001 From: Lukas Potthast Date: Fri, 27 Jun 2025 23:04:48 +0200 Subject: [PATCH 4/9] Switch from must/must_ref to must_owned/must, as working on references should be the default; Add remaining "be"/"have" style asserts; Fix clippy lints --- Cargo.lock | 9 +- assertr-derive/tests/04-equality-check.rs | 8 +- assertr-derive/tests/05-replace-field-type.rs | 4 +- .../tests/06-replace-deep-field-type.rs | 4 +- .../tests/07-derive-impl-for-reference.rs | 2 +- assertr-derive/tests/08-default-impl.rs | 4 +- assertr/Cargo.toml | 3 +- assertr/src/assertions/alloc/boxed.rs | 29 ++- assertr/src/assertions/alloc/panic_value.rs | 34 ++- assertr/src/assertions/alloc/string.rs | 36 +-- assertr/src/assertions/alloc/vec.rs | 26 +- assertr/src/assertions/core/array.rs | 28 ++- assertr/src/assertions/core/bool.rs | 22 +- assertr/src/assertions/core/char.rs | 39 ++- assertr/src/assertions/core/debug.rs | 61 +++-- assertr/src/assertions/core/display.rs | 41 ++- assertr/src/assertions/core/fn.rs | 25 +- assertr/src/assertions/core/iter.rs | 34 ++- assertr/src/assertions/core/length.rs | 91 +++---- assertr/src/assertions/core/option.rs | 32 ++- assertr/src/assertions/core/partial_eq.rs | 27 +- assertr/src/assertions/core/partial_ord.rs | 60 ++++- assertr/src/assertions/core/poll.rs | 33 ++- assertr/src/assertions/core/range.rs | 78 ++++-- assertr/src/assertions/core/ref_cell.rs | 38 ++- assertr/src/assertions/core/result.rs | 35 +-- assertr/src/assertions/core/slice.rs | 149 +++++++---- assertr/src/assertions/core/str_slice.rs | 86 ++++--- .../src/assertions/jiff/signed_duration.rs | 50 +++- assertr/src/assertions/jiff/span.rs | 58 +++-- assertr/src/assertions/jiff/zoned.rs | 30 ++- assertr/src/assertions/mod.rs | 110 ++++----- assertr/src/assertions/num/mod.rs | 233 +++++++++++------- assertr/src/assertions/reqwest/response.rs | 2 +- assertr/src/assertions/std/command.rs | 4 +- assertr/src/assertions/std/hashmap.rs | 59 +++-- assertr/src/assertions/std/mem.rs | 4 + assertr/src/assertions/std/mutex.rs | 46 +++- assertr/src/assertions/std/path.rs | 178 +++++++++---- assertr/src/assertions/tokio/mutex.rs | 28 ++- assertr/src/assertions/tokio/rw_lock.rs | 59 +++-- assertr/src/assertions/tokio/watch.rs | 39 ++- assertr/src/cmp/hashmap.rs | 4 +- assertr/src/cmp/slice.rs | 20 +- assertr/src/conversion.rs | 4 +- assertr/src/failure.rs | 2 +- assertr/src/lib.rs | 196 ++++++++++----- assertr/src/tracking.rs | 27 +- assertr/src/util/slice.rs | 46 ++-- assertr/tests/conditions.rs | 4 +- assertr/tests/conversion.rs | 11 +- assertr/tests/custom_assertions.rs | 2 +- assertr/tests/derive.rs | 9 +- assertr/tests/derive_async.rs | 5 +- assertr/tests/detail_messages.rs | 2 +- assertr/tests/map.rs | 10 +- assertr/tests/map_async.rs | 5 +- 57 files changed, 1513 insertions(+), 772 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 358b684..3fa5067 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,11 +38,10 @@ dependencies = [ [[package]] name = "assertr" -version = "0.3.5" +version = "0.4.0" dependencies = [ "assertr", "assertr-derive", - "impls", "indoc", "jiff", "libm", @@ -604,12 +603,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "impls" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a46645bbd70538861a90d0f26c31537cdf1e44aae99a794fb75a664b70951bc" - [[package]] name = "indexmap" version = "2.9.0" diff --git a/assertr-derive/tests/04-equality-check.rs b/assertr-derive/tests/04-equality-check.rs index e560665..c2db0a1 100644 --- a/assertr-derive/tests/04-equality-check.rs +++ b/assertr-derive/tests/04-equality-check.rs @@ -20,22 +20,22 @@ fn main() { data: (42, 100), }; - assert_that_ref(&foo).is_equal_to(FooAssertrEq { + foo.must().be_equal_to(FooAssertrEq { id: any(), name: any(), data: any(), }); - assert_that_ref(&foo).is_equal_to(FooAssertrEq { + foo.must().be_equal_to(FooAssertrEq { id: eq(1), name: eq("bob".to_string()), data: any(), }); assert_that_panic_by(|| { - assert_that_ref(&foo) + foo.must() .with_location(false) - .is_equal_to(FooAssertrEq { + .be_equal_to(FooAssertrEq { id: eq(1), name: eq("otto".to_string()), data: any(), diff --git a/assertr-derive/tests/05-replace-field-type.rs b/assertr-derive/tests/05-replace-field-type.rs index 1cd14e2..f86cc48 100644 --- a/assertr-derive/tests/05-replace-field-type.rs +++ b/assertr-derive/tests/05-replace-field-type.rs @@ -21,12 +21,12 @@ fn main() { bar: Bar { id: 42 }, }; - assert_that_ref(&foo).is_equal_to(FooAssertrEq { + foo.must().be_equal_to(FooAssertrEq { id: any(), bar: any(), }); - assert_that_ref(&foo).is_equal_to(FooAssertrEq { + foo.must().be_equal_to(FooAssertrEq { id: eq(1), bar: eq(BarAssertrEq { id: eq(42) }), }); diff --git a/assertr-derive/tests/06-replace-deep-field-type.rs b/assertr-derive/tests/06-replace-deep-field-type.rs index e94a5f1..5f00537 100644 --- a/assertr-derive/tests/06-replace-deep-field-type.rs +++ b/assertr-derive/tests/06-replace-deep-field-type.rs @@ -33,13 +33,13 @@ fn main() { bars2: HashMap::new(), }; - assert_that_ref(&foo).is_equal_to(FooAssertrEq { + foo.must().be_equal_to(FooAssertrEq { id: any(), bars: any(), bars2: any(), }); - assert_that_ref(&foo).is_equal_to(FooAssertrEq { + foo.must().be_equal_to(FooAssertrEq { id: eq(1), bars: eq(vec![BarAssertrEq { id: eq(42) }]), bars2: eq(HashMap::new()), diff --git a/assertr-derive/tests/07-derive-impl-for-reference.rs b/assertr-derive/tests/07-derive-impl-for-reference.rs index 541f960..32ffeb5 100644 --- a/assertr-derive/tests/07-derive-impl-for-reference.rs +++ b/assertr-derive/tests/07-derive-impl-for-reference.rs @@ -29,5 +29,5 @@ fn main() { // This must compile without errors. // It should only compile when AssertrPartialEq // was not only implemented for Bar, but also for &Bar! - assert_that(bars_refs).contains(BarAssertrEq { id: any() }); + bars_refs.must().contain(BarAssertrEq { id: any() }); } diff --git a/assertr-derive/tests/08-default-impl.rs b/assertr-derive/tests/08-default-impl.rs index 02d34e3..a805cc5 100644 --- a/assertr-derive/tests/08-default-impl.rs +++ b/assertr-derive/tests/08-default-impl.rs @@ -16,8 +16,8 @@ fn main() { field_2: 2, field_3: 3, }; - - assert_that(foo).is_equal_to(FooAssertrEq { + + foo.must().be_equal_to(FooAssertrEq { field_1: eq(1), ..Default::default() }); diff --git a/assertr/Cargo.toml b/assertr/Cargo.toml index 762a46e..68511c1 100644 --- a/assertr/Cargo.toml +++ b/assertr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "assertr" -version = "0.3.5" +version = "0.4.0" edition = "2024" rust-version = "1.85.0" authors = ["Lukas Potthast "] @@ -35,7 +35,6 @@ serde = { version = "1.0.218", optional = true, features = ["derive"] } serde_json = { version = "1.0.140", optional = true } toml = { version = "0.8.20", optional = true } tokio = { version = "1.43.0", optional = true, features = ["full"] } -impls = "1.0.3" [dev-dependencies] assertr = { path = ".", features = ["std", "derive", "jiff", "reqwest", "tokio", "serde"] } diff --git a/assertr/src/assertions/alloc/boxed.rs b/assertr/src/assertions/alloc/boxed.rs index 199b69d..2b413db 100644 --- a/assertr/src/assertions/alloc/boxed.rs +++ b/assertr/src/assertions/alloc/boxed.rs @@ -12,8 +12,21 @@ pub trait BoxAssertions<'t, M: Mode> { /// If this fails in capturing mode, a panic is raised! fn has_type(self) -> AssertThat<'t, E, M>; + /// If this fails in capturing mode, a panic is raised! + fn have_type(self) -> AssertThat<'t, E, M> + where + Self: Sized, + { + self.has_type() + } + /// If this fails in capturing mode, a panic is raised! fn has_type_ref(&'t self) -> AssertThat<'t, &'t E, M>; + + /// If this fails in capturing mode, a panic is raised! + fn have_type_ref(&'t self) -> AssertThat<'t, &'t E, M> { + self.has_type_ref() + } } impl<'t, M: Mode> BoxAssertions<'t, M> for AssertThat<'t, Box, M> { @@ -197,7 +210,11 @@ mod tests { fn succeeds_when_type_of_contained_value_matches_expected_type() { let boxed_any: Box = Box::new("foo"); - assert_that(boxed_any).has_type::<&str>().is_equal_to("foo"); + boxed_any + .must() + .have_type::<&str>() + .and() + .be_equal_to("foo"); } #[test] @@ -205,7 +222,7 @@ mod tests { let boxed_any: Box = Box::new("foo"); assert_that_panic_by(|| { - assert_that(boxed_any) + assert_that_owned(boxed_any) .with_location(false) .has_type::(); }) @@ -229,7 +246,7 @@ mod tests { fn succeeds_when_type_matches() { let actual: Box = Box::new(String::from("foo")); - assert_that(actual) + assert_that_owned(actual) .has_type_ref::() .is_equal_to(&String::from("foo")); } @@ -239,7 +256,7 @@ mod tests { let actual: Box = Box::new(String::from("foo")); assert_that_panic_by(|| { - assert_that(actual) + assert_that_owned(actual) .with_location(false) .has_type_ref::(); }) @@ -258,7 +275,7 @@ mod tests { let actual: Box = Box::new("foo"); assert_that_panic_by(|| { - assert_that(actual) + assert_that_owned(actual) .with_location(false) .has_type_ref::(); }) @@ -278,7 +295,7 @@ mod tests { let actual: Box = Box::new(Foo {}); assert_that_panic_by(|| { - assert_that(actual) + assert_that_owned(actual) .with_location(false) .has_type_ref::(); }) diff --git a/assertr/src/assertions/alloc/panic_value.rs b/assertr/src/assertions/alloc/panic_value.rs index f352df4..ae6b446 100644 --- a/assertr/src/assertions/alloc/panic_value.rs +++ b/assertr/src/assertions/alloc/panic_value.rs @@ -11,8 +11,20 @@ use super::boxed::BoxAssertions; pub trait PanicValueAssertions<'t, M: Mode> { fn has_type(self) -> AssertThat<'t, E, M>; + fn have_type(self) -> AssertThat<'t, E, M> + where + Self: Sized, + { + self.has_type() + } + /// NOTE: If this fails in capturing mode, a panic is raised! fn has_type_ref(&'t self) -> AssertThat<'t, &'t E, M>; + + /// NOTE: If this fails in capturing mode, a panic is raised! + fn have_type_ref(&'t self) -> AssertThat<'t, &'t E, M> { + self.has_type_ref() + } } impl<'t, M: Mode> PanicValueAssertions<'t, M> for AssertThat<'t, PanicValue, M> { @@ -72,13 +84,13 @@ mod tests { fn succeeds_when_type_matches() { let actual = PanicValue(Box::new(String::from("foo"))); - assert_that_ref(&actual) - .has_type::() - .is_equal_to(String::from("foo")); + actual.must() + .have_type::() + .be_equal_to(String::from("foo")); - assert_that(actual) - .has_type::() - .is_equal_to(String::from("foo")); + actual.must() + .have_type::() + .be_equal_to(String::from("foo")); } #[test] @@ -86,7 +98,7 @@ mod tests { let actual = PanicValue(Box::new(String::from("foo"))); assert_that_panic_by(|| { - assert_that(actual).with_location(false).has_type::(); + actual.must().with_location(false).have_type::(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -107,7 +119,7 @@ mod tests { fn succeeds_when_type_matches() { let actual = PanicValue(Box::new(String::from("foo"))); - assert_that(actual) + assert_that!(actual) .has_type_ref::() .is_equal_to(&String::from("foo")); } @@ -117,7 +129,7 @@ mod tests { let actual = PanicValue(Box::new(String::from("foo"))); assert_that_panic_by(|| { - assert_that(actual) + assert_that!(actual) .with_location(false) .has_type_ref::(); }) @@ -136,7 +148,7 @@ mod tests { let actual = PanicValue(Box::new("foo")); assert_that_panic_by(|| { - assert_that(actual) + assert_that!(actual) .with_location(false) .has_type_ref::(); }) @@ -156,7 +168,7 @@ mod tests { let actual = PanicValue(Box::new(Foo {})); assert_that_panic_by(|| { - assert_that(actual) + assert_that!(actual) .with_location(false) .has_type_ref::(); }) diff --git a/assertr/src/assertions/alloc/string.rs b/assertr/src/assertions/alloc/string.rs index e882e1c..4da266d 100644 --- a/assertr/src/assertions/alloc/string.rs +++ b/assertr/src/assertions/alloc/string.rs @@ -5,49 +5,49 @@ use crate::{AssertThat, Mode}; /// Assertions for heap-allocated, owned [String]s. pub trait StringAssertions { - fn contain(self, expected: impl AsRef) -> Self; + fn contains(self, expected: impl AsRef) -> Self; - fn contains(self, expected: impl AsRef) -> Self + fn contain(self, expected: impl AsRef) -> Self where Self: Sized, { - self.contain(expected) + self.contains(expected) } - fn start_with(self, expected: impl AsRef) -> Self; + fn starts_with(self, expected: impl AsRef) -> Self; - fn starts_with(self, expected: impl AsRef) -> Self + fn start_with(self, expected: impl AsRef) -> Self where Self: Sized, { - self.start_with(expected) + self.starts_with(expected) } - fn end_with(self, expected: impl AsRef) -> Self; + fn ends_with(self, expected: impl AsRef) -> Self; - fn ends_with(self, expected: impl AsRef) -> Self + fn end_with(self, expected: impl AsRef) -> Self where Self: Sized, { - self.end_with(expected) + self.ends_with(expected) } } impl StringAssertions for AssertThat<'_, String, M> { #[track_caller] - fn contain(self, expected: impl AsRef) -> Self { + fn contains(self, expected: impl AsRef) -> Self { self.derive(|actual| actual.as_str()).contains(expected); self } #[track_caller] - fn start_with(self, expected: impl AsRef) -> Self { + fn starts_with(self, expected: impl AsRef) -> Self { self.derive(|actual| actual.as_str()).starts_with(expected); self } #[track_caller] - fn end_with(self, expected: impl AsRef) -> Self { + fn ends_with(self, expected: impl AsRef) -> Self { self.derive(|actual| actual.as_str()).ends_with(expected); self } @@ -55,7 +55,7 @@ impl StringAssertions for AssertThat<'_, String, M> { #[cfg(test)] mod tests { - mod contain { + mod contains { use crate::prelude::*; use indoc::formatdoc; @@ -69,7 +69,7 @@ mod tests { #[test] fn panics_when_expected_is_not_contained() { assert_that_panic_by(|| { - assert_that(String::from("foo bar baz")) + assert_that!(String::from("foo bar baz")) .with_location(false) .contains("42"); }) @@ -86,7 +86,7 @@ mod tests { } } - mod start_with { + mod starts_with { use crate::prelude::*; use indoc::formatdoc; @@ -98,7 +98,7 @@ mod tests { #[test] fn panics_when_start_is_different() { assert_that_panic_by(|| { - assert_that(String::from("foo bar baz")) + assert_that!(String::from("foo bar baz")) .with_location(false) .starts_with("oo"); }) @@ -115,7 +115,7 @@ mod tests { } } - mod end_with { + mod ends_with { use crate::prelude::*; use indoc::formatdoc; @@ -127,7 +127,7 @@ mod tests { #[test] fn panics_when_start_is_different() { assert_that_panic_by(|| { - assert_that(String::from("foo bar baz")) + assert_that!(String::from("foo bar baz")) .with_location(false) .ends_with("raz"); }) diff --git a/assertr/src/assertions/alloc/vec.rs b/assertr/src/assertions/alloc/vec.rs index bea2e21..6b97fc8 100644 --- a/assertr/src/assertions/alloc/vec.rs +++ b/assertr/src/assertions/alloc/vec.rs @@ -4,52 +4,52 @@ use core::fmt::Debug; use crate::{AssertThat, AssertrPartialEq, Mode, prelude::SliceAssertions}; pub trait VecAssertions<'t, T: Debug> { - fn contain(self, expected: E) -> Self + fn contains(self, expected: E) -> Self where E: Debug, T: AssertrPartialEq + Debug; - fn contains(self, expected: E) -> Self + fn contain(self, expected: E) -> Self where E: Debug, T: AssertrPartialEq + Debug, Self: Sized, { - self.contain(expected) + self.contains(expected) } - fn contain_exactly(self, expected: impl AsRef<[E]>) -> Self + fn contains_exactly(self, expected: impl AsRef<[E]>) -> Self where E: Debug + 't, T: AssertrPartialEq + Debug; - fn contains_exactly(self, expected: impl AsRef<[E]>) -> Self + fn contain_exactly(self, expected: impl AsRef<[E]>) -> Self where E: Debug + 't, T: AssertrPartialEq + Debug, Self: Sized, { - self.contain_exactly(expected) + self.contains_exactly(expected) } /// [P] - Predicate - fn contain_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self + fn contains_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self where P: Fn(&T) -> bool; /// [P] - Predicate - fn contains_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self + fn contain_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self where P: Fn(&T) -> bool, Self: Sized, { - self.contain_exactly_matching_in_any_order(expected) + self.contains_exactly_matching_in_any_order(expected) } } impl<'t, T: Debug, M: Mode> VecAssertions<'t, T> for AssertThat<'t, Vec, M> { #[track_caller] - fn contain(self, expected: E) -> Self + fn contains(self, expected: E) -> Self where E: Debug, T: AssertrPartialEq + Debug, @@ -59,7 +59,7 @@ impl<'t, T: Debug, M: Mode> VecAssertions<'t, T> for AssertThat<'t, Vec, M> { } #[track_caller] - fn contain_exactly(self, expected: impl AsRef<[E]>) -> Self + fn contains_exactly(self, expected: impl AsRef<[E]>) -> Self where E: Debug + 't, T: AssertrPartialEq + Debug, @@ -69,7 +69,7 @@ impl<'t, T: Debug, M: Mode> VecAssertions<'t, T> for AssertThat<'t, Vec, M> { } #[track_caller] - fn contain_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self + fn contains_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self where T: Debug, P: Fn(&T) -> bool; + + /// [P] - Predicate + fn contain_exactly_matching_in_any_order

(self, expected: impl AsRef<[P]>) -> Self + where + T: Debug, + P: Fn(&T) -> bool, + Self: Sized, + { + self.contains_exactly_matching_in_any_order(expected) + } } impl<'t, T, M: Mode> SliceAssertions<'t, T> for AssertThat<'t, &[T], M> { @@ -120,8 +162,6 @@ impl<'t, T, M: Mode> SliceAssertions<'t, T> for AssertThat<'t, &[T], M> { if !elements_not_found.is_empty() || !elements_not_expected.is_empty() { self.fail(format_args!( "Actual: {actual:#?},\n\nElements expected: {expected:#?}\n\nElements not found: {elements_not_found:#?}\n\nElements not expected: {elements_not_expected:#?}\n", - actual = actual, - expected = expected )); } self @@ -157,36 +197,48 @@ impl<'t, T, M: Mode> SliceAssertions<'t, T> for AssertThat<'t, &[T], M> { #[cfg(test)] mod tests { mod contains_exactly { - use indoc::formatdoc; - use crate::prelude::*; + use indoc::formatdoc; #[test] fn succeeds_when_exact_match() { - assert_that([1, 2, 3].as_slice()).contains_exactly([1, 2, 3]); + [1, 2, 3].as_slice().must().contain_exactly([1, 2, 3]); } #[test] fn compiles_for_different_type_combinations() { - assert_that(["foo".to_owned()].as_slice()).contains_exactly(["foo"]); - assert_that(["foo"].as_slice()).contains_exactly(["foo"]); - assert_that(["foo"].as_slice()).contains_exactly(["foo".to_owned()]); - assert_that(["foo"].as_slice()).contains_exactly(vec!["foo".to_owned()]); - assert_that(vec!["foo"].as_slice()) - .contains_exactly(vec!["foo".to_owned()].into_iter()); + ["foo".to_owned()] + .as_slice() + .must() + .contain_exactly(["foo"]); + ["foo"].as_slice().must().contain_exactly(["foo"]); + ["foo"] + .as_slice() + .must() + .contain_exactly(["foo".to_owned()]); + ["foo"] + .as_slice() + .must() + .contain_exactly(vec!["foo".to_owned()]); + vec!["foo"] + .as_slice() + .must() + .contain_exactly(vec!["foo".to_owned()].into_iter()); } #[test] fn succeeds_when_exact_match_provided_as_slice() { - assert_that([1, 2, 3].as_slice()).contains_exactly(&[1, 2, 3]); + [1, 2, 3].as_slice().must().contain_exactly(&[1, 2, 3]); } #[test] fn panics_when_not_exact_match() { assert_that_panic_by(|| { - assert_that([1, 2, 3].as_slice()) + [1, 2, 3] + .as_slice() + .must() .with_location(false) - .contains_exactly([2, 3, 4]) + .contain_exactly([2, 3, 4]); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -220,9 +272,11 @@ mod tests { #[test] fn panics_with_detail_message_when_only_differing_in_order() { assert_that_panic_by(|| { - assert_that([1, 2, 3].as_slice()) + [1, 2, 3] + .as_slice() + .must() .with_location(false) - .contains_exactly([3, 2, 1]) + .contain_exactly([3, 2, 1]); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -250,21 +304,25 @@ mod tests { } mod contains_exactly_in_any_order { - use indoc::formatdoc; - use crate::prelude::*; + use indoc::formatdoc; #[test] fn succeeds_when_slices_match() { - assert_that([1, 2, 3].as_slice()).contains_exactly_in_any_order([2, 3, 1]); + [1, 2, 3] + .as_slice() + .must() + .contain_exactly_in_any_order([2, 3, 1]); } #[test] fn panics_when_slice_contains_unknown_data() { assert_that_panic_by(|| { - assert_that([1, 2, 3].as_slice()) + [1, 2, 3] + .as_slice() + .must() .with_location(false) - .contains_exactly_in_any_order([2, 3, 4]) + .contain_exactly_in_any_order([2, 3, 4]); }) .has_type::() .is_equal_to(formatdoc! {" @@ -294,47 +352,54 @@ mod tests { } mod contains_exactly_matching_in_any_order { - use indoc::formatdoc; - use crate::prelude::*; + use indoc::formatdoc; #[test] fn succeeds_when_slices_match() { - assert_that([1, 2, 3].as_slice()).contains_exactly_matching_in_any_order( - [ - move |it: &i32| *it == 1, - move |it: &i32| *it == 2, - move |it: &i32| *it == 3, - ] - .as_slice(), - ); + [1, 2, 3] + .as_slice() + .must() + .contain_exactly_matching_in_any_order( + [ + move |it: &i32| *it == 1, + move |it: &i32| *it == 2, + move |it: &i32| *it == 3, + ] + .as_slice(), + ); } #[test] fn succeeds_when_slices_match_in_different_order() { - assert_that([1, 2, 3].as_slice()).contains_exactly_matching_in_any_order( - [ - move |it: &i32| *it == 3, - move |it: &i32| *it == 1, - move |it: &i32| *it == 2, - ] - .as_slice(), - ); + [1, 2, 3] + .as_slice() + .must() + .contain_exactly_matching_in_any_order( + [ + move |it: &i32| *it == 3, + move |it: &i32| *it == 1, + move |it: &i32| *it == 2, + ] + .as_slice(), + ); } #[test] fn panics_when_slice_contains_non_matching_data() { assert_that_panic_by(|| { - assert_that([1, 2, 3].as_slice()) + [1, 2, 3] + .as_slice() + .must() .with_location(false) - .contains_exactly_matching_in_any_order( + .contain_exactly_matching_in_any_order( [ move |it: &i32| *it == 2, move |it: &i32| *it == 3, move |it: &i32| *it == 4, ] .as_slice(), - ) + ); }) .has_type::() .is_equal_to(formatdoc! {" diff --git a/assertr/src/assertions/core/str_slice.rs b/assertr/src/assertions/core/str_slice.rs index f3924e0..3cbaa89 100644 --- a/assertr/src/assertions/core/str_slice.rs +++ b/assertr/src/assertions/core/str_slice.rs @@ -10,14 +10,50 @@ pub trait StrSliceAssertions { /// `White_Space`. fn is_blank(self) -> Self; + /// Tests whether this string is empty or only containing whitespace characters. + /// 'Whitespace' is defined according to the terms of the Unicode Derived Core Property + /// `White_Space`. + fn be_blank(self) -> Self + where + Self: Sized, + { + self.is_blank() + } + /// Tests whether this string is empty or only containing ascii-whitespace characters. fn is_blank_ascii(self) -> Self; + /// Tests whether this string is empty or only containing ascii-whitespace characters. + fn be_blank_ascii(self) -> Self + where + Self: Sized, + { + self.is_blank_ascii() + } + fn contains(self, expected: impl AsRef) -> Self; + fn contain(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.contains(expected) + } fn starts_with(self, expected: impl AsRef) -> Self; + fn start_with(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.starts_with(expected) + } fn ends_with(self, expected: impl AsRef) -> Self; + fn end_with(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.ends_with(expected) + } } impl StrSliceAssertions for AssertThat<'_, &str, M> { @@ -29,9 +65,9 @@ impl StrSliceAssertions for AssertThat<'_, &str, M> { self.fail(|w: &mut String| { writedoc! {w, r#" Actual: {actual:?} - + contains non-whitespace characters. - + Expected it to be empty or only containing whitespace. "#, actual = self.actual()} }); @@ -47,9 +83,9 @@ impl StrSliceAssertions for AssertThat<'_, &str, M> { self.fail(|w: &mut String| { writedoc! {w, r#" Actual: {actual:?} - + contains non-whitespace characters. - + Expected it to be empty or only containing whitespace. "#, actual = self.actual()} }); @@ -108,15 +144,15 @@ mod tests { #[test] fn succeeds_when_expected_is_blank() { - assert_that("").is_blank(); - assert_that(" ").is_blank(); - assert_that("\t \n").is_blank(); + "".must().be_blank(); + " ".must().be_blank(); + "\t \n".must().be_blank(); } #[test] fn panics_when_expected_is_not_blank() { assert_that_panic_by(|| { - assert_that("a").with_location(false).is_blank(); + "a".must().with_location(false).be_blank(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -136,16 +172,16 @@ mod tests { use indoc::formatdoc; #[test] - fn succeeds_when_expected_is_blank() { - assert_that("").is_blank_ascii(); - assert_that(" ").is_blank_ascii(); - assert_that("\t \n").is_blank_ascii(); + fn succeeds_when_blank() { + "".must().be_blank_ascii(); + " ".must().be_blank_ascii(); + "\t \n".must().be_blank_ascii(); } #[test] - fn panics_when_expected_is_not_blank() { + fn panics_when_not_blank() { assert_that_panic_by(|| { - assert_that("a").with_location(false).is_blank_ascii(); + "a".must().with_location(false).be_blank_ascii(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -166,17 +202,15 @@ mod tests { #[test] fn succeeds_when_expected_is_contained() { - assert_that("foobar").contains("foo"); - assert_that("foobar").contains("bar"); - assert_that("foobar").contains("oob"); + "foobar".must().contain("foo"); + "foobar".must().contain("bar"); + "foobar".must().contain("oob"); } #[test] fn panics_when_expected_is_not_contained() { assert_that_panic_by(|| { - assert_that("foo bar baz") - .with_location(false) - .contains("42"); + "foo bar baz".must().with_location(false).contain("42"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -197,15 +231,13 @@ mod tests { #[test] fn succeeds_when_start_matches() { - assert_that("foo bar baz").starts_with("foo b"); + "foo bar baz".must().start_with("foo b"); } #[test] fn panics_when_start_is_different() { assert_that_panic_by(|| { - assert_that("foo bar baz") - .with_location(false) - .starts_with("oo"); + "foo bar baz".must().with_location(false).start_with("oo"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -226,15 +258,13 @@ mod tests { #[test] fn succeeds_when_start_matches() { - assert_that("foo bar baz").ends_with("r baz"); + "foo bar baz".must().end_with("r baz"); } #[test] fn panics_when_start_is_different() { assert_that_panic_by(|| { - assert_that("foo bar baz") - .with_location(false) - .ends_with("raz"); + "foo bar baz".must().with_location(false).end_with("raz"); }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/jiff/signed_duration.rs b/assertr/src/assertions/jiff/signed_duration.rs index f500f28..0d80982 100644 --- a/assertr/src/assertions/jiff/signed_duration.rs +++ b/assertr/src/assertions/jiff/signed_duration.rs @@ -7,12 +7,36 @@ use std::fmt::Write; pub trait SignedDurationAssertions { fn is_zero(self) -> Self; + fn be_zero(self) -> Self + where + Self: Sized, + { + self.is_zero() + } fn is_negative(self) -> Self; + fn be_negative(self) -> Self + where + Self: Sized, + { + self.is_negative() + } fn is_positive(self) -> Self; + fn be_positive(self) -> Self + where + Self: Sized, + { + self.is_positive() + } fn is_close_to(self, expected: SignedDuration, allowed_deviation: SignedDuration) -> Self; + fn be_close_to(self, expected: SignedDuration, allowed_deviation: SignedDuration) -> Self + where + Self: Sized, + { + self.is_close_to(expected, allowed_deviation) + } } impl SignedDurationAssertions for AssertThat<'_, SignedDuration, M> { @@ -102,16 +126,18 @@ mod tests { #[test] fn succeeds_when_zero() { - assert_that(SignedDuration::ZERO).is_zero(); + SignedDuration::ZERO.must().be_zero(); } #[test] fn panics_when_not_zero() { let duration: SignedDuration = "2h 30m".parse().unwrap(); - assert_that_panic_by(|| assert_that(duration).with_location(false).is_zero()) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| { + duration.assert().with_location(false).is_zero(); + }) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Expected: 0s @@ -133,12 +159,13 @@ mod tests { #[test] fn panics_when_below_allowed_range() { assert_that_panic_by(|| { - assert_that(SignedDuration::from_secs_f32(0.3319)) + SignedDuration::from_secs_f32(0.3319) + .assert() .with_location(false) .is_close_to( SignedDuration::from_secs_f32(0.333), SignedDuration::from_secs_f32(0.001), - ) + ); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -154,15 +181,15 @@ mod tests { #[test] fn succeeds_when_actual_is_in_allowed_range() { - assert_that(SignedDuration::from_secs_f32(0.332)).is_close_to( + SignedDuration::from_secs_f32(0.332).must().be_close_to( SignedDuration::from_secs_f32(0.333), SignedDuration::from_secs_f32(0.001), ); - assert_that(SignedDuration::from_secs_f32(0.333)).is_close_to( + SignedDuration::from_secs_f32(0.333).must().be_close_to( SignedDuration::from_secs_f32(0.333), SignedDuration::from_secs_f32(0.001), ); - assert_that(SignedDuration::from_secs_f32(0.334)).is_close_to( + SignedDuration::from_secs_f32(0.334).must().be_close_to( SignedDuration::from_secs_f32(0.333), SignedDuration::from_secs_f32(0.001), ); @@ -171,12 +198,13 @@ mod tests { #[test] fn panics_when_above_allowed_range() { assert_that_panic_by(|| { - assert_that(SignedDuration::from_secs_f32(0.3341)) + SignedDuration::from_secs_f32(0.3341) + .assert() .with_location(false) .is_close_to( SignedDuration::from_secs_f32(0.333), SignedDuration::from_secs_f32(0.001), - ) + ); }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/jiff/span.rs b/assertr/src/assertions/jiff/span.rs index 85e598b..d8f9156 100644 --- a/assertr/src/assertions/jiff/span.rs +++ b/assertr/src/assertions/jiff/span.rs @@ -8,10 +8,32 @@ use std::fmt::Write; pub trait SpanAssertions { fn is_zero(self) -> Self; + fn be_zero(self) -> Self + where + Self: Sized, + { + self.is_zero() + } + fn is_negative(self) -> Self; + fn be_negative(self) -> Self + where + Self: Sized, + { + self.is_negative() + } + /// Unlike the is_positive assertions on numerics, this fails for a span of 0! fn is_positive(self) -> Self; + + /// Unlike the is_positive assertions on numerics, this fails for a span of 0! + fn be_positive(self) -> Self + where + Self: Sized, + { + self.is_positive() + } } impl SpanAssertions for AssertThat<'_, Span, M> { @@ -79,14 +101,14 @@ mod tests { #[test] fn succeeds_when_zero() { - assert_that(Span::new()).is_zero(); + Span::new().must().be_zero(); } #[test] fn panics_when_not_zero() { let duration: Span = 2.hours().minutes(30); - assert_that_panic_by(|| assert_that(duration).with_location(false).is_zero()) + assert_that_panic_by(|| duration.assert().with_location(false).is_zero()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -109,14 +131,16 @@ mod tests { #[test] fn succeeds_when_zero() { - assert_that(-2.hours().minutes(30)).is_negative(); + (-2).hours().minutes(30).must().be_negative(); } #[test] fn panics_when_zero() { - assert_that_panic_by(|| assert_that(0.seconds()).with_location(false).is_negative()) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| { + 0.seconds().assert().with_location(false).is_negative(); + }) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Expected value to be negative. But was @@ -128,9 +152,11 @@ mod tests { #[test] fn panics_when_positive() { assert_that_panic_by(|| { - assert_that(2.hours().minutes(30)) + 2.hours() + .minutes(30) + .assert() .with_location(false) - .is_negative() + .is_negative(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -150,14 +176,16 @@ mod tests { #[test] fn succeeds_when_positive() { - assert_that(2.hours().minutes(30)).is_positive(); + 2.hours().minutes(30).must().be_positive(); } #[test] fn panics_when_zero() { - assert_that_panic_by(|| assert_that(0.seconds()).with_location(false).is_positive()) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| { + 0.seconds().assert().with_location(false).is_positive(); + }) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Expected value to be positive. But was @@ -169,9 +197,11 @@ mod tests { #[test] fn panics_when_negative() { assert_that_panic_by(|| { - assert_that(-2.hours().minutes(30)) + (-2).hours() + .minutes(30) + .assert() .with_location(false) - .is_positive() + .is_positive(); }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/jiff/zoned.rs b/assertr/src/assertions/jiff/zoned.rs index fb1e5de..b4fc9d1 100644 --- a/assertr/src/assertions/jiff/zoned.rs +++ b/assertr/src/assertions/jiff/zoned.rs @@ -10,7 +10,21 @@ use std::fmt::Write; pub trait ZonedAssertions { fn is_in_time_zone(self, expected: impl Borrow) -> Self; + fn be_in_time_zone(self, expected: impl Borrow) -> Self + where + Self: Sized, + { + self.is_in_time_zone(expected) + } + fn is_in_time_zone_named(self, expected: impl AsRef) -> Self; + + fn be_in_time_zone_named(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.is_in_time_zone_named(expected) + } } impl ZonedAssertions for AssertThat<'_, Zoned, M> { @@ -91,7 +105,7 @@ mod tests { fn succeeds_when_matches() { let zdt: Zoned = "2024-06-19 15:22[America/New_York]".parse().expect("valid"); let tz = TimeZone::get("America/New_York").expect("valid"); - assert_that(zdt).is_in_time_zone(tz); + zdt.must().be_in_time_zone(tz); } #[test] @@ -99,9 +113,11 @@ mod tests { let zdt: Zoned = "2024-06-19 15:22[America/New_York]".parse().expect("valid"); let tz = TimeZone::get("Europe/Berlin").expect("valid"); - assert_that_panic_by(|| assert_that(zdt).with_location(false).is_in_time_zone(tz)) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| { + zdt.assert().with_location(false).is_in_time_zone(tz); + }) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Expected: Europe/Berlin @@ -121,16 +137,16 @@ mod tests { #[test] fn succeeds_when_matches() { let zdt: Zoned = "2024-06-19 15:22[America/New_York]".parse().expect("valid"); - assert_that(zdt).is_in_time_zone_named("America/New_York"); + zdt.must().be_in_time_zone_named("America/New_York"); } #[test] fn panics_when_in_different_time_zone() { let zdt: Zoned = "2024-06-19 15:22[America/New_York]".parse().expect("valid"); assert_that_panic_by(|| { - assert_that(zdt) + zdt.assert() .with_location(false) - .is_in_time_zone_named("Europe/Berlin") + .is_in_time_zone_named("Europe/Berlin"); }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/mod.rs b/assertr/src/assertions/mod.rs index 4205412..a477f70 100644 --- a/assertr/src/assertions/mod.rs +++ b/assertr/src/assertions/mod.rs @@ -136,11 +136,7 @@ impl HasLength for &::std::collections::HashSet { impl HasLength for Range { fn length(&self) -> usize { - if self.start < self.end { - self.end - self.start - } else { - self.start - self.end - } + self.end.abs_diff(self.start) } } @@ -260,12 +256,12 @@ mod tests { #[test] fn works_on_range_and_inclusive_range() { - assert_that(1_usize..9_usize).has_length(8); - assert_that(1_usize..=9_usize).has_length(9); + assert_that!(1_usize..9_usize).has_length(8); + assert_that!(1_usize..=9_usize).has_length(9); // inverted range - assert_that(9_usize..1_usize).has_length(8); - assert_that(9_usize..=1_usize).has_length(9); + assert_that!(9_usize..1_usize).has_length(8); + assert_that!(9_usize..=1_usize).has_length(9); } } @@ -274,12 +270,12 @@ mod tests { #[test] fn works_on_range_and_inclusive_range() { - assert_that(1_u8..9_u8).has_length(8); - assert_that(1_u8..=9_u8).has_length(9); + assert_that!(1_u8..9_u8).has_length(8); + assert_that!(1_u8..=9_u8).has_length(9); // inverted range - assert_that(9_u8..1_u8).has_length(8); - assert_that(9_u8..=1_u8).has_length(9); + assert_that!(9_u8..1_u8).has_length(8); + assert_that!(9_u8..=1_u8).has_length(9); } } @@ -288,12 +284,12 @@ mod tests { #[test] fn works_on_range_and_inclusive_range() { - assert_that(1_u16..9_u16).has_length(8); - assert_that(1_u16..=9_u16).has_length(9); + assert_that!(1_u16..9_u16).has_length(8); + assert_that!(1_u16..=9_u16).has_length(9); // inverted range - assert_that(9_u16..1_u16).has_length(8); - assert_that(9_u16..=1_u16).has_length(9); + assert_that!(9_u16..1_u16).has_length(8); + assert_that!(9_u16..=1_u16).has_length(9); } } @@ -302,12 +298,12 @@ mod tests { #[test] fn works_on_range_and_inclusive_range() { - assert_that(1_u32..9_u32).has_length(8); - assert_that(1_u32..=9_u32).has_length(9); + assert_that!(1_u32..9_u32).has_length(8); + assert_that!(1_u32..=9_u32).has_length(9); // inverted range - assert_that(9_u32..1_u32).has_length(8); - assert_that(9_u32..=1_u32).has_length(9); + assert_that!(9_u32..1_u32).has_length(8); + assert_that!(9_u32..=1_u32).has_length(9); } } @@ -316,12 +312,12 @@ mod tests { #[test] fn works_on_range_and_inclusive_range() { - assert_that(1_u64..9_u64).has_length(8); - assert_that(1_u64..=9_u64).has_length(9); + assert_that!(1_u64..9_u64).has_length(8); + assert_that!(1_u64..=9_u64).has_length(9); // inverted range - assert_that(9_u64..1_u64).has_length(8); - assert_that(9_u64..=1_u64).has_length(9); + assert_that!(9_u64..1_u64).has_length(8); + assert_that!(9_u64..=1_u64).has_length(9); } } @@ -330,20 +326,20 @@ mod tests { #[test] fn works_on_range_and_inclusive_range() { - assert_that(1_i8..9_i8).has_length(8); - assert_that(1_i8..=9_i8).has_length(9); + assert_that!(1_i8..9_i8).has_length(8); + assert_that!(1_i8..=9_i8).has_length(9); // inverted range - assert_that(9_i8..1_i8).has_length(8); - assert_that(9_i8..=1_i8).has_length(9); + assert_that!(9_i8..1_i8).has_length(8); + assert_that!(9_i8..=1_i8).has_length(9); // negative range - assert_that(-9_i8..-1_i8).has_length(8); - assert_that(-9_i8..=-1_i8).has_length(9); + assert_that!(-9_i8..-1_i8).has_length(8); + assert_that!(-9_i8..=-1_i8).has_length(9); // across zero - assert_that(-4_i8..4_i8).has_length(8); - assert_that(-4_i8..=4_i8).has_length(9); + assert_that!(-4_i8..4_i8).has_length(8); + assert_that!(-4_i8..=4_i8).has_length(9); } } @@ -352,20 +348,20 @@ mod tests { #[test] fn works_on_range_and_inclusive_range() { - assert_that(1_i16..9_i16).has_length(8); - assert_that(1_i16..=9_i16).has_length(9); + assert_that!(1_i16..9_i16).has_length(8); + assert_that!(1_i16..=9_i16).has_length(9); // inverted range - assert_that(9_i16..1_i16).has_length(8); - assert_that(9_i16..=1_i16).has_length(9); + assert_that!(9_i16..1_i16).has_length(8); + assert_that!(9_i16..=1_i16).has_length(9); // negative range - assert_that(-9_i16..-1_i16).has_length(8); - assert_that(-9_i16..=-1_i16).has_length(9); + assert_that!(-9_i16..-1_i16).has_length(8); + assert_that!(-9_i16..=-1_i16).has_length(9); // across zero - assert_that(-4_i16..4_i16).has_length(8); - assert_that(-4_i16..=4_i16).has_length(9); + assert_that!(-4_i16..4_i16).has_length(8); + assert_that!(-4_i16..=4_i16).has_length(9); } } @@ -374,20 +370,20 @@ mod tests { #[test] fn works_on_range_and_inclusive_range() { - assert_that(1_i32..9_i32).has_length(8); - assert_that(1_i32..=9_i32).has_length(9); + assert_that!(1_i32..9_i32).has_length(8); + assert_that!(1_i32..=9_i32).has_length(9); // inverted range - assert_that(9_i32..1_i32).has_length(8); - assert_that(9_i32..=1_i32).has_length(9); + assert_that!(9_i32..1_i32).has_length(8); + assert_that!(9_i32..=1_i32).has_length(9); // negative range - assert_that(-9_i32..-1_i32).has_length(8); - assert_that(-9_i32..=-1_i32).has_length(9); + assert_that!(-9_i32..-1_i32).has_length(8); + assert_that!(-9_i32..=-1_i32).has_length(9); // across zero - assert_that(-4_i32..4_i32).has_length(8); - assert_that(-4_i32..=4_i32).has_length(9); + assert_that!(-4_i32..4_i32).has_length(8); + assert_that!(-4_i32..=4_i32).has_length(9); } } @@ -396,20 +392,20 @@ mod tests { #[test] fn works_on_range_and_inclusive_range() { - assert_that(1_i64..9_i64).has_length(8); - assert_that(1_i64..=9_i64).has_length(9); + assert_that!(1_i64..9_i64).has_length(8); + assert_that!(1_i64..=9_i64).has_length(9); // inverted range - assert_that(9_i64..1_i64).has_length(8); - assert_that(9_i64..=1_i64).has_length(9); + assert_that!(9_i64..1_i64).has_length(8); + assert_that!(9_i64..=1_i64).has_length(9); // negative range - assert_that(-9_i64..-1_i64).has_length(8); - assert_that(-9_i64..=-1_i64).has_length(9); + assert_that!(-9_i64..-1_i64).has_length(8); + assert_that!(-9_i64..=-1_i64).has_length(9); // across zero - assert_that(-4_i64..4_i64).has_length(8); - assert_that(-4_i64..=4_i64).has_length(9); + assert_that!(-4_i64..4_i64).has_length(8); + assert_that!(-4_i64..=4_i64).has_length(9); } } } diff --git a/assertr/src/assertions/num/mod.rs b/assertr/src/assertions/num/mod.rs index e2966af..69c8b51 100644 --- a/assertr/src/assertions/num/mod.rs +++ b/assertr/src/assertions/num/mod.rs @@ -12,35 +12,63 @@ pub trait NumAssertions { /// Fails if actual is not equal to the additive identity. fn is_zero(self) -> Self; + /// Fails if actual is not equal to the additive identity. + fn be_zero(self) -> Self + where + Self: Sized, + { + self.is_zero() + } + fn is_additive_identity(self) -> Self; + fn be_additive_identity(self) -> Self + where + Self: Sized, + { + self.is_additive_identity() + } /// Fails if actual is not equal to the multiplicative identity. fn is_one(self) -> Self; + /// Fails if actual is not equal to the multiplicative identity. + fn be_one(self) -> Self + where + Self: Sized, + { + self.is_one() + } + fn is_multiplicative_identity(self) -> Self; + fn be_multiplicative_identity(self) -> Self + where + Self: Sized, + { + self.is_multiplicative_identity() + } - fn be_negative(self) -> Self + fn is_negative(self) -> Self where T: Signed; - fn is_negative(self) -> Self + fn be_negative(self) -> Self where T: Signed, Self: Sized, { - self.be_negative() + self.is_negative() } - fn be_positive(self) -> Self + fn is_positive(self) -> Self where T: Signed; - fn is_positive(self) -> Self + fn be_positive(self) -> Self where T: Signed, Self: Sized, { - self.be_positive() + self.is_positive() } /// Fails if actual is not in the range @@ -50,20 +78,55 @@ pub trait NumAssertions { T: PartialOrd, T: Clone; + /// Fails if actual is not in the range + /// `[expected - allowed_deviation, expected + allowed_deviation]`. + fn be_close_to(self, expected: T, allowed_deviation: T) -> Self + where + T: PartialOrd, + T: Clone, + Self: Sized, + { + self.is_close_to(expected, allowed_deviation) + } + #[cfg(any(feature = "std", feature = "libm"))] fn is_nan(self) -> Self where T: Float; + #[cfg(any(feature = "std", feature = "libm"))] + fn be_nan(self) -> Self + where + T: Float, + Self: Sized, + { + self.is_nan() + } #[cfg(any(feature = "std", feature = "libm"))] fn is_finite(self) -> Self where T: Float; + #[cfg(any(feature = "std", feature = "libm"))] + fn be_finite(self) -> Self + where + T: Float, + Self: Sized, + { + self.is_finite() + } #[cfg(any(feature = "std", feature = "libm"))] fn is_infinite(self) -> Self where T: Float; + #[cfg(any(feature = "std", feature = "libm"))] + fn be_infinite(self) -> Self + where + T: Float, + Self: Sized, + { + self.is_infinite() + } // TODO: is_normal // TODO: is_subnormal @@ -123,7 +186,7 @@ impl NumAssertions for AssertThat<'_, T, M> { } #[track_caller] - fn be_negative(self) -> Self + fn is_negative(self) -> Self where T: Signed, { @@ -142,7 +205,7 @@ impl NumAssertions for AssertThat<'_, T, M> { } #[track_caller] - fn be_positive(self) -> Self + fn is_positive(self) -> Self where T: Signed, { @@ -254,50 +317,50 @@ mod tests { use crate::prelude::*; use ::num::Float; - assert_that(0u8).is_zero(); - assert_that(0i8).is_zero(); - assert_that(0u16).is_zero(); - assert_that(0i16).is_zero(); - assert_that(0u32).is_zero(); - assert_that(0i32).is_zero(); - assert_that(0u64).is_zero(); - assert_that(0i64).is_zero(); - assert_that(0u128).is_zero(); - assert_that(0i128).is_zero(); - assert_that(0.0f32).is_zero(); - assert_that(0.0f64).is_zero(); - - assert_that(1u8).is_one(); - assert_that(1i8).is_one(); - assert_that(1u16).is_one(); - assert_that(1i16).is_one(); - assert_that(1u32).is_one(); - assert_that(1i32).is_one(); - assert_that(1u64).is_one(); - assert_that(1i64).is_one(); - assert_that(1u128).is_one(); - assert_that(1i128).is_one(); - assert_that(1.0f32).is_one(); - assert_that(1.0f64).is_one(); - - assert_that(42u8).is_close_to(42, 0); - assert_that(42i8).is_close_to(42, 0); - assert_that(42u16).is_close_to(42, 0); - assert_that(42i16).is_close_to(42, 0); - assert_that(42u32).is_close_to(42, 0); - assert_that(42i32).is_close_to(42, 0); - assert_that(42u64).is_close_to(42, 0); - assert_that(42i64).is_close_to(42, 0); - assert_that(42u128).is_close_to(42, 0); - assert_that(42i128).is_close_to(42, 0); - assert_that(0.2f32 + 0.1f32).is_close_to(0.3, 0.0001); - assert_that(0.2f64 + 0.1f64).is_close_to(0.3, 0.0001); - - assert_that(f32::nan()).is_nan(); - assert_that(f64::nan()).is_nan(); - - assert_that(f32::infinity()).is_infinite(); - assert_that(f64::infinity()).is_infinite(); + 0u8.must().be_zero(); + 0i8.must().be_zero(); + 0u16.must().be_zero(); + 0i16.must().be_zero(); + 0u32.must().be_zero(); + 0i32.must().be_zero(); + 0u64.must().be_zero(); + 0i64.must().be_zero(); + 0u128.must().be_zero(); + 0i128.must().be_zero(); + 0.0f32.must().be_zero(); + 0.0f64.must().be_zero(); + + 1u8.must().be_one(); + 1i8.must().be_one(); + 1u16.must().be_one(); + 1i16.must().be_one(); + 1u32.must().be_one(); + 1i32.must().be_one(); + 1u64.must().be_one(); + 1i64.must().be_one(); + 1u128.must().be_one(); + 1i128.must().be_one(); + 1.0f32.must().be_one(); + 1.0f64.must().be_one(); + + 42u8.must().be_close_to(42, 0); + 42i8.must().be_close_to(42, 0); + 42u16.must().be_close_to(42, 0); + 42i16.must().be_close_to(42, 0); + 42u32.must().be_close_to(42, 0); + 42i32.must().be_close_to(42, 0); + 42u64.must().be_close_to(42, 0); + 42i64.must().be_close_to(42, 0); + 42u128.must().be_close_to(42, 0); + 42i128.must().be_close_to(42, 0); + (0.2f32 + 0.1f32).must().be_close_to(0.3, 0.0001); + (0.2f64 + 0.1f64).must().be_close_to(0.3, 0.0001); + + f32::nan().must().be_nan(); + f64::nan().must().be_nan(); + + f32::infinity().must().be_infinite(); + f64::infinity().must().be_infinite(); } mod is_zero { @@ -306,12 +369,12 @@ mod tests { #[test] fn succeeds_when_zero() { - assert_that(0).is_zero(); + 0.must().be_zero(); } #[test] fn panics_when_not_zero() { - assert_that_panic_by(|| assert_that(3).with_location(false).is_zero()) + assert_that_panic_by(|| 3.must().with_location(false).be_zero()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -333,12 +396,12 @@ mod tests { #[test] fn succeeds_when_one() { - assert_that(1).is_one(); + 1.must().be_one(); } #[test] fn panics_when_not_one() { - assert_that_panic_by(|| assert_that(3).with_location(false).is_one()) + assert_that_panic_by(|| 3.must().with_location(false).be_one()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -360,12 +423,12 @@ mod tests { #[test] fn succeeds_when_zero() { - assert_that(-0.01).is_negative(); + (-0.01).must().be_negative(); } #[test] fn panics_when_zero() { - assert_that_panic_by(|| assert_that(0.0).with_location(false).is_negative()) + assert_that_panic_by(|| 0.0.must().with_location(false).be_negative()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -378,7 +441,7 @@ mod tests { #[test] fn panics_when_positive() { - assert_that_panic_by(|| assert_that(1.23).with_location(false).is_negative()) + assert_that_panic_by(|| 1.23.must().with_location(false).be_negative()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -396,17 +459,17 @@ mod tests { #[test] fn succeeds_when_positive() { - assert_that(0.01).is_positive(); + 0.01.must().be_positive(); } #[test] fn succeeds_when_zero() { - assert_that(0.0).is_positive(); + 0.0.must().be_positive(); } #[test] fn panics_when_negative() { - assert_that_panic_by(|| assert_that(-1.23).with_location(false).is_positive()) + assert_that_panic_by(|| (-1.23).must().with_location(false).be_positive()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -424,13 +487,9 @@ mod tests { #[test] fn panics_when_below_allowed_range() { - assert_that_panic_by(|| { - assert_that(0.3319) - .with_location(false) - .is_close_to(0.333, 0.001) - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| 0.3319.must().with_location(false).be_close_to(0.333, 0.001)) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Expected value to be close to: 0.333, with allowed deviation being: 0.001, @@ -443,20 +502,16 @@ mod tests { #[test] fn succeeds_when_actual_is_in_allowed_range() { - assert_that(0.332).is_close_to(0.333, 0.001); - assert_that(0.333).is_close_to(0.333, 0.001); - assert_that(0.334).is_close_to(0.333, 0.001); + 0.332.must().be_close_to(0.333, 0.001); + 0.333.must().be_close_to(0.333, 0.001); + 0.334.must().be_close_to(0.333, 0.001); } #[test] fn panics_when_above_allowed_range() { - assert_that_panic_by(|| { - assert_that(0.3341) - .with_location(false) - .is_close_to(0.333, 0.001) - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| 0.3341.must().with_location(false).be_close_to(0.333, 0.001)) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Expected value to be close to: 0.333, with allowed deviation being: 0.001, @@ -475,12 +530,12 @@ mod tests { #[test] fn succeeds_when_nan() { - assert_that(f32::nan()).is_nan(); + f32::nan().must().be_nan(); } #[test] fn panics_when_not_nan() { - assert_that_panic_by(|| assert_that(1.23).with_location(false).is_nan()) + assert_that_panic_by(|| 1.23.must().with_location(false).be_nan()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -499,15 +554,13 @@ mod tests { #[test] fn succeeds_when_finite() { - assert_that(0.3f32).is_finite(); + 0.3f32.must().be_finite(); } #[test] fn panics_when_positive_infinity() { assert_that_panic_by(|| { - assert_that(f32::infinity()) - .with_location(false) - .is_finite() + f32::infinity().must().with_location(false).be_finite(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -522,9 +575,7 @@ mod tests { #[test] fn panics_when_negative_infinity() { assert_that_panic_by(|| { - assert_that(f32::neg_infinity()) - .with_location(false) - .is_finite() + f32::neg_infinity().must().with_location(false).be_finite(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -544,17 +595,17 @@ mod tests { #[test] fn succeeds_when_positive_infinity() { - assert_that(f32::infinity()).is_infinite(); + f32::infinity().must().be_infinite(); } #[test] fn succeeds_when_negative_infinity() { - assert_that(f32::neg_infinity()).is_infinite(); + f32::neg_infinity().must().be_infinite(); } #[test] fn panics_when_not_infinity() { - assert_that_panic_by(|| assert_that(1.23).with_location(false).is_infinite()) + assert_that_panic_by(|| 1.23.must().with_location(false).be_infinite()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- diff --git a/assertr/src/assertions/reqwest/response.rs b/assertr/src/assertions/reqwest/response.rs index abd27f8..c205530 100644 --- a/assertr/src/assertions/reqwest/response.rs +++ b/assertr/src/assertions/reqwest/response.rs @@ -47,7 +47,7 @@ mod tests { .await .unwrap(); - assert_that(response).has_status_code(reqwest::StatusCode::OK); + assert_that!(response).has_status_code(reqwest::StatusCode::OK); } } } diff --git a/assertr/src/assertions/std/command.rs b/assertr/src/assertions/std/command.rs index ae38f41..c375019 100644 --- a/assertr/src/assertions/std/command.rs +++ b/assertr/src/assertions/std/command.rs @@ -28,7 +28,7 @@ mod tests { let mut cmd = Command::new("foo"); cmd.arg("--bar").arg("--baz"); - assert_that(cmd).has_arg("--bar").has_arg("--baz"); + assert_that!(cmd).has_arg("--bar").has_arg("--baz"); } #[test] @@ -37,7 +37,7 @@ mod tests { cmd.arg("--bar"); assert_that_panic_by(|| { - assert_that(cmd).with_location(false).has_arg("help"); + assert_that!(cmd).with_location(false).has_arg("help"); }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/std/hashmap.rs b/assertr/src/assertions/std/hashmap.rs index cfe96b9..64b25db 100644 --- a/assertr/src/assertions/std/hashmap.rs +++ b/assertr/src/assertions/std/hashmap.rs @@ -12,41 +12,59 @@ pub trait HashMapAssertions { K: Eq + Hash + Debug, V: Debug; + fn contain_key(self, expected: impl Borrow) -> Self + where + K: Eq + Hash + Debug, + V: Debug, + Self: Sized, + { + self.contains_key(expected) + } + fn does_not_contain_key(self, not_expected: impl Borrow) -> Self where K: Eq + Hash + Debug, V: Debug; - fn contain_value(self, expected: E) -> Self + fn not_contain_key(self, not_expected: impl Borrow) -> Self + where + K: Eq + Hash + Debug, + V: Debug, + Self: Sized, + { + self.does_not_contain_key(not_expected) + } + + fn contains_value(self, expected: E) -> Self where K: Debug, V: AssertrPartialEq + Debug, E: Debug; - fn contains_value(self, expected: E) -> Self + fn contain_value(self, expected: E) -> Self where K: Debug, V: AssertrPartialEq + Debug, E: Debug, Self: Sized, { - self.contain_value(expected) + self.contains_value(expected) } - fn contain_entry(self, key: impl Borrow, value: impl Borrow) -> Self + fn contains_entry(self, key: impl Borrow, value: impl Borrow) -> Self where K: Eq + Hash + Debug, V: AssertrPartialEq + Debug, E: Debug; - fn contains_entry(self, key: impl Borrow, value: impl Borrow) -> Self + fn contain_entry(self, key: impl Borrow, value: impl Borrow) -> Self where K: Eq + Hash + Debug, V: AssertrPartialEq + Debug, E: Debug, Self: Sized, { - self.contain_entry(key, value) + self.contains_entry(key, value) } } @@ -96,7 +114,7 @@ impl HashMapAssertions for AssertThat<'_, HashMap, M> } #[track_caller] - fn contain_value(self, expected: E) -> Self + fn contains_value(self, expected: E) -> Self where K: Debug, V: AssertrPartialEq + Debug, @@ -121,7 +139,7 @@ impl HashMapAssertions for AssertThat<'_, HashMap, M> } #[track_caller] - fn contain_entry(self, key: impl Borrow, value: impl Borrow) -> Self + fn contains_entry(self, key: impl Borrow, value: impl Borrow) -> Self where K: Eq + Hash + Debug, V: AssertrPartialEq + Debug, @@ -175,7 +193,7 @@ mod tests { fn succeeds_when_key_is_present() { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map).contains_key("foo"); + map.must().contain_key("foo"); } #[test] @@ -183,7 +201,7 @@ mod tests { assert_that_panic_by(|| { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map).with_location(false).contains_key("baz"); + map.must().with_location(false).contain_key("baz"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -209,7 +227,7 @@ mod tests { fn succeeds_when_key_is_absent() { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map).does_not_contain_key("baz"); + map.must().not_contain_key("baz"); } #[test] @@ -217,9 +235,7 @@ mod tests { assert_that_panic_by(|| { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map) - .with_location(false) - .does_not_contain_key("foo"); + map.must().with_location(false).not_contain_key("foo"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -245,7 +261,7 @@ mod tests { fn succeeds_when_value_is_present() { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map).contains_value("bar"); + map.must().contain_value("bar"); } #[test] @@ -253,7 +269,7 @@ mod tests { assert_that_panic_by(|| { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map).with_location(false).contains_value("baz"); + map.must().with_location(false).contains_value("baz"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -271,7 +287,7 @@ mod tests { fn compiles_with_any_type_comparable_to_the_actual_value_type() { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map).contains_value("bar".to_string()); + map.must().contain_value("bar".to_string()); } #[test] @@ -283,7 +299,7 @@ mod tests { let mut map = HashMap::new(); map.insert("foo", Data { data: 0 }); - map.must_ref().contain_value(Data { data: 0 }); + map.must().contain_value(Data { data: 0 }); map.must().contain_value(Data { data: 0 }); } } @@ -310,10 +326,9 @@ mod tests { } let mut map = HashMap::<&str, Person>::new(); map.insert("foo", Person { age: 42 }); - (&map).must().contain_entry("foo", &Person { age: 42 }); - (&map).must().contain_entry("foo", Person { age: 42 }); - (&map) - .must() + map.must().contain_entry("foo", &Person { age: 42 }); + map.must().contain_entry("foo", Person { age: 42 }); + map.must() .contain_entry("foo", Box::new(Person { age: 42 })); } diff --git a/assertr/src/assertions/std/mem.rs b/assertr/src/assertions/std/mem.rs index 17d0b88..dbdcf2d 100644 --- a/assertr/src/assertions/std/mem.rs +++ b/assertr/src/assertions/std/mem.rs @@ -5,6 +5,10 @@ use indoc::writedoc; /// Static memory assertions for any type. pub trait MemAssertions { fn needs_drop(self) -> Self; + + fn need_drop(self) -> Self where Self: Sized { + self.needs_drop() + } } impl MemAssertions for AssertThat<'_, Type, M> { diff --git a/assertr/src/assertions/std/mutex.rs b/assertr/src/assertions/std/mutex.rs index 23e16c6..8e81180 100644 --- a/assertr/src/assertions/std/mutex.rs +++ b/assertr/src/assertions/std/mutex.rs @@ -10,10 +10,28 @@ pub trait MutexAssertions { /// Note that implementations may try to acquire the lock in order to check its state. fn is_locked(self) -> Self; + /// Asserts that this mutex is locked. + /// Note that implementations may try to acquire the lock in order to check its state. + fn be_locked(self) -> Self + where + Self: Sized, + { + self.is_locked() + } + /// Asserts that this mutex is not locked. /// Note that implementations may try to acquire the lock in order to check its state. fn is_not_locked(self) -> Self; + /// Asserts that this mutex is not locked. + /// Note that implementations may try to acquire the lock in order to check its state. + fn not_be_locked(self) -> Self + where + Self: Sized, + { + self.is_not_locked() + } + /// Asserts that this mutex is not locked. /// Note that implementations may try to acquire the lock in order to check its state. /// @@ -24,6 +42,17 @@ pub trait MutexAssertions { { self.is_not_locked() } + + /// Asserts that this mutex is not locked. + /// Note that implementations may try to acquire the lock in order to check its state. + /// + /// Synonym for [Self::is_not_locked]. + fn be_free(self) -> Self + where + Self: Sized, + { + self.is_free() + } } impl MutexAssertions for AssertThat<'_, Mutex, M> { @@ -64,16 +93,15 @@ impl MutexAssertions for AssertThat<'_, Mutex, M> { mod tests { mod is_locked { + use crate::prelude::*; use indoc::formatdoc; use std::sync::Mutex; - use crate::prelude::*; - #[test] fn succeeds_when_locked() { let mutex = Mutex::new(42); let guard = mutex.lock(); - mutex.assert_ref().is_locked(); + mutex.must().be_locked(); drop(guard); } @@ -93,22 +121,21 @@ mod tests { } mod is_not_locked { + use crate::prelude::*; use indoc::formatdoc; use std::sync::Mutex; - use crate::prelude::*; - #[test] fn succeeds_when_not_locked() { let mutex = Mutex::new(42); - assert_that(mutex).is_not_locked(); + mutex.must().not_be_locked(); } #[test] fn panics_when_locked() { let mutex = Mutex::new(42); let guard = mutex.lock(); - assert_that_panic_by(|| mutex.assert_ref().with_location(false).is_not_locked()) + assert_that_panic_by(|| mutex.assert().with_location(false).is_not_locked()) .has_type::() .is_equal_to(formatdoc! {" -------- assertr -------- @@ -122,14 +149,13 @@ mod tests { } mod is_free { - use std::sync::Mutex; - use crate::prelude::*; + use std::sync::Mutex; #[test] fn succeeds_when_not_locked() { let mutex = Mutex::new(42); - assert_that(mutex).is_free(); + mutex.must().be_free(); } } } diff --git a/assertr/src/assertions/std/path.rs b/assertr/src/assertions/std/path.rs index b25059a..f6b0ade 100644 --- a/assertr/src/assertions/std/path.rs +++ b/assertr/src/assertions/std/path.rs @@ -4,15 +4,84 @@ use std::{ffi::OsStr, path::Path}; pub trait PathAssertions { fn exists(self) -> Self; + fn exist(self) -> Self + where + Self: Sized, + { + self.exists() + } + fn does_not_exist(self) -> Self; + fn not_exist(self) -> Self + where + Self: Sized, + { + self.does_not_exist() + } + fn is_a_file(self) -> Self; + fn be_a_file(self) -> Self + where + Self: Sized, + { + self.is_a_file() + } + fn is_a_directory(self) -> Self; + fn be_a_directory(self) -> Self + where + Self: Sized, + { + self.is_a_directory() + } + fn is_a_symlink(self) -> Self; + fn be_a_symlink(self) -> Self + where + Self: Sized, + { + self.is_a_symlink() + } + fn has_a_root(self) -> Self; + fn have_a_root(self) -> Self + where + Self: Sized, + { + self.has_a_root() + } + fn is_relative(self) -> Self; + fn be_relative(self) -> Self + where + Self: Sized, + { + self.is_relative() + } + fn has_file_name(self, expected: impl AsRef) -> Self; + fn have_file_name(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.has_file_name(expected) + } + fn has_file_stem(self, expected: impl AsRef) -> Self; + fn have_file_stem(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.has_file_stem(expected) + } + fn has_extension(self, expected: impl AsRef) -> Self; + fn have_extension(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.has_extension(expected) + } } impl PathAssertions for AssertThat<'_, PathBuf, M> { @@ -234,16 +303,18 @@ mod tests { #[test] fn succeeds_when_present() { let path = env::current_dir().unwrap().parent().unwrap().join(file!()); - assert_that(path.as_path()) - .exists() + path.as_path() + .must() + .exist() .map(|it| it.borrowed().to_str().unwrap_or_default().into()) + .and() .ends_with("src/assertions/std/path.rs"); } #[test] fn panics_when_absent() { let path = Path::new("src/assertions/std/some-non-existing-file.rs"); - assert_that_panic_by(|| assert_that(path).with_location(false).exists()) + assert_that_panic_by(|| assert_that_owned(path).with_location(false).exists()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -263,16 +334,14 @@ mod tests { #[test] fn succeeds_when_absent() { let path = Path::new("../../foo/bar/baz.rs"); - assert_that(path).does_not_exist(); + assert_that_owned(path).does_not_exist(); } #[test] fn panics_when_present() { let path = env::current_dir().unwrap().parent().unwrap().join(file!()); assert_that_panic_by(|| { - assert_that(path.as_path()) - .with_location(false) - .does_not_exist() + path.as_path().must().with_location(false).not_exist(); }) .has_type::() .contains("-------- assertr --------") @@ -289,7 +358,7 @@ mod tests { #[test] fn succeeds_when_file() { let path = env::current_dir().unwrap().parent().unwrap().join(file!()); - assert_that(path.as_path()).is_a_file(); + assert_that_owned(path.as_path()).is_a_file(); } #[test] @@ -297,7 +366,7 @@ mod tests { let path = env::current_dir().unwrap().parent().unwrap().join(file!()); let dir = path.parent().unwrap(); assert_that_panic_by(|| { - assert_that(dir) + assert_that_owned(dir) .with_location(false) .exists() // Sanity-check. Non-existing paths would also not be files! .is_a_file() @@ -323,17 +392,18 @@ mod tests { .parent() .unwrap() .join(Path::new(file!()).parent().expect("present")); - assert_that(path.as_path()).is_a_directory(); + assert_that_owned(path.as_path()).is_a_directory(); } #[test] fn panics_when_not_a_directory() { let path = env::current_dir().unwrap().parent().unwrap().join(file!()); assert_that_panic_by(|| { - assert_that(path.as_path()) + path.as_path() + .must() .with_location(false) - .exists() // Sanity-check. Non-existing paths would also not be files! - .is_a_directory() + .exist() // Sanity-check. Non-existing paths would also not be files! + .be_a_directory(); }) .has_type::() .contains("-------- assertr --------") @@ -351,7 +421,7 @@ mod tests { #[test] fn is_symlink_succeeds_when_directory() { let path = Path::new(file!()); - assert_that(path).is_symlink(); + assert_that_owned(path).is_symlink(); } */ } @@ -364,13 +434,13 @@ mod tests { #[test] fn succeeds_when_root() { let path = Path::new("/foo/bar/baz.rs"); - assert_that(path).has_a_root(); + assert_that_owned(path).has_a_root(); } #[test] fn panics_when_relative() { let path = Path::new("foo/bar/baz.rs"); - assert_that_panic_by(|| assert_that(path).with_location(false).has_a_root()) + assert_that_panic_by(|| assert_that_owned(path).with_location(false).has_a_root()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -390,13 +460,13 @@ mod tests { #[test] fn succeeds_when_relative() { let path = Path::new("foo/bar/baz.rs"); - assert_that(path).is_relative(); + assert_that_owned(path).is_relative(); } #[test] fn panics_when_absolute() { let path = Path::new("/foo/bar/baz.rs"); - assert_that_panic_by(|| assert_that(path).with_location(false).is_relative()) + assert_that_panic_by(|| assert_that_owned(path).with_location(false).is_relative()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -416,14 +486,14 @@ mod tests { #[test] fn succeeds_when_equal() { let path = Path::new(file!()); - assert_that(path).has_file_name("path.rs"); + assert_that_owned(path).has_file_name("path.rs"); } #[test] fn panics_when_different() { let path = Path::new(file!()); assert_that_panic_by(|| { - assert_that(path) + assert_that_owned(path) .with_location(false) .has_file_name("some.json") }) @@ -447,14 +517,16 @@ mod tests { #[test] fn succeeds_when_equal() { let path = Path::new(file!()); - assert_that(path).has_file_stem("path"); + assert_that_owned(path).has_file_stem("path"); } #[test] fn panics_when_different() { let path = Path::new(file!()); assert_that_panic_by(|| { - assert_that(path).with_location(false).has_file_stem("some") + assert_that_owned(path) + .with_location(false) + .has_file_stem("some") }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -476,14 +548,16 @@ mod tests { #[test] fn succeeds_when_equal() { let path = Path::new(file!()); - assert_that(path).has_extension("rs"); + assert_that_owned(path).has_extension("rs"); } #[test] fn panics_when_different() { let path = Path::new(file!()); assert_that_panic_by(|| { - assert_that(path).with_location(false).has_extension("json") + assert_that_owned(path) + .with_location(false) + .has_extension("json") }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -513,7 +587,7 @@ mod tests { .unwrap() .join(file!()) .to_owned(); - assert_that(path) + assert_that_owned(path) .exists() .map(|it| it.unwrap_owned().display().to_string().into()) .ends_with("src/assertions/std/path.rs"); @@ -522,7 +596,7 @@ mod tests { #[test] fn panics_when_absent() { let path = Path::new("src/assertions/std/some-non-existing-file.rs").to_owned(); - assert_that_panic_by(|| assert_that(path).with_location(false).exists()) + assert_that_panic_by(|| assert_that_owned(path).with_location(false).exists()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -542,18 +616,22 @@ mod tests { #[test] fn succeeds_when_absent() { let path = Path::new("../../foo/bar/baz.rs").to_owned(); - assert_that(path).does_not_exist(); + assert_that_owned(path).does_not_exist(); } #[test] fn panics_when_present() { let path = env::current_dir().unwrap().parent().unwrap().join(file!()); - assert_that_panic_by(|| assert_that(path).with_location(false).does_not_exist()) - .has_type::() - .contains("-------- assertr --------") - .contains("Expected: \"") - .contains("assertr/src/assertions/std/path.rs\"") - .contains("to not exist, but it does!"); + assert_that_panic_by(|| { + assert_that_owned(path) + .with_location(false) + .does_not_exist() + }) + .has_type::() + .contains("-------- assertr --------") + .contains("Expected: \"") + .contains("assertr/src/assertions/std/path.rs\"") + .contains("to not exist, but it does!"); } } @@ -564,7 +642,7 @@ mod tests { #[test] fn succeeds_when_file() { let path = env::current_dir().unwrap().parent().unwrap().join(file!()); - assert_that(path).is_a_file(); + assert_that_owned(path).is_a_file(); } #[test] @@ -572,10 +650,10 @@ mod tests { let path = env::current_dir().unwrap().parent().unwrap().join(file!()); let dir = path.parent().unwrap().to_owned(); assert_that_panic_by(|| { - assert_that(dir) + assert_that_owned(dir) .with_location(false) .exists() // Sanity-check. Non-existing paths would also not be files! - .is_a_file() + .is_a_file(); }) .has_type::() .contains("-------- assertr --------") @@ -598,14 +676,14 @@ mod tests { .parent() .unwrap() .join(Path::new(file!()).parent().expect("present")); - assert_that(path).is_a_directory(); + assert_that_owned(path).is_a_directory(); } #[test] fn panics_when_not_a_directory() { let path = env::current_dir().unwrap().parent().unwrap().join(file!()); assert_that_panic_by(|| { - assert_that(path) + assert_that_owned(path) .with_location(false) .exists() // Sanity-check. Non-existing paths would also not be files! .is_a_directory() @@ -639,13 +717,13 @@ mod tests { #[test] fn succeeds_when_root() { let path = Path::new("/foo/bar/baz.rs").to_owned(); - assert_that(path).has_a_root(); + assert_that_owned(path).has_a_root(); } #[test] fn panics_when_relative() { let path = Path::new("foo/bar/baz.rs").to_owned(); - assert_that_panic_by(|| assert_that(path).with_location(false).has_a_root()) + assert_that_panic_by(|| assert_that_owned(path).with_location(false).has_a_root()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -665,13 +743,13 @@ mod tests { #[test] fn succeeds_when_relative() { let path = Path::new("foo/bar/baz.rs").to_owned(); - assert_that(path).is_relative(); + assert_that_owned(path).is_relative(); } #[test] fn panics_when_absolute() { let path = Path::new("/foo/bar/baz.rs").to_owned(); - assert_that_panic_by(|| assert_that(path).with_location(false).is_relative()) + assert_that_panic_by(|| assert_that_owned(path).with_location(false).is_relative()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -691,14 +769,14 @@ mod tests { #[test] fn succeeds_when_equal() { let path = Path::new(file!()).to_owned(); - assert_that(path).has_file_name("path.rs"); + assert_that_owned(path).has_file_name("path.rs"); } #[test] fn panics_when_different() { let path = Path::new(file!()).to_owned(); assert_that_panic_by(|| { - assert_that(path) + assert_that_owned(path) .with_location(false) .has_file_name("some.json") }) @@ -722,14 +800,16 @@ mod tests { #[test] fn succeeds_when_equal() { let path = Path::new(file!()).to_owned(); - assert_that(path).has_file_stem("path"); + assert_that_owned(path).has_file_stem("path"); } #[test] fn panics_when_different() { let path = Path::new(file!()).to_owned(); assert_that_panic_by(|| { - assert_that(path).with_location(false).has_file_stem("some") + assert_that_owned(path) + .with_location(false) + .has_file_stem("some") }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -751,14 +831,16 @@ mod tests { #[test] fn succeeds_when_equal() { let path = Path::new(file!()).to_owned(); - assert_that(path).has_extension("rs"); + assert_that_owned(path).has_extension("rs"); } #[test] fn panics_when_different() { let path = Path::new(file!()).to_owned(); assert_that_panic_by(|| { - assert_that(path).with_location(false).has_extension("json") + assert_that_owned(path) + .with_location(false) + .has_extension("json") }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/tokio/mutex.rs b/assertr/src/assertions/tokio/mutex.rs index e1c28a9..05530cc 100644 --- a/assertr/src/assertions/tokio/mutex.rs +++ b/assertr/src/assertions/tokio/mutex.rs @@ -8,8 +8,20 @@ use tokio::sync::Mutex; /// Assertions for tokio's [Mutex] type. pub trait TokioMutexAssertions { fn is_locked(self) -> Self; + fn be_locked(self) -> Self + where + Self: Sized, + { + self.is_locked() + } fn is_not_locked(self) -> Self; + fn not_be_locked(self) -> Self + where + Self: Sized, + { + self.is_not_locked() + } fn is_free(self) -> Self where @@ -17,6 +29,12 @@ pub trait TokioMutexAssertions { { self.is_not_locked() } + fn be_free(self) -> Self + where + Self: Sized, + { + self.is_free() + } } impl TokioMutexAssertions for AssertThat<'_, Mutex, M> { @@ -66,14 +84,14 @@ mod tests { async fn succeeds_when_locked() { let mutex = Mutex::new(42); let guard = mutex.lock().await; - assert_that_ref(&mutex).is_locked(); + mutex.must().be_locked(); drop(guard); } #[test] fn panics_when_not_locked() { let mutex = Mutex::new(42); - assert_that_panic_by(|| assert_that(mutex).with_location(false).is_locked()) + assert_that_panic_by(|| mutex.must().with_location(false).be_locked()) .has_type::() .is_equal_to(formatdoc! {" -------- assertr -------- @@ -94,14 +112,14 @@ mod tests { #[test] fn succeeds_when_not_locked() { let mutex = Mutex::new(42); - assert_that(mutex).is_not_locked(); + mutex.must().not_be_locked(); } #[tokio::test] async fn panics_when_locked() { let mutex = Mutex::new(42); let guard = mutex.lock().await; - assert_that_panic_by(|| assert_that_ref(&mutex).with_location(false).is_not_locked()) + assert_that_panic_by(|| mutex.must().with_location(false).not_be_locked()) .has_type::() .is_equal_to(formatdoc! {" -------- assertr -------- @@ -122,7 +140,7 @@ mod tests { #[test] fn succeeds_when_not_locked() { let mutex = Mutex::new(42); - assert_that(mutex).is_free(); + mutex.must().be_free(); } } } diff --git a/assertr/src/assertions/tokio/rw_lock.rs b/assertr/src/assertions/tokio/rw_lock.rs index 46d3264..0c292f5 100644 --- a/assertr/src/assertions/tokio/rw_lock.rs +++ b/assertr/src/assertions/tokio/rw_lock.rs @@ -5,6 +5,12 @@ use tokio::sync::RwLock; /// Assertions for tokio's [RwLock] type. pub trait TokioRwLockAssertions { fn is_not_locked(self) -> Self; + fn not_be_locked(self) -> Self + where + Self: Sized, + { + self.is_not_locked() + } fn is_free(self) -> Self where @@ -12,10 +18,29 @@ pub trait TokioRwLockAssertions { { self.is_not_locked() } + fn be_free(self) -> Self + where + Self: Sized, + { + self.is_free() + } fn is_read_locked(self) -> Self; + fn be_read_locked(self) -> Self + where + Self: Sized, + { + self.is_read_locked() + } + fn is_write_locked(self) -> Self; + fn be_write_locked(self) -> Self + where + Self: Sized, + { + self.is_write_locked() + } } impl TokioRwLockAssertions for AssertThat<'_, RwLock, M> { @@ -104,7 +129,7 @@ mod tests { #[test] fn succeeds_when_not_locked() { let rw_lock = RwLock::new(42); - assert_that(rw_lock).is_not_locked(); + rw_lock.must().not_be_locked(); } #[tokio::test] @@ -112,13 +137,9 @@ mod tests { let rw_lock = RwLock::new(42); let rw_lock_write_guard = rw_lock.write().await; - assert_that_panic_by(|| { - assert_that_ref::>(&rw_lock) - .with_location(false) - .is_not_locked() - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| rw_lock.must().with_location(false).not_be_locked()) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Actual: RwLock {{ data: }} @@ -136,13 +157,9 @@ mod tests { let rw_lock = RwLock::new(42); let rw_lock_read_guard = rw_lock.read().await; - assert_that_panic_by(|| { - assert_that_ref::>(&rw_lock) - .with_location(false) - .is_not_locked() - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| rw_lock.must().with_location(false).not_be_locked()) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Actual: RwLock {{ data: 42 }} @@ -166,7 +183,7 @@ mod tests { async fn succeeds_when_read_locked() { let rw_lock = RwLock::new(42); let rw_lock_read_guard = rw_lock.read().await; - rw_lock.assert_ref().is_read_locked(); + rw_lock.must().be_read_locked(); drop(rw_lock_read_guard); } @@ -175,7 +192,7 @@ mod tests { let rw_lock = RwLock::new(42); let rw_lock_write_guard = rw_lock.write().await; - assert_that_panic_by(|| rw_lock.assert_ref().with_location(false).is_read_locked()) + assert_that_panic_by(|| rw_lock.must().with_location(false).be_read_locked()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -194,7 +211,7 @@ mod tests { fn panics_when_not_locked_at_all() { let rw_lock = RwLock::new(42); - assert_that_panic_by(|| assert_that(rw_lock).with_location(false).is_read_locked()) + assert_that_panic_by(|| rw_lock.must().with_location(false).be_read_locked()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -218,7 +235,7 @@ mod tests { async fn succeeds_when_write_locked() { let rw_lock = RwLock::new(42); let rw_lock_write_guard = rw_lock.write().await; - rw_lock.assert_ref().is_write_locked(); + rw_lock.must().be_write_locked(); drop(rw_lock_write_guard); } @@ -227,7 +244,7 @@ mod tests { let rw_lock = RwLock::new(42); let rw_lock_read_guard = rw_lock.read().await; - assert_that_panic_by(|| rw_lock.assert_ref().with_location(false).is_write_locked()) + assert_that_panic_by(|| rw_lock.must().with_location(false).be_write_locked()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -246,7 +263,7 @@ mod tests { fn panics_when_not_write_locked() { let rw_lock = RwLock::new(42); - assert_that_panic_by(|| rw_lock.assert().with_location(false).is_write_locked()) + assert_that_panic_by(|| rw_lock.must().with_location(false).be_write_locked()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- diff --git a/assertr/src/assertions/tokio/watch.rs b/assertr/src/assertions/tokio/watch.rs index 6e6318a..14ac823 100644 --- a/assertr/src/assertions/tokio/watch.rs +++ b/assertr/src/assertions/tokio/watch.rs @@ -10,9 +10,30 @@ pub trait TokioWatchReceiverAssertions { where T: PartialEq; + fn have_current_value(self, expected: impl Borrow) -> Self + where + T: PartialEq, + Self: Sized, + { + self.has_current_value(expected) + } + fn has_changed(self) -> Self; + fn have_changed(self) -> Self + where + Self: Sized, + { + self.has_changed() + } + fn has_not_changed(self) -> Self; + fn have_not_changed(self) -> Self + where + Self: Sized, + { + self.has_not_changed() + } } impl TokioWatchReceiverAssertions @@ -66,7 +87,7 @@ mod tests { }) .unwrap(); - assert_that(rx).has_current_value(Person { + rx.must().have_current_value(Person { name: "kevin".into(), }); } @@ -76,11 +97,9 @@ mod tests { let (_tx, rx) = tokio::sync::watch::channel(Person { name: "bob".into() }); assert_that_panic_by(|| { - assert_that(rx) - .with_location(false) - .has_current_value(Person { - name: "alice".into(), - }) + rx.assert().with_location(false).has_current_value(Person { + name: "alice".into(), + }) }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -107,7 +126,7 @@ mod tests { let (_tx, mut rx) = tokio::sync::watch::channel(Person { name: "bob".into() }); rx.mark_changed(); - assert_that(rx).has_changed(); + rx.must().have_changed(); } #[tokio::test] @@ -115,7 +134,7 @@ mod tests { let (_tx, mut rx) = tokio::sync::watch::channel(Person { name: "bob".into() }); rx.mark_unchanged(); - assert_that_panic_by(|| assert_that(rx).with_location(false).has_changed()) + assert_that_panic_by(|| rx.assert().with_location(false).has_changed()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -141,7 +160,7 @@ mod tests { let (_tx, mut rx) = tokio::sync::watch::channel(Person { name: "bob".into() }); rx.mark_unchanged(); - assert_that(rx).has_not_changed(); + rx.must().have_not_changed(); } #[tokio::test] @@ -149,7 +168,7 @@ mod tests { let (_tx, mut rx) = tokio::sync::watch::channel(Person { name: "bob".into() }); rx.mark_changed(); - assert_that_panic_by(|| assert_that(rx).with_location(false).has_not_changed()) + assert_that_panic_by(|| rx.assert().with_location(false).has_not_changed()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- diff --git a/assertr/src/cmp/hashmap.rs b/assertr/src/cmp/hashmap.rs index ca27be0..d7a28f3 100644 --- a/assertr/src/cmp/hashmap.rs +++ b/assertr/src/cmp/hashmap.rs @@ -73,7 +73,7 @@ mod test { let mut ctx = EqContext::new(); - assert_that(compare(&m1, &m2, Some(&mut ctx))).is_true(); - assert_that(compare(&m1, &m3, Some(&mut ctx))).is_false(); + assert_that!(compare(&m1, &m2, Some(&mut ctx))).is_true(); + assert_that!(compare(&m1, &m3, Some(&mut ctx))).is_false(); } } diff --git a/assertr/src/cmp/slice.rs b/assertr/src/cmp/slice.rs index d206c37..e45eb9e 100644 --- a/assertr/src/cmp/slice.rs +++ b/assertr/src/cmp/slice.rs @@ -87,8 +87,8 @@ mod test { let mut ctx = EqContext::new(); - assert_that(compare(&slice1, &slice2, Some(&mut ctx))).is_true(); - assert_that(compare(&slice1, &slice3, Some(&mut ctx))).is_false(); + assert_that!(compare(&slice1, &slice2, Some(&mut ctx))).is_true(); + assert_that!(compare(&slice1, &slice3, Some(&mut ctx))).is_false(); } #[test] @@ -100,8 +100,8 @@ mod test { let result = compare(&slice1, &slice2, Some(&mut ctx)); - assert_that(result).is_true(); - assert_that(ctx.differences.differences).is_empty(); + assert_that!(result).is_true(); + assert_that!(ctx.differences.differences).is_empty(); } #[test] @@ -113,8 +113,8 @@ mod test { let result = compare(&slice1, &slice2, Some(&mut ctx)); - assert_that(result).is_false(); - assert_that(ctx.differences.differences).contains_exactly(&[ + assert_that!(result).is_false(); + assert_that!(ctx.differences.differences).contains_exactly(&[ "Elements not expected: [\n 1,\n]".to_string(), "Elements not found: [\n 4,\n]".to_string(), ]); @@ -129,8 +129,8 @@ mod test { let result = compare(&slice1, &slice2, Some(&mut ctx)); - assert_that(result).is_false(); - assert_that(ctx.differences.differences).contains_exactly(&[ + assert_that!(result).is_false(); + assert_that!(ctx.differences.differences).contains_exactly(&[ "Slices only differ in their element-order. A:[\n 1,\n 2,\n 3,\n] and B:[\n 1,\n 3,\n 2,\n]".to_string(), ]); } @@ -144,8 +144,8 @@ mod test { let result = compare(&slice1, &slice2, Some(&mut ctx)); - assert_that(result).is_false(); - assert_that(ctx.differences.differences).contains_exactly(&[ + assert_that!(result).is_false(); + assert_that!(ctx.differences.differences).contains_exactly(&[ "Slices are not of the same length. A:3 and B:4".to_string(), "Elements not found: [\n 4,\n]".to_string(), ]); diff --git a/assertr/src/conversion.rs b/assertr/src/conversion.rs index 0568c09..f609918 100644 --- a/assertr/src/conversion.rs +++ b/assertr/src/conversion.rs @@ -20,7 +20,7 @@ use crate::mode::Mode; /// /// let person = Person { age: 42 }; /// -/// assert_that(person) +/// assert_that(&person) /// .map(json()) /// .is_equal_to(r#"{"age":42}"#); /// ``` @@ -48,7 +48,7 @@ pub fn json() -> impl FnOnce(Actual) -> Actual { /// /// let config = Config { value: 42 }; /// -/// assert_that(config) +/// assert_that(&config) /// .map(toml()) /// .is_equal_to("value = 42\n"); /// ``` diff --git a/assertr/src/failure.rs b/assertr/src/failure.rs index 36b77ee..665e2d4 100644 --- a/assertr/src/failure.rs +++ b/assertr/src/failure.rs @@ -90,7 +90,7 @@ fn build_failure_message( } if let Some(subject_name) = subject_name { - err.write_fmt(format_args!("Subject: {}\n\n", subject_name))?; + err.write_fmt(format_args!("Subject: {subject_name}\n\n"))?; } failure.write_to(&mut err)?; diff --git a/assertr/src/lib.rs b/assertr/src/lib.rs index 51866df..f784926 100644 --- a/assertr/src/lib.rs +++ b/assertr/src/lib.rs @@ -39,9 +39,9 @@ pub mod prelude { pub use crate::IntoAssertContext; pub use crate::any; pub use crate::assert_that; + pub use crate::assert_that_owned; #[cfg(feature = "std")] pub use crate::assert_that_panic_by; - pub use crate::assert_that_ref; pub use crate::assert_that_type; pub use crate::assertions::HasLength; pub use crate::assertions::alloc::prelude::*; @@ -76,27 +76,27 @@ pub struct PanicValue(Box); /// use assertr::prelude::*; /// /// // This will panic with a descriptive message and a pointer to the actual line of the assertion. -/// assert_that(3).is_equal_to(4); +/// assert_that_owned(3).is_equal_to(4); /// /// // This instead captures the assertion failure for later inspection. -/// let failures = assert_that(3) +/// let failures = assert_that_owned(3) /// .with_capture() /// .is_equal_to(4) // This will collect a failure instead of panicking. /// .capture_failures(); /// -/// assert_that(failures) +/// assert_that_owned(failures) /// .has_length(1) /// .contains(""); /// ``` #[track_caller] #[must_use] -pub fn assert_that<'t, T>(actual: T) -> AssertThat<'t, T, Panic> { +pub fn assert_that_owned<'t, T>(actual: T) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Owned(actual)) } #[track_caller] #[must_use] -pub fn assert_that_ref(actual: &T) -> AssertThat { +pub fn assert_that(actual: &T) -> AssertThat { AssertThat::new_panicking(Actual::Borrowed(actual)) } @@ -104,86 +104,92 @@ pub fn assert_that_ref(actual: &T) -> AssertThat { #[macro_export] macro_rules! assert_that { ($expr:expr) => { - $crate::IntoAssertContext::assert($expr) + $expr.assert() }; } pub trait IntoAssertContext<'t, T> { - fn assert(self) -> AssertThat<'t, T, Panic>; - fn assert_ref(&'t self) -> AssertThat<'t, T, Panic>; + #[must_use] + fn assert(&'t self) -> AssertThat<'t, T, Panic>; + #[must_use] + fn assert_owned(self) -> AssertThat<'t, T, Panic>; - fn must(self) -> AssertThat<'t, T, Panic>; - fn must_ref(&'t self) -> AssertThat<'t, T, Panic>; + #[must_use] + fn must(&'t self) -> AssertThat<'t, T, Panic>; + #[must_use] + fn must_owned(self) -> AssertThat<'t, T, Panic>; - fn should(self) -> AssertThat<'t, T, Capture>; - fn should_ref(&'t self) -> AssertThat<'t, T, Capture>; + #[must_use] + fn should(&'t self) -> AssertThat<'t, T, Capture>; + #[must_use] + fn should_owned(self) -> AssertThat<'t, T, Capture>; } impl<'t, T> IntoAssertContext<'t, T> for T { - fn assert(self) -> AssertThat<'t, T, Panic> { - AssertThat::new_panicking(Actual::Owned(self)) - } - fn assert_ref(&'t self) -> AssertThat<'t, T, Panic> { + fn assert(&'t self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } + fn assert_owned(self) -> AssertThat<'t, T, Panic> { + AssertThat::new_panicking(Actual::Owned(self)) + } - fn must(self) -> AssertThat<'t, T, Panic> { + fn must_owned(self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Owned(self)) } - fn must_ref(&'t self) -> AssertThat<'t, T, Panic> { + fn must(&'t self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } - fn should(self) -> AssertThat<'t, T, Capture> { - AssertThat::new_capturing(Actual::Owned(self)) - } - fn should_ref(&'t self) -> AssertThat<'t, T, Capture> { + fn should(&'t self) -> AssertThat<'t, T, Capture> { AssertThat::new_capturing(Actual::Borrowed(self)) } + fn should_owned(self) -> AssertThat<'t, T, Capture> { + AssertThat::new_capturing(Actual::Owned(self)) + } } impl<'t, T> IntoAssertContext<'t, T> for &'t T { - fn assert(self) -> AssertThat<'t, T, Panic> { + fn assert(&'t self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } - fn assert_ref(&'t self) -> AssertThat<'t, T, Panic> { + fn assert_owned(self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } - fn must(self) -> AssertThat<'t, T, Panic> { + fn must(&'t self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } - fn must_ref(&'t self) -> AssertThat<'t, T, Panic> { + fn must_owned(self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } - fn should(self) -> AssertThat<'t, T, Capture> { + fn should(&'t self) -> AssertThat<'t, T, Capture> { AssertThat::new_capturing(Actual::Borrowed(self)) } - fn should_ref(&'t self) -> AssertThat<'t, T, Capture> { + fn should_owned(self) -> AssertThat<'t, T, Capture> { AssertThat::new_capturing(Actual::Borrowed(self)) } } impl<'t, T> IntoAssertContext<'t, T> for &'t mut T { - fn assert(self) -> AssertThat<'t, T, Panic> { + fn assert(&'t self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } - fn assert_ref(&'t self) -> AssertThat<'t, T, Panic> { + fn assert_owned(self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } - fn must(self) -> AssertThat<'t, T, Panic> { + fn must(&'t self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } - fn must_ref(&'t self) -> AssertThat<'t, T, Panic> { + fn must_owned(self) -> AssertThat<'t, T, Panic> { AssertThat::new_panicking(Actual::Borrowed(self)) } - fn should(self) -> AssertThat<'t, T, Capture> { + fn should(&'t self) -> AssertThat<'t, T, Capture> { AssertThat::new_capturing(Actual::Borrowed(self)) } - fn should_ref(&'t self) -> AssertThat<'t, T, Capture> { + fn should_owned(self) -> AssertThat<'t, T, Capture> { AssertThat::new_capturing(Actual::Borrowed(self)) } } @@ -196,7 +202,7 @@ pub fn assert_that_panic_by<'t, R>( ) -> AssertThat<'t, PanicValue, Panic> { use crate::prelude::FnOnceAssertions; - assert_that(fun).panics() + assert_that_owned(fun).panics() } pub struct Type { @@ -204,6 +210,12 @@ pub struct Type { } impl Type { + pub fn new() -> Self { + Self { + phantom: Default::default(), + } + } + pub fn get_type_name(&self) -> &'static str { std::any::type_name::() } @@ -217,10 +229,14 @@ impl Type { } } +impl Default for Type { + fn default() -> Self { + Self::new() + } +} + pub fn assert_that_type() -> AssertThat<'static, Type, Panic> { - AssertThat::new_panicking(Actual::Owned(Type { - phantom: Default::default(), - })) + AssertThat::new_panicking(Actual::Owned(Type::::new())) } /// `AssertThat` is the core structure used for assertions. It allows developers to perform @@ -319,7 +335,7 @@ impl AssertThat<'_, T, Capture> { /// .be_negative() /// .be_equal_to(43) /// .capture_failures(); - /// + /// /// failures.must().have_length(2); /// ``` #[must_use] @@ -488,6 +504,14 @@ impl<'t, T, M: Mode> AssertThat<'t, T, M> { self } + pub fn satisfy(self, mapper: F, assertions: A) -> Self + where + for<'a> F: FnOnce(&'a T) -> U, + for<'a> A: FnOnce(AssertThat<'a, U, M>), + { + self.satisfies(mapper, assertions) + } + pub fn satisfies_ref(self, mapper: F, assertions: A) -> Self where for<'a> F: FnOnce(&'a T) -> &'a U, @@ -517,6 +541,28 @@ impl<'t, T, M: Mode> AssertThat<'t, T, M> { } } +/* Fluent connect */ + +impl<'t, T, M: Mode> AssertThat<'t, T, M> { + /// Filler that allows you to add an "and" inside your assertion chain. + /// + /// This is completely optional (noop). + /// + /// ``` + /// use assertr::prelude::*; + /// + /// 42.must().be_positive().and().be_less_than(100); + /// 42.must().be_positive().be_less_than(100); + /// + /// 42.assert().is_positive().and().is_less_than(100); + /// 42.assert().is_positive().is_less_than(100); + /// ``` + #[inline(always)] + pub fn and(self) -> Self { + self + } +} + /* Mode changes */ impl<'t, T> AssertThat<'t, T, Panic> { @@ -552,7 +598,7 @@ impl<'t, T> AssertThat<'t, T, Capture> { // Take out all assertion failures, marking the `Capture` as "captured". // Assert that no failures exist. use crate::assertions::core::length::LengthAssertions; - assert_that(self.take_failures()) + assert_that_owned(self.take_failures()) .with_location(self.print_location) .with_subject_name("Assertion failures") .with_detail_message( @@ -733,14 +779,14 @@ mod tests { #[test] fn with_capture_yields_failures_and_does_not_panic() { - let failures = assert_that(42) + let failures = 42 + .should() .with_location(false) - .with_capture() - .is_greater_than(100) - .is_equal_to(1) + .be_greater_than(100) + .be_equal_to(1) .capture_failures(); - assert_that(failures.as_slice()) + assert_that!(failures.as_slice()) .has_length(2) .contains_exactly([ formatdoc! {" @@ -764,10 +810,7 @@ mod tests { #[test] fn dropping_a_capturing_assert_panics_when_failures_occurred_which_were_not_captured() { - let assert = assert_that(42) - .with_location(false) - .with_capture() - .is_equal_to(43); + let assert = 42.should().with_location(false).be_equal_to(43); assert_that_panic_by(move || drop(assert)) .has_type::<&str>() .is_equal_to("You dropped an `assert_that(..)` value, on which `.with_capture()` was called, without actually capturing the assertion failures using `.capture_failures()`!"); @@ -775,7 +818,7 @@ mod tests { #[test] fn without_capture_switches_to_panic_mode() { - let assert_capturing = assert_that(42) + let assert_capturing = assert_that_owned(42) .with_location(false) .with_capture() // Without this assertion, we would see a panic due to zero assertions being made. @@ -786,7 +829,7 @@ mod tests { #[test] fn without_capture_panics_when_assertion_failures_were_already_recorded() { - let assert_capturing = assert_that(42) + let assert_capturing = assert_that_owned(42) .with_location(false) .with_capture() // This records a failure. @@ -818,7 +861,7 @@ mod tests { #[test] fn panics_on_borrowed_value_in_panic_mode() { let value = String::from("foo"); - let assert = assert_that_ref(&value) + let assert = assert_that(&value) .with_location(false) // Avoid "number-of-assertions not greater 0" panic. .is_equal_to("foo"); @@ -831,7 +874,7 @@ mod tests { #[test] fn panics_on_borrowed_value_in_capture_mode() { let value = String::from("foo"); - let assert = assert_that_ref(&value) + let assert = assert_that(&value) .with_location(false) .with_capture() // Avoid "number-of-assertions not greater 0" panic. @@ -844,27 +887,27 @@ mod tests { #[test] fn succeeds_on_owned_value_in_panic_mode() { - let assert = assert_that(42) + let assert = assert_that_owned(42) .with_location(false) // Avoid "number-of-assertions not greater 0" panic. .is_equal_to(42); let actual = assert.unwrap_inner(); - assert_that(actual).is_equal_to(42); + actual.must().be_equal_to(42); } #[test] fn succeeds_on_owned_value_in_capture_mode_when_no_failures_were_recorded() { - let assert = assert_that(42) + let assert = assert_that_owned(42) .with_location(false) .with_capture() .has_display_value("42"); let actual = assert.unwrap_inner(); - assert_that(actual).is_equal_to(42); + actual.must().be_equal_to(42); } #[test] fn panics_on_owned_value_in_capture_mode_when_failures_were_recorded() { - let assert = assert_that(42) + let assert = assert_that_owned(42) .with_location(false) .with_capture() // This records a failure. @@ -892,7 +935,40 @@ mod tests { #[test] fn allows_fluent_entry_into_assertion_context() { - 42.assert_ref().is_equal_to(42); 42.assert().is_equal_to(42); + 42.assert_owned().is_equal_to(42); + + 42.must().be_equal_to(42); + 42.must_owned().be_equal_to(42); + + 42.should() + .be_equal_to(42) + .capture_failures() + .must() + .be_empty(); + 42.should_owned() + .be_equal_to(42) + .capture_failures() + .must() + .be_empty(); + + assert_that(&42).is_equal_to(42); + assert_that_owned(42).is_equal_to(42); + + assert_that(&42) + .with_capture() + .is_equal_to(42) + .capture_failures() + .assert_owned() + .is_empty(); + assert_that_owned(42) + .with_capture() + .is_equal_to(42) + .capture_failures() + .assert_owned() + .is_empty(); + + assert_that!(&42).is_equal_to(42); + assert_that!(42).is_equal_to(42); } } diff --git a/assertr/src/tracking.rs b/assertr/src/tracking.rs index 766f557..a0757aa 100644 --- a/assertr/src/tracking.rs +++ b/assertr/src/tracking.rs @@ -41,7 +41,7 @@ mod tests { #[test] fn panics_on_drop_when_no_assertions_were_made() { - assert_that_panic_by(|| assert_that(42).with_location(false)) + assert_that_panic_by(|| 42.must().with_location(false)) .has_type::<&str>() .is_equal_to( "An AssertThat was dropped without performing any actual assertions on it!", @@ -50,13 +50,28 @@ mod tests { #[test] fn number_of_assertions_are_tracked() { - let initial_assertions = assert_that(42).is_equal_to(42).is_positive(); + let initial_assertions = 42.must().be_equal_to(42).be_positive(); - assert_that(initial_assertions.number_of_assertions.borrow().0).is_equal_to(2); + initial_assertions + .number_of_assertions + .borrow() + .0 + .must() + .be_equal_to(2); - let derived_assertions = initial_assertions.derive(|it| it * 2).is_equal_to(84); + let derived_assertions = initial_assertions.derive(|it| it * 2).be_equal_to(84); - assert_that(initial_assertions.number_of_assertions.borrow().0).is_equal_to(3); - assert_that(derived_assertions.number_of_assertions.borrow().0).is_equal_to(1); + initial_assertions + .number_of_assertions + .borrow() + .0 + .must() + .be_equal_to(3); + derived_assertions + .number_of_assertions + .borrow() + .0 + .must() + .be_equal_to(1); } } diff --git a/assertr/src/util/slice.rs b/assertr/src/util/slice.rs index 10f3581..fc65fc8 100644 --- a/assertr/src/util/slice.rs +++ b/assertr/src/util/slice.rs @@ -106,44 +106,44 @@ mod tests { fn returns_equal_on_equal_input_using_refs() { let result = compare(&[&1, &2, &3], &[&1, &2, &3]); - assert_that(result.only_differing_in_order()).is_false(); - assert_that(result.strictly_equal).is_true(); - assert_that(result.same_length).is_true(); - assert_that(result.not_in_a).is_empty(); - assert_that(result.not_in_b).is_empty(); + result.only_differing_in_order().must().be_false(); + result.strictly_equal.must().be_true(); + result.same_length.must().be_true(); + result.not_in_a.must().be_empty(); + result.not_in_b.must().be_empty(); } #[test] fn returns_equal_on_equal_input() { let result = compare(&[1, 2, 3], &[1, 2, 3]); - assert_that(result.only_differing_in_order()).is_false(); - assert_that(result.strictly_equal).is_true(); - assert_that(result.same_length).is_true(); - assert_that(result.not_in_a).is_empty(); - assert_that(result.not_in_b).is_empty(); + result.only_differing_in_order().must().be_false(); + result.strictly_equal.must().be_true(); + result.same_length.must().be_true(); + result.not_in_a.must().be_empty(); + result.not_in_b.must().be_empty(); } #[test] fn returns_not_equal_on_equal_but_rearranged_input() { let result = compare(&[1, 2, 3], &[3, 2, 1]); - assert_that(result.only_differing_in_order()).is_true(); - assert_that(result.strictly_equal).is_false(); - assert_that(result.same_length).is_true(); - assert_that(result.not_in_a).is_empty(); - assert_that(result.not_in_b).is_empty(); + result.only_differing_in_order().must().be_true(); + result.strictly_equal.must().be_false(); + result.same_length.must().be_true(); + result.not_in_a.must().be_empty(); + result.not_in_b.must().be_empty(); } #[test] fn returns_not_equal_and_lists_differences_on_differing_input() { let result = compare(&[1, 5, 7], &[5, 3, 4, 42]); - assert_that(result.only_differing_in_order()).is_false(); - assert_that(result.strictly_equal).is_false(); - assert_that(result.same_length).is_false(); - assert_that(result.not_in_a).contains_exactly([&3, &4, &42]); - assert_that(result.not_in_b).contains_exactly([&1, &7]); + result.only_differing_in_order().must().be_false(); + result.strictly_equal.must().be_false(); + result.same_length.must().be_false(); + result.not_in_a.must().contain_exactly([&3, &4, &42]); + result.not_in_b.must().contain_exactly([&1, &7]); } } @@ -163,7 +163,7 @@ mod tests { .as_slice(), ); - assert_that(result.not_matched).is_empty(); + result.not_matched.must().be_empty(); } #[test] @@ -178,7 +178,7 @@ mod tests { .as_slice(), ); - assert_that(result.not_matched).is_empty(); + result.not_matched.must().be_empty(); } #[test] @@ -194,7 +194,7 @@ mod tests { .as_slice(), ); - assert_that(result.not_matched).contains_exactly([&1, &7]); + result.not_matched.must().contain_exactly([&1, &7]); } } } diff --git a/assertr/tests/conditions.rs b/assertr/tests/conditions.rs index 484765a..5610fff 100644 --- a/assertr/tests/conditions.rs +++ b/assertr/tests/conditions.rs @@ -57,7 +57,7 @@ fn is_able_to_use_custom_conditions_using_is_and_has() { }; let alive = IsAlive {}; let name_bob = HasName { expected: "Bob" }; - assert_that(bob).is(alive).has(name_bob); + assert_that!(bob).is(alive).has(name_bob); } #[test] @@ -73,5 +73,5 @@ fn is_able_to_use_custom_conditions_on_an_iterable_using_are_and_have() { let people = vec![bob, kevin]; let alive = IsAlive {}; let not_name_otto = HasNotName { unexpected: "Otto" }; - assert_that(people).are(alive).have(not_name_otto); + assert_that!(people).are(alive).have(not_name_otto); } diff --git a/assertr/tests/conversion.rs b/assertr/tests/conversion.rs index f8a658e..c48fca0 100644 --- a/assertr/tests/conversion.rs +++ b/assertr/tests/conversion.rs @@ -11,11 +11,8 @@ fn is_able_to_use_json_conversion() { let expected = r#"{"age":42}"#; - assert_that(person.clone()) - .map(json()) - .is_equal_to(expected); - - assert_that(person).as_json().is_equal_to(expected); + assert_that(&person).map(json()).is_equal_to(expected); + assert_that(&person).as_json().is_equal_to(expected); } #[test] @@ -31,14 +28,14 @@ fn is_able_to_use_toml_conversion() { list: vec![1, 2], }; - assert_that(config.clone()) + assert_that(&config) .map(toml()) .is_equal_to(indoc::formatdoc! {r#" value = 42 list = [1, 2] "#}); - assert_that(config) + assert_that(&config) .as_toml() .is_equal_to(indoc::formatdoc! {r#" value = 42 diff --git a/assertr/tests/custom_assertions.rs b/assertr/tests/custom_assertions.rs index 1aae9f4..0eb37dd 100644 --- a/assertr/tests/custom_assertions.rs +++ b/assertr/tests/custom_assertions.rs @@ -44,7 +44,7 @@ fn is_able_to_use_custom_has_age_assertion() { meta: Metadata { alive: true }, }; - assert_that(person) + assert_that(&person) .is_equal_to(Person { age: 30, meta: Metadata { alive: true }, diff --git a/assertr/tests/derive.rs b/assertr/tests/derive.rs index 78806bf..18a7584 100644 --- a/assertr/tests/derive.rs +++ b/assertr/tests/derive.rs @@ -18,17 +18,18 @@ fn is_able_to_access_derived_properties_without_breaking_the_call_chain() { meta: Metadata { alive: true }, }; - assert_that(person) - .is_equal_to(Person { + person + .must() + .be_equal_to(Person { age: 30, meta: Metadata { alive: true }, }) - .satisfies( + .satisfy( |it| it.age, |age| { age.is_greater_than(18); }, ) .derive(|it| it.meta.alive) - .is_equal_to(true); + .be_equal_to(true); } diff --git a/assertr/tests/derive_async.rs b/assertr/tests/derive_async.rs index 733e231..b18a512 100644 --- a/assertr/tests/derive_async.rs +++ b/assertr/tests/derive_async.rs @@ -22,9 +22,10 @@ async fn is_able_to_access_derived_properties_without_breaking_the_call_chain() meta: Metadata { alive: true }, }; - assert_that(person) + person + .must() .derive_async(|it| it.get_metadata()) .await .derive(|it| it.alive) - .is_equal_to(true); + .be_equal_to(true); } diff --git a/assertr/tests/detail_messages.rs b/assertr/tests/detail_messages.rs index 6bbad8a..b21d0e6 100644 --- a/assertr/tests/detail_messages.rs +++ b/assertr/tests/detail_messages.rs @@ -9,7 +9,7 @@ struct Person { #[test] fn test() { - assert_that(Person { age: 42 }) + assert_that_owned(Person { age: 42 }) .with_location(false) .with_capture() .with_detail_message("Checking person...") diff --git a/assertr/tests/map.rs b/assertr/tests/map.rs index 1c669df..595c0f9 100644 --- a/assertr/tests/map.rs +++ b/assertr/tests/map.rs @@ -16,12 +16,14 @@ fn is_able_to_access_derived_properties_without_breaking_the_call_chain() { meta: Metadata { alive: true }, }; - assert_that(person) + person + .must() .map(|it| it.borrowed().meta.alive.into()) - .is_equal_to(true); + .be_equal_to(true); - assert_that(-1.23) + (-1.23) + .must() .map_owned(|it| it.to_string()) .has_length(5) - .is_equal_to("-1.23".to_owned()); + .be_equal_to("-1.23".to_owned()); } diff --git a/assertr/tests/map_async.rs b/assertr/tests/map_async.rs index 184c412..8a0c804 100644 --- a/assertr/tests/map_async.rs +++ b/assertr/tests/map_async.rs @@ -22,9 +22,10 @@ async fn is_able_to_access_derived_properties_without_breaking_the_call_chain() meta: Metadata { alive: true }, }; - assert_that(person) + person + .must_owned() .map_async(|it| it.unwrap_owned().to_metadata()) .await .map(|it| it.borrowed().alive.into()) - .is_equal_to(true); + .be_equal_to(true); } From bd4fba32d41ac7927112b1db2d7e93ec378ba957 Mon Sep 17 00:00:00 2001 From: Lukas Potthast Date: Fri, 27 Jun 2025 23:06:35 +0200 Subject: [PATCH 5/9] Update dependencies --- Cargo.lock | 278 +++++++++++++++++++++++++++++------------------------ 1 file changed, 152 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3fa5067..2cadb53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" @@ -75,9 +75,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" @@ -102,15 +102,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytes" @@ -120,18 +120,18 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.22" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "colored" @@ -227,12 +227,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -318,7 +318,7 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] @@ -366,9 +366,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "http" @@ -439,11 +439,10 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", "http", "hyper", "hyper-util", @@ -472,22 +471,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -539,9 +544,9 @@ checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", @@ -555,9 +560,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" @@ -605,9 +610,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", @@ -625,6 +630,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "itoa" version = "1.0.15" @@ -633,9 +648,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -648,9 +663,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", @@ -684,9 +699,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.172" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libm" @@ -708,9 +723,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -724,9 +739,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "mime" @@ -736,22 +751,22 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -886,9 +901,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.72" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ "bitflags", "cfg-if", @@ -918,9 +933,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.108" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -930,9 +945,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -940,9 +955,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -977,9 +992,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" @@ -1028,9 +1043,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -1063,9 +1078,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags", ] @@ -1101,15 +1116,14 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", - "futures-util", "h2", "http", "http-body", @@ -1118,29 +1132,26 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows-registry", ] [[package]] @@ -1159,9 +1170,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustix" @@ -1178,9 +1189,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" dependencies = [ "once_cell", "rustls-pki-types", @@ -1189,15 +1200,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -1220,9 +1222,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" @@ -1302,9 +1304,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -1344,24 +1346,21 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1387,9 +1386,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.101" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -1477,9 +1476,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -1539,9 +1538,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -1551,18 +1550,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -1574,9 +1573,9 @@ dependencies = [ [[package]] name = "toml_write" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tower" @@ -1593,6 +1592,24 @@ dependencies = [ "tower-service", ] +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -1617,9 +1634,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] @@ -1692,9 +1709,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -1797,35 +1814,35 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ + "windows-link", "windows-result", "windows-strings", - "windows-targets 0.53.0", ] [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -1848,6 +1865,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1866,9 +1892,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", @@ -1978,9 +2004,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -2026,18 +2052,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", From 79c96105a000014de7ab56873df0c41eac4bcb74 Mon Sep 17 00:00:00 2001 From: Lukas Potthast Date: Wed, 17 Sep 2025 21:43:04 +0200 Subject: [PATCH 6/9] Adept new string assertions to new structure --- assertr/src/assertions/alloc/string.rs | 41 ++++++++++++++++++------ assertr/src/assertions/core/str_slice.rs | 37 ++++++++++++++------- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/assertr/src/assertions/alloc/string.rs b/assertr/src/assertions/alloc/string.rs index a26b455..8a87c42 100644 --- a/assertr/src/assertions/alloc/string.rs +++ b/assertr/src/assertions/alloc/string.rs @@ -15,6 +15,12 @@ pub trait StringAssertions { } fn does_not_contain(self, unexpected: impl AsRef) -> Self; + fn not_contain(self, unexpected: impl AsRef) -> Self + where + Self: Sized, + { + self.does_not_contain(unexpected) + } fn starts_with(self, expected: impl AsRef) -> Self; @@ -27,6 +33,13 @@ pub trait StringAssertions { fn does_not_start_with(self, unexpected: impl AsRef) -> Self; + fn not_start_with(self, unexpected: impl AsRef) -> Self + where + Self: Sized, + { + self.does_not_start_with(unexpected) + } + fn ends_with(self, expected: impl AsRef) -> Self; fn end_with(self, expected: impl AsRef) -> Self @@ -37,6 +50,13 @@ pub trait StringAssertions { } fn does_not_end_with(self, unexpected: impl AsRef) -> Self; + + fn not_end_with(self, unexpected: impl AsRef) -> Self + where + Self: Sized, + { + self.does_not_end_with(unexpected) + } } impl StringAssertions for AssertThat<'_, String, M> { @@ -119,15 +139,16 @@ mod tests { #[test] fn succeeds_when_expected_is_not_contained() { - assert_that(String::from("foobar")).does_not_contain("hello"); + String::from("foobar").must().not_contain("hello"); } #[test] fn panics_when_expected_is_contained() { assert_that_panic_by(|| { - assert_that(String::from("foo bar baz")) + String::from("foo bar baz") + .must() .with_location(false) - .does_not_contain("ar b"); + .not_contain("ar b"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -177,15 +198,16 @@ mod tests { #[test] fn succeeds_when_start_does_not_match() { - assert_that(String::from("foo bar baz")).starts_with("fo"); + String::from("foo bar baz").must().does_not_start_with("of"); } #[test] fn panics_when_start_matches() { assert_that_panic_by(|| { - assert_that(String::from("foo bar baz")) + String::from("foo bar baz") + .must() .with_location(false) - .does_not_start_with("foo bar ba"); + .not_start_with("foo bar ba"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -235,15 +257,16 @@ mod tests { #[test] fn succeeds_when_end_does_not_matches() { - assert_that(String::from("foo bar baz")).does_not_end_with("bar"); + String::from("foo bar baz").must().not_end_with("bar"); } #[test] fn panics_when_end_matches() { assert_that_panic_by(|| { - assert_that(String::from("foo bar baz")) + String::from("foo bar baz") + .must() .with_location(false) - .does_not_end_with(" baz"); + .not_end_with(" baz"); }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/core/str_slice.rs b/assertr/src/assertions/core/str_slice.rs index 61e70c2..0581397 100644 --- a/assertr/src/assertions/core/str_slice.rs +++ b/assertr/src/assertions/core/str_slice.rs @@ -40,6 +40,12 @@ pub trait StrSliceAssertions { } fn does_not_contain(self, unexpected: impl AsRef) -> Self; + fn not_contain(self, unexpected: impl AsRef) -> Self + where + Self: Sized, + { + self.does_not_contain(unexpected) + } fn starts_with(self, expected: impl AsRef) -> Self; fn start_with(self, expected: impl AsRef) -> Self @@ -50,6 +56,12 @@ pub trait StrSliceAssertions { } fn does_not_start_with(self, unexpected: impl AsRef) -> Self; + fn not_start_with(self, unexpected: impl AsRef) -> Self + where + Self: Sized, + { + self.does_not_start_with(unexpected) + } fn ends_with(self, expected: impl AsRef) -> Self; fn end_with(self, expected: impl AsRef) -> Self @@ -60,6 +72,12 @@ pub trait StrSliceAssertions { } fn does_not_end_with(self, unexpected: impl AsRef) -> Self; + fn not_end_with(self, unexpected: impl AsRef) -> Self + where + Self: Sized, + { + self.does_not_end_with(unexpected) + } } impl StrSliceAssertions for AssertThat<'_, &str, M> { @@ -309,15 +327,13 @@ mod tests { #[test] fn succeeds_when_expected_is_not_contained() { - assert_that("foobar").does_not_contain("baz"); + "foobar".must().not_contain("baz"); } #[test] fn panics_when_expected_is_contained() { assert_that_panic_by(|| { - assert_that("foo bar baz") - .with_location(false) - .does_not_contain("o b"); + "foo bar baz".must().with_location(false).not_contain("o b"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -365,15 +381,16 @@ mod tests { #[test] fn succeeds_when_start_does_not_match() { - assert_that("foo bar baz").does_not_start_with("oo"); + "foo bar baz".must().not_start_with("oo"); } #[test] fn panics_when_start_matches() { assert_that_panic_by(|| { - assert_that("foo bar baz") + "foo bar baz" + .must() .with_location(false) - .does_not_start_with("foo"); + .not_start_with("foo"); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -421,15 +438,13 @@ mod tests { #[test] fn succeeds_when_end_does_match() { - assert_that("foo bar baz").does_not_end_with("y"); + "foo bar baz".must().not_end_with("y"); } #[test] fn panics_when_end_is_matches() { assert_that_panic_by(|| { - assert_that("foo bar baz") - .with_location(false) - .does_not_end_with("z"); + "foo bar baz".must().with_location(false).not_end_with("z"); }) .has_type::() .is_equal_to(formatdoc! {r#" From 44dce4d9dcaee09ee2b58bf7954c4e6da000f2f6 Mon Sep 17 00:00:00 2001 From: Lukas Potthast Date: Wed, 17 Sep 2025 21:46:30 +0200 Subject: [PATCH 7/9] Adept new path assertions to new structure --- assertr/src/assertions/std/path.rs | 62 ++++++++++++++++-------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/assertr/src/assertions/std/path.rs b/assertr/src/assertions/std/path.rs index edf1227..7fe6e3c 100644 --- a/assertr/src/assertions/std/path.rs +++ b/assertr/src/assertions/std/path.rs @@ -84,8 +84,22 @@ pub trait PathAssertions { { self.has_extension(expected) } + fn starts_with(self, expected: impl AsRef) -> Self; + fn start_with(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.starts_with(expected) + } + fn ends_with(self, expected: impl AsRef) -> Self; + fn end_with(self, expected: impl AsRef) -> Self + where + Self: Sized, + { + self.ends_with(expected) + } } impl PathAssertions for AssertThat<'_, PathBuf, M> { @@ -692,17 +706,15 @@ mod tests { #[test] fn succeeds_when_prefix() { let path = Path::new(file!()); - assert_that(path).starts_with("assertr/src"); + path.must().start_with("assertr/src"); } #[test] fn panics_when_not_a_prefix() { let path = Path::new(file!()); - assert_that_panic_by(|| { - assert_that(path).with_location(false).starts_with("foobar") - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| path.must().with_location(false).start_with("foobar")) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Path: "assertr/src/assertions/std/path.rs" @@ -718,11 +730,9 @@ mod tests { #[test] fn panics_when_not_a_whole_segment_prefix() { let path = Path::new(file!()); - assert_that_panic_by(|| { - assert_that(path).with_location(false).starts_with("assert") - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| path.must().with_location(false).start_with("assert")) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Path: "assertr/src/assertions/std/path.rs" @@ -744,13 +754,13 @@ mod tests { #[test] fn succeeds_when_postfix() { let path = Path::new(file!()); - assert_that(path).ends_with("std/path.rs"); + path.must().end_with("std/path.rs"); } #[test] fn panics_when_not_a_postfix() { let path = Path::new(file!()); - assert_that_panic_by(|| assert_that(path).with_location(false).ends_with("foobar")) + assert_that_panic_by(|| path.must().with_location(false).end_with("foobar")) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -768,7 +778,7 @@ mod tests { #[test] fn panics_when_not_a_whole_segment_postfix() { let path = Path::new(file!()); - assert_that_panic_by(|| assert_that(path).with_location(false).ends_with("ath.rs")) + assert_that_panic_by(|| path.must().with_location(false).end_with("ath.rs")) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -1075,17 +1085,15 @@ mod tests { #[test] fn succeeds_when_prefix() { let path = Path::new(file!()).to_owned(); - assert_that(path).starts_with("assertr/src"); + path.must().start_with("assertr/src"); } #[test] fn panics_when_not_a_prefix() { let path = Path::new(file!()).to_owned(); - assert_that_panic_by(|| { - assert_that(path).with_location(false).starts_with("foobar") - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| path.must().with_location(false).start_with("foobar")) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Path: "assertr/src/assertions/std/path.rs" @@ -1101,11 +1109,9 @@ mod tests { #[test] fn panics_when_not_a_whole_segment_prefix() { let path = Path::new(file!()).to_owned(); - assert_that_panic_by(|| { - assert_that(path).with_location(false).starts_with("assert") - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| path.must().with_location(false).start_with("assert")) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Path: "assertr/src/assertions/std/path.rs" @@ -1127,13 +1133,13 @@ mod tests { #[test] fn succeeds_when_postfix() { let path = Path::new(file!()).to_owned(); - assert_that(path).ends_with("std/path.rs"); + path.must().end_with("std/path.rs"); } #[test] fn panics_when_not_a_postfix() { let path = Path::new(file!()).to_owned(); - assert_that_panic_by(|| assert_that(path).with_location(false).ends_with("foobar")) + assert_that_panic_by(|| path.must().with_location(false).end_with("foobar")) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -1151,7 +1157,7 @@ mod tests { #[test] fn panics_when_not_a_whole_segment_postfix() { let path = Path::new(file!()).to_owned(); - assert_that_panic_by(|| assert_that(path).with_location(false).ends_with("ath.rs")) + assert_that_panic_by(|| path.must().with_location(false).end_with("ath.rs")) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- From 2242add0d04fd40f2b20889d92e4d55b255d6171 Mon Sep 17 00:00:00 2001 From: Lukas Potthast Date: Wed, 17 Sep 2025 21:51:34 +0200 Subject: [PATCH 8/9] Adept new header assertions to new structure --- assertr/src/assertions/http/header_value.rs | 58 ++++++++++++++++----- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/assertr/src/assertions/http/header_value.rs b/assertr/src/assertions/http/header_value.rs index cd37c9d..3f92deb 100644 --- a/assertr/src/assertions/http/header_value.rs +++ b/assertr/src/assertions/http/header_value.rs @@ -4,14 +4,44 @@ use crate::prelude::{BoolAssertions, PartialEqAssertions, PartialOrdAssertions}; pub trait HttpHeaderValueAssertions<'t, M: Mode> { fn is_empty(self) -> Self; + fn be_empty(self) -> Self + where + Self: Sized, + { + self.is_empty() + } fn is_not_empty(self) -> Self; + fn not_be_empty(self) -> Self + where + Self: Sized, + { + self.is_not_empty() + } fn is_sensitive(self) -> Self; + fn be_sensitive(self) -> Self + where + Self: Sized, + { + self.is_sensitive() + } fn is_insensitive(self) -> Self; + fn be_insensitive(self) -> Self + where + Self: Sized, + { + self.is_sensitive() + } fn is_ascii(self) -> AssertThat<'t, String, M>; + fn be_ascii(self) -> AssertThat<'t, String, M> + where + Self: Sized, + { + self.is_ascii() + } } impl<'t, M: Mode> HttpHeaderValueAssertions<'t, M> @@ -63,7 +93,7 @@ mod tests { async fn succeeds_when_matching() { let actual = HeaderValue::from_str("http/1.1").expect("valid header value"); - assert_that(actual).has_debug_value("http/1.1"); + actual.must().have_debug_value("http/1.1"); } } @@ -76,14 +106,14 @@ mod tests { fn succeeds_when_empty() { let actual = HeaderValue::from_str("").expect("valid header value"); - assert_that(actual).is_empty(); + actual.must().be_empty(); } #[test] fn panics_when_not_empty() { let actual = HeaderValue::from_str("http/1.1").expect("valid header value"); - assert_that_panic_by(|| assert_that(actual).with_location(false).is_empty()) + assert_that_panic_by(|| actual.must().with_location(false).be_empty()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -108,14 +138,14 @@ mod tests { fn succeeds_when_not_empty() { let actual = HeaderValue::from_str("http/1.1").expect("valid header value"); - assert_that(actual).is_not_empty(); + actual.must().not_be_empty(); } #[test] fn panics_when_empty() { let actual = HeaderValue::from_str("").expect("valid header value"); - assert_that_panic_by(|| assert_that(actual).with_location(false).is_not_empty()) + assert_that_panic_by(|| actual.must().with_location(false).not_be_empty()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -143,7 +173,7 @@ mod tests { let mut actual = HeaderValue::from_str("http/1.1").expect("valid header value"); actual.set_sensitive(true); - assert_that(actual).is_sensitive(); + actual.must().be_sensitive(); } #[test] @@ -151,7 +181,7 @@ mod tests { let mut actual = HeaderValue::from_str("http/1.1").expect("valid header value"); actual.set_sensitive(false); - assert_that_panic_by(|| assert_that(actual).with_location(false).is_sensitive()) + assert_that_panic_by(|| actual.must().with_location(false).be_sensitive()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -176,7 +206,7 @@ mod tests { fn not_sensitive_by_default() { let actual = HeaderValue::from_str("http/1.1").expect("valid header value"); - assert_that(actual).is_insensitive(); + actual.must().be_insensitive(); } #[test] @@ -184,7 +214,7 @@ mod tests { let mut actual = HeaderValue::from_str("http/1.1").expect("valid header value"); actual.set_sensitive(false); - assert_that(actual).is_insensitive(); + actual.must().be_insensitive(); } #[test] @@ -192,7 +222,7 @@ mod tests { let mut actual = HeaderValue::from_str("http/1.1").expect("valid header value"); actual.set_sensitive(true); - assert_that_panic_by(|| assert_that(actual).with_location(false).is_insensitive()) + assert_that_panic_by(|| actual.must().with_location(false).be_insensitive()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -217,21 +247,21 @@ mod tests { async fn succeeds_when_constructed_from_visible_ascii_characters_through_str() { let actual = HeaderValue::from_str("http/1.1").expect("valid header value"); - assert_that(actual).is_ascii().is_equal_to("http/1.1"); + actual.must().be_ascii().be_equal_to("http/1.1"); } #[tokio::test] async fn succeeds_when_constructed_from_visible_ascii_characters_through_bytes() { let actual = HeaderValue::from_bytes(&[32, 33, 34]).expect("valid header value"); - assert_that(actual).is_ascii().is_equal_to(" !\""); + actual.must().be_ascii().be_equal_to(" !\""); } #[tokio::test] async fn panics_when_constructed_from_non_ascii_characters_through_str() { let actual = HeaderValue::from_str("Ä").expect("valid header value"); - assert_that_panic_by(|| assert_that(actual).with_location(false).is_ascii()) + assert_that_panic_by(|| actual.must().with_location(false).be_ascii()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -250,7 +280,7 @@ mod tests { async fn panics_when_constructed_from_non_ascii_characters_through_bytes() { let actual = HeaderValue::from_bytes(&[32, 33, 255]).expect("valid header value"); - assert_that_panic_by(|| assert_that(actual).with_location(false).is_ascii()) + assert_that_panic_by(|| actual.must().with_location(false).be_ascii()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- From 81c4ffa46d0f53c825c8e0da5fb869fc7d570e8f Mon Sep 17 00:00:00 2001 From: Lukas Potthast Date: Wed, 17 Sep 2025 21:57:22 +0200 Subject: [PATCH 9/9] Fix tests --- assertr/src/assertions/http/header_value.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assertr/src/assertions/http/header_value.rs b/assertr/src/assertions/http/header_value.rs index 3f92deb..2eb49b3 100644 --- a/assertr/src/assertions/http/header_value.rs +++ b/assertr/src/assertions/http/header_value.rs @@ -32,7 +32,7 @@ pub trait HttpHeaderValueAssertions<'t, M: Mode> { where Self: Sized, { - self.is_sensitive() + self.is_insensitive() } fn is_ascii(self) -> AssertThat<'t, String, M>; @@ -78,7 +78,7 @@ impl<'t, M: Mode> HttpHeaderValueAssertions<'t, M> fn is_ascii(self) -> AssertThat<'t, String, M> { use crate::prelude::ResultAssertions; - self.map(|it| it.unwrap_owned().to_str().map(|it| it.to_owned()).into()) + self.map(|it| it.borrowed().to_str().map(|it| it.to_owned()).into()) .is_ok() } }

(self, expected: impl AsRef<[P]>) -> Self where P: Fn(&T) -> bool, // predicate { @@ -89,6 +89,6 @@ mod tests { fn assert_vec_contains_exactly() { let vec = vec![1, 2, 3]; - assert_that(vec).into_iter_contains_exactly([1, 2, 3]); + assert_that_owned(vec).into_iter_contains_exactly([1, 2, 3]); } } diff --git a/assertr/src/assertions/core/array.rs b/assertr/src/assertions/core/array.rs index 4bbd4f1..35d158d 100644 --- a/assertr/src/assertions/core/array.rs +++ b/assertr/src/assertions/core/array.rs @@ -7,9 +7,25 @@ pub trait ArrayAssertions { where T: PartialEq; + fn contain_exactly>(self, expected: E) -> Self + where + T: PartialEq, + Self: Sized, + { + self.contains_exactly(expected) + } + fn contains_exactly_in_any_order>(self, expected: E) -> Self where T: PartialEq; + + fn contain_exactly_in_any_order>(self, expected: E) -> Self + where + T: PartialEq, + Self: Sized, + { + self.contains_exactly_in_any_order(expected) + } } /// Assertions for generic arrays. @@ -43,18 +59,18 @@ mod tests { #[test] fn contains_exactly_succeeds_when_exact_match() { - assert_that([1, 2, 3]).contains_exactly([1, 2, 3]); + assert_that!([1, 2, 3]).contains_exactly([1, 2, 3]); } #[test] fn contains_exactly_succeeds_when_exact_match_provided_as_slice() { - assert_that([1, 2, 3]).contains_exactly(&[1, 2, 3]); + assert_that!([1, 2, 3]).contains_exactly(&[1, 2, 3]); } #[test] fn contains_exactly_panics_when_not_exact_match() { assert_that_panic_by(|| { - assert_that([1, 2, 3]) + assert_that!([1, 2, 3]) .with_location(false) .contains_exactly([3, 4, 1]) }) @@ -90,7 +106,7 @@ mod tests { #[test] fn contains_exactly_panics_with_detail_message_when_only_differing_in_order() { assert_that_panic_by(|| { - assert_that([1, 2, 3]) + assert_that!([1, 2, 3]) .with_location(false) .contains_exactly([3, 2, 1]) }) @@ -120,13 +136,13 @@ mod tests { #[test] fn contains_exactly_in_any_order_succeeds_when_slices_match() { - assert_that([1, 2, 3]).contains_exactly_in_any_order([2, 3, 1]); + assert_that!([1, 2, 3]).contains_exactly_in_any_order([2, 3, 1]); } #[test] fn contains_exactly_in_any_order_panics_when_slice_contains_unknown_data() { assert_that_panic_by(|| { - assert_that([1, 2, 3]) + assert_that!([1, 2, 3]) .with_location(false) .contains_exactly_in_any_order([2, 3, 4]) }) diff --git a/assertr/src/assertions/core/bool.rs b/assertr/src/assertions/core/bool.rs index 32e5efc..9fa369b 100644 --- a/assertr/src/assertions/core/bool.rs +++ b/assertr/src/assertions/core/bool.rs @@ -3,7 +3,21 @@ use crate::{AssertThat, Mode, tracking::AssertionTracking}; /// Assertions for boolean values. pub trait BoolAssertions { fn is_true(self) -> Self; + fn be_true(self) -> Self + where + Self: Sized, + { + self.is_true() + } + fn is_false(self) -> Self; + + fn be_false(self) -> Self + where + Self: Sized, + { + self.is_false() + } } impl BoolAssertions for AssertThat<'_, bool, M> { @@ -43,12 +57,12 @@ mod tests { #[test] fn succeeds_when_true() { - assert_that(true).is_true(); + true.must().be_true(); } #[test] fn panics_when_false() { - assert_that_panic_by(|| assert_that(false).with_location(false).is_true()) + assert_that_panic_by(|| false.must().with_location(false).be_true()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -66,12 +80,12 @@ mod tests { #[test] fn succeeds_when_false() { - assert_that(false).is_false(); + false.must().be_false(); } #[test] fn panics_when_true() { - assert_that_panic_by(|| assert_that(true).with_location(false).is_false()) + assert_that_panic_by(|| true.must().with_location(false).be_false()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- diff --git a/assertr/src/assertions/core/char.rs b/assertr/src/assertions/core/char.rs index 373f51a..7088c95 100644 --- a/assertr/src/assertions/core/char.rs +++ b/assertr/src/assertions/core/char.rs @@ -8,14 +8,49 @@ use crate::tracking::AssertionTracking; pub trait CharAssertions { fn is_equal_to_ignoring_ascii_case(self, expected: char) -> Self; + fn be_equal_to_ignoring_ascii_case(self, expected: char) -> Self + where + Self: Sized, + { + self.is_equal_to_ignoring_ascii_case(expected) + } + fn is_lowercase(self) -> Self; + fn be_lowercase(self) -> Self + where + Self: Sized, + { + self.is_lowercase() + } + fn is_uppercase(self) -> Self; + fn be_uppercase(self) -> Self + where + Self: Sized, + { + self.is_uppercase() + } + fn is_ascii_lowercase(self) -> Self; + fn be_ascii_lowercase(self) -> Self + where + Self: Sized, + { + self.is_ascii_lowercase() + } + fn is_ascii_uppercase(self) -> Self; + fn be_ascii_uppercase(self) -> Self + where + Self: Sized, + { + self.is_ascii_uppercase() + } + //fn is_ascii(self) -> Self; //fn is_whitespace(self) -> Self; //fn is_alphabetic(self) -> Self; @@ -107,13 +142,13 @@ mod tests { #[test] fn succeeds_when_equal_ignoring_ascii_case() { - assert_that('a').is_equal_to_ignoring_ascii_case('A'); + assert_that!('a').is_equal_to_ignoring_ascii_case('A'); } #[test] fn panics_when_not_equal_to_ignoring_ascii_case() { assert_that_panic_by(|| { - assert_that('a') + assert_that!('a') .with_location(false) .is_equal_to_ignoring_ascii_case('B') }) diff --git a/assertr/src/assertions/core/debug.rs b/assertr/src/assertions/core/debug.rs index 0fa4d3d..2eac593 100644 --- a/assertr/src/assertions/core/debug.rs +++ b/assertr/src/assertions/core/debug.rs @@ -6,31 +6,31 @@ use core::fmt::Debug; /// Assertions for values implementing [Debug]. pub trait DebugAssertions { /// Test that actual has the `expected` `Debug` representation. - fn have_debug_string(self, expected: impl AsRef) -> Self; + fn has_debug_string(self, expected: impl AsRef) -> Self; /// Test that actual has the `expected` `Debug` representation. - fn has_debug_string(self, expected: impl AsRef) -> Self + fn have_debug_string(self, expected: impl AsRef) -> Self where Self: Sized, { - self.have_debug_string(expected) + self.has_debug_string(expected) } /// Test that actual and expected have the same `Debug` representation. - fn have_debug_value(self, expected: impl Debug) -> Self; + fn has_debug_value(self, expected: impl Debug) -> Self; /// Test that actual and expected have the same `Debug` representation. - fn has_debug_value(self, expected: impl Debug) -> Self + fn have_debug_value(self, expected: impl Debug) -> Self where Self: Sized, { - self.have_debug_value(expected) + self.has_debug_value(expected) } } impl DebugAssertions for AssertThat<'_, T, M> { #[track_caller] - fn have_debug_string(self, expected: impl AsRef) -> Self { + fn has_debug_string(self, expected: impl AsRef) -> Self { self.track_assertion(); let actual_string = format!("{:?}", self.actual()); @@ -53,7 +53,7 @@ impl DebugAssertions for AssertThat<'_, T, M> { } #[track_caller] - fn have_debug_value(self, expected: impl Debug) -> Self { + fn has_debug_value(self, expected: impl Debug) -> Self { self.track_assertion(); let actual_string = format!("{:?}", self.actual()); @@ -100,7 +100,7 @@ mod tests { #[test] fn panics_when_not_equal() { - assert_that_panic_by(|| assert_that(42).with_location(false).has_debug_string("foo")) + assert_that_panic_by(|| 42.must().with_location(false).have_debug_string("foo")) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -134,7 +134,7 @@ mod tests { #[test] fn panics_when_not_equal() { - assert_that_panic_by(|| assert_that(42).with_location(false).has_debug_value(43)) + assert_that_panic_by(|| 42.must().with_location(false).have_debug_value(43)) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -154,13 +154,9 @@ mod tests { #[test] fn panics_when_trying_to_compare_with_string_containing_escaped_characters_although_user_would_expect_this_to_be_successful() { - assert_that_panic_by(|| { - assert_that("\n") - .with_location(false) - .has_debug_value(r#"\n"#) - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| "\n".must().with_location(false).have_debug_value(r#"\n"#)) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Expected: "\\\\n" @@ -183,11 +179,12 @@ mod tests { #[test] fn succeeds_when_equal_using_value() { - assert_that(Person { + Person { age: 42, alive: true, - }) - .has_debug_value(Person { + } + .must_owned() + .have_debug_value(Person { age: 42, alive: true, }); @@ -195,35 +192,37 @@ mod tests { #[test] fn succeeds_when_equal_using_borrowed_value() { - let expected = Person { + Person { age: 42, alive: true, - }; - assert_that(Person { + } + .must_owned() + .have_debug_value(&Person { age: 42, alive: true, - }) - .has_debug_value(&expected); + }); } #[test] fn succeeds_when_equal_using_string_representation() { - assert_that(Person { + Person { age: 42, alive: true, - }) - .has_debug_string("Person { age: 42, alive: true }"); + } + .must_owned() + .have_debug_string("Person { age: 42, alive: true }"); } #[test] fn panics_when_not_equal() { assert_that_panic_by(|| { - assert_that(Person { + Person { age: 42, alive: true, - }) + } + .must_owned() .with_location(false) - .has_debug_string("foo") + .have_debug_string("foo") }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/core/display.rs b/assertr/src/assertions/core/display.rs index 54a4471..d893b21 100644 --- a/assertr/src/assertions/core/display.rs +++ b/assertr/src/assertions/core/display.rs @@ -5,23 +5,23 @@ use crate::assertions::core::strip_quotation_marks; use crate::{AssertThat, Mode, tracking::AssertionTracking}; pub trait DisplayAssertions { - fn have_display_value(self, expected: impl Display) -> Self; + fn has_display_value(self, expected: impl Display) -> Self; - fn has_display_value(self, expected: impl Display) -> Self + fn have_display_value(self, expected: impl Display) -> Self where Self: Sized, { - self.have_display_value(expected) + self.has_display_value(expected) } } impl DisplayAssertions for AssertThat<'_, T, M> { #[track_caller] - fn have_display_value(self, expected: impl Display) -> Self { + fn has_display_value(self, expected: impl Display) -> Self { self.track_assertion(); let actual_string = format!("{}", self.actual()); - let expected_string = format!("{}", expected); + let expected_string = format!("{expected}"); let actual_str = strip_quotation_marks(actual_string.as_str()); let expected_str = strip_quotation_marks(expected_string.as_str()); @@ -56,13 +56,9 @@ mod tests { #[test] fn panics_when_not_equal() { - assert_that_panic_by(|| { - assert_that(42) - .with_location(false) - .has_display_value("foo") - }) - .has_type::() - .is_equal_to(formatdoc! {r#" + assert_that_panic_by(|| 42.must().with_location(false).have_display_value("foo")) + .has_type::() + .is_equal_to(formatdoc! {r#" -------- assertr -------- Expected: "foo" @@ -78,15 +74,16 @@ mod tests { #[test] fn succeeds_when_equal_using_string_representation() { - assert_that("foo:bar").has_display_value("foo:bar"); + "foo:bar".must().have_display_value("foo:bar"); } #[test] fn panics_when_not_equal() { assert_that_panic_by(|| { - assert_that("foo:bar") + "foo:bar" + .must() .with_location(false) - .has_display_value("foo:baz") + .have_display_value("foo:baz") }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -122,22 +119,24 @@ mod tests { #[test] fn succeeds_when_equal_using_string_representation() { - assert_that(Person { + Person { age: 42, alive: true, - }) - .has_display_value("PERSON"); + } + .must() + .have_display_value("PERSON"); } #[test] fn panics_when_not_equal() { assert_that_panic_by(|| { - assert_that(Person { + Person { age: 42, alive: true, - }) + } + .must() .with_location(false) - .has_display_value("foo") + .have_display_value("foo") }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/core/fn.rs b/assertr/src/assertions/core/fn.rs index a3d4f2c..f8e907c 100644 --- a/assertr/src/assertions/core/fn.rs +++ b/assertr/src/assertions/core/fn.rs @@ -10,10 +10,27 @@ pub trait FnOnceAssertions<'t, R, M: Mode> { #[cfg(feature = "std")] fn panics(self) -> AssertThat<'t, PanicValue, M>; + #[cfg(feature = "std")] + fn panic(self) -> AssertThat<'t, PanicValue, M> + where + Self: Sized, + { + self.panics() + } + #[cfg(feature = "std")] fn does_not_panic(self) -> AssertThat<'t, R, M> where R: Debug; + + #[cfg(feature = "std")] + fn not_panic(self) -> AssertThat<'t, R, M> + where + R: Debug, + Self: Sized, + { + self.does_not_panic() + } } impl<'t, R, F: FnOnce() -> R, M: Mode> FnOnceAssertions<'t, R, M> for AssertThat<'t, F, M> { @@ -87,7 +104,7 @@ mod tests { #[test] fn succeeds_when_panic_occurs() { - assert_that(|| unimplemented!()) + assert_that_owned(|| unimplemented!()) .panics() .has_type::<&str>() .is_equal_to("not implemented"); @@ -95,7 +112,7 @@ mod tests { #[test] fn panics_when_no_panic_occurs() { - assert_that_panic_by(|| assert_that(|| 42).with_location(false).panics()) + assert_that_panic_by(|| assert_that_owned(|| 42).with_location(false).panics()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -113,13 +130,13 @@ mod tests { #[test] fn succeeds_when_no_panic_occurs() { - assert_that(|| 42).does_not_panic(); + assert_that_owned(|| 42).does_not_panic(); } #[test] fn fails_when_panic_occurs() { assert_that_panic_by(|| { - assert_that(|| unimplemented!()) + assert_that_owned(|| unimplemented!()) .with_location(false) .does_not_panic() }) diff --git a/assertr/src/assertions/core/iter.rs b/assertr/src/assertions/core/iter.rs index c9c0be3..505e4c0 100644 --- a/assertr/src/assertions/core/iter.rs +++ b/assertr/src/assertions/core/iter.rs @@ -12,6 +12,17 @@ pub trait IteratorAssertions<'t, T: Debug, M: Mode> { T: AssertrPartialEq, 't: 'u; + /// This is a terminal assertion, as it must consume the underlying iterator. + fn contain<'u, E>(self, expected: E) -> AssertThat<'u, (), M> + where + E: Debug, + T: AssertrPartialEq, + 't: 'u, + Self: Sized, + { + self.contains(expected) + } + /// This is a terminal assertion, as it must consume the underlying iterator. fn contains_exactly<'u, E>(self, expected: impl AsRef<[E]>) -> AssertThat<'u, (), M> where @@ -19,6 +30,18 @@ pub trait IteratorAssertions<'t, T: Debug, M: Mode> { T: PartialEq, T: AssertrPartialEq + Debug, 't: 'u; + + /// This is a terminal assertion, as it must consume the underlying iterator. + fn contain_exactly<'u, E>(self, expected: impl AsRef<[E]>) -> AssertThat<'u, (), M> + where + E: Debug, + T: PartialEq, + T: AssertrPartialEq + Debug, + 't: 'u, + Self: Sized, + { + self.contains_exactly(expected) + } } impl<'t, T, I, M: Mode> IteratorAssertions<'t, T, M> for AssertThat<'t, I, M> @@ -34,6 +57,7 @@ where 't: 'u, { self.track_assertion(); + // Any iterator can only be iterated once! Take it. let (actual, this) = self.replace_actual_with(Actual::Owned(())); let actual = actual.unwrap_owned().collect::>(); @@ -189,13 +213,15 @@ mod tests { fn succeeds_when_value_is_present() { let values = [1, 2, 3]; let iter = values.iter(); - assert_that(iter).contains(&1); + // TODO: We could also call must() which would lead to a panic, as we cannot + // "unwrap_owned" an owned Iterator anymore. + iter.must_owned().contain(&1); } #[test] fn compiles_for_comparable_but_different_type() { let values = vec!["foo"]; - assert_that(values).into_iter_contains("foo".to_string()); + values.must().into_iter_contains("foo".to_string()); } } } @@ -208,7 +234,7 @@ mod tests { #[test] fn succeeds_when_value_is_present() { let values = vec![1, 2, 3, 42]; - assert_that(values) + assert_that_owned(values) .into_iter_contains(1) .into_iter_contains(42) .into_iter_contains(3) @@ -218,7 +244,7 @@ mod tests { #[test] fn compiles_for_comparable_but_different_type() { let values = vec!["foo"]; - assert_that(values).into_iter_contains("foo".to_string()); + assert_that_owned(values).into_iter_contains("foo".to_string()); } } } diff --git a/assertr/src/assertions/core/length.rs b/assertr/src/assertions/core/length.rs index 4aae2c1..8461f52 100644 --- a/assertr/src/assertions/core/length.rs +++ b/assertr/src/assertions/core/length.rs @@ -9,15 +9,29 @@ use indoc::writedoc; pub trait LengthAssertions { fn is_empty(self) -> Self; + fn be_empty(self) -> Self + where + Self: Sized, + { + self.is_empty() + } + fn is_not_empty(self) -> Self; - fn have_length(self, expected: usize) -> Self; + fn not_be_empty(self) -> Self + where + Self: Sized, + { + self.is_not_empty() + } + + fn has_length(self, expected: usize) -> Self; - fn has_length(self, expected: usize) -> Self + fn have_length(self, expected: usize) -> Self where Self: Sized, { - self.have_length(expected) + self.has_length(expected) } } @@ -57,7 +71,7 @@ impl LengthAssertions for AssertThat<'_, T, M> { } #[track_caller] - fn have_length(self, expected: usize) -> Self { + fn has_length(self, expected: usize) -> Self { self.track_assertion(); let actual_len = self.actual().length(); if actual_len != expected { @@ -86,12 +100,12 @@ mod tests { #[test] fn succeeds_when_empty() { let arr: [i32; 0] = []; - assert_that(arr).is_empty(); + arr.must().be_empty(); } #[test] fn panics_when_not_empty() { - assert_that_panic_by(|| assert_that([1, 2, 3]).with_location(false).is_empty()) + assert_that_panic_by(|| [1, 2, 3].assert().with_location(false).is_empty()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -115,13 +129,13 @@ mod tests { #[test] fn with_slice_succeeds_when_empty() { let slice: &[i32] = [].as_slice(); - assert_that(slice).is_empty(); + slice.must().be_empty(); } #[test] fn with_slice_panics_when_not_empty() { assert_that_panic_by(|| { - assert_that([42].as_slice()).with_location(false).is_empty(); + [42].as_slice().assert().with_location(false).is_empty(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -142,13 +156,13 @@ mod tests { #[test] fn succeeds_when_empty() { - assert_that("").is_empty(); + "".must().be_empty(); } #[test] fn panics_when_not_empty() { assert_that_panic_by(|| { - assert_that("foo").with_location(false).is_empty(); + "foo".assert().with_location(false).is_empty(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -167,15 +181,13 @@ mod tests { #[test] fn succeeds_when_empty() { - assert_that(String::from("")).is_empty(); + String::from("").must().be_empty(); } #[test] fn panics_when_not_empty() { assert_that_panic_by(|| { - assert_that(String::from("foo")) - .with_location(false) - .is_empty(); + String::from("foo").assert().with_location(false).is_empty(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -199,13 +211,13 @@ mod tests { #[test] fn with_slice_succeeds_when_empty() { let vec = Vec::::new(); - assert_that(vec).is_empty(); + vec.must().be_empty(); } #[test] fn with_slice_panics_when_not_empty() { assert_that_panic_by(|| { - assert_that(vec![42]).with_location(false).is_empty(); + vec![42].assert().with_location(false).is_empty(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -230,7 +242,7 @@ mod tests { #[test] fn succeeds_when_map_is_empty() { let map = HashMap::<(), ()>::new(); - assert_that(map).is_empty(); + map.must().be_empty(); } #[test] @@ -238,7 +250,7 @@ mod tests { assert_that_panic_by(|| { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map).with_location(false).is_empty(); + map.assert().with_location(false).is_empty(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -264,14 +276,14 @@ mod tests { fn succeeds_when_map_is_empty() { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map).is_not_empty(); + map.must().not_be_empty(); } #[test] fn panics_when_map_is_empty() { assert_that_panic_by(|| { let map = HashMap::<(), ()>::new(); - assert_that(map).with_location(false).is_not_empty(); + map.assert().with_location(false).is_not_empty(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -290,21 +302,21 @@ mod tests { #[test] fn succeeds_when_expected_length_matches() { - assert_that("foo bar").has_length(7); + "foo bar".must().have_length(7); } #[test] fn panics_when_expected_length_does_not_match() { assert_that_panic_by(|| { - assert_that("foo bar").with_location(false).has_length(42); + "foo bar".assert().with_location(false).has_length(42); }) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- Actual: &str "foo bar" - + does not have the correct length - + Expected: 42 Actual: 7 -------- assertr -------- @@ -318,13 +330,14 @@ mod tests { #[test] fn succeeds_when_expected_length_matches() { - assert_that(String::from("foo bar")).has_length(7); + String::from("foo bar").must().have_length(7); } #[test] fn panics_when_expected_length_does_not_match() { assert_that_panic_by(|| { - assert_that(String::from("foo bar")) + String::from("foo bar") + .assert() .with_location(false) .has_length(42); }) @@ -343,27 +356,24 @@ mod tests { } mod has_length_on_slice { - use indoc::formatdoc; - use crate::prelude::*; + use indoc::formatdoc; #[test] fn succeeds_when_length_matches_and_empty() { let slice: &[i32] = [].as_slice(); - assert_that(slice).has_length(0); + slice.must().have_length(0); } #[test] fn succeeds_when_length_matches_and_non_empty() { let slice: &[i32] = [1, 2, 3].as_slice(); - assert_that(slice).has_length(3); + slice.must().have_length(3); } #[test] fn panics_when_length_does_not_match() { assert_that_panic_by(|| { - assert_that([42].as_slice()) - .with_location(false) - .has_length(2); + [42].as_slice().must().with_location(false).have_length(2); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -388,19 +398,17 @@ mod tests { #[test] fn succeeds_when_length_matches_and_empty() { - let vec = Vec::::new(); - assert_that(vec).has_length(0); + Vec::::new().must().have_length(0); } #[test] fn succeeds_when_length_matches_and_non_empty() { - let vec = vec![1, 2, 3]; - assert_that(vec).has_length(3); + vec![1, 2, 3].must().have_length(3); } #[test] fn panics_when_length_does_not_match() { assert_that_panic_by(|| { - assert_that(vec![42]).with_location(false).has_length(2); + vec![42].assert().with_location(false).has_length(2); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -426,8 +434,7 @@ mod tests { #[test] fn succeeds_when_length_matches_and_empty() { - let map = HashMap::<(), ()>::new(); - assert_that(map).has_length(0); + HashMap::<(), ()>::new().must().have_length(0); } #[test] @@ -436,7 +443,7 @@ mod tests { map.insert("foo", "bar"); map.insert("bar", "baz"); map.insert("baz", "foo"); - assert_that(map).has_length(3); + map.must().have_length(3); } #[test] @@ -444,7 +451,7 @@ mod tests { assert_that_panic_by(|| { let mut map = HashMap::new(); map.insert("foo", "bar"); - assert_that(map).with_location(false).has_length(2); + map.assert().with_location(false).has_length(2); }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/core/option.rs b/assertr/src/assertions/core/option.rs index aefe061..eb2d001 100644 --- a/assertr/src/assertions/core/option.rs +++ b/assertr/src/assertions/core/option.rs @@ -8,7 +8,7 @@ pub trait OptionAssertions<'t, T, M: Mode> { /// This is a terminal operation on the contained `Option`, /// as there is nothing meaningful to do with the option if its variant was ensured. /// This allows you to chain additional expectations on the contained success value. - fn be_some(self) -> AssertThat<'t, T, M> + fn is_some(self) -> AssertThat<'t, T, M> where T: Debug; @@ -16,36 +16,36 @@ pub trait OptionAssertions<'t, T, M: Mode> { /// This is a terminal operation on the contained `Option`, /// as there is nothing meaningful to do with the option if its variant was ensured. /// This allows you to chain additional expectations on the contained success value. - fn is_some(self) -> AssertThat<'t, T, M> + fn be_some(self) -> AssertThat<'t, T, M> where T: Debug, Self: Sized, { - self.be_some() + self.is_some() } /// Test if this option is of the `None` variant. /// This is a terminal operation on the contained `Option`, /// as there is nothing meaningful to do with the option after its variant was ensured. - fn be_none(self) -> AssertThat<'t, (), M> + fn is_none(self) -> AssertThat<'t, (), M> where T: Debug; /// Test if this option is of the `None` variant. /// This is a terminal operation on the contained `Option`, /// as there is nothing meaningful to do with the option after its variant was ensured. - fn is_none(self) -> AssertThat<'t, (), M> + fn be_none(self) -> AssertThat<'t, (), M> where T: Debug, Self: Sized, { - self.be_none() + self.is_none() } } impl<'t, T, M: Mode> OptionAssertions<'t, T, M> for AssertThat<'t, Option, M> { #[track_caller] - fn be_some(self) -> AssertThat<'t, T, M> + fn is_some(self) -> AssertThat<'t, T, M> where T: Debug, { @@ -65,7 +65,7 @@ impl<'t, T, M: Mode> OptionAssertions<'t, T, M> for AssertThat<'t, Option, M> } #[track_caller] - fn be_none(self) -> AssertThat<'t, (), M> + fn is_none(self) -> AssertThat<'t, (), M> where T: Debug, { @@ -95,13 +95,9 @@ mod tests { #[test] fn panics_when_none() { - assert_that_panic_by(|| { - assert_that(Option::::None) - .with_location(false) - .is_some() - }) - .has_type::() - .is_equal_to(formatdoc! {" + assert_that_panic_by(|| Option::::None.assert().with_location(false).is_some()) + .has_type::() + .is_equal_to(formatdoc! {" -------- assertr -------- Actual: None @@ -118,16 +114,16 @@ mod tests { #[test] fn succeeds_when_none() { - assert_that(Option::::None).is_none(); + Option::::None.must().be_none(); } #[test] fn panics_when_some() { assert_that_panic_by(|| { Option::::Some(42) - .must() + .assert() .with_location(false) - .be_none() + .is_none() }) .has_type::() .is_equal_to(formatdoc! {" diff --git a/assertr/src/assertions/core/partial_eq.rs b/assertr/src/assertions/core/partial_eq.rs index d2f7d13..b820183 100644 --- a/assertr/src/assertions/core/partial_eq.rs +++ b/assertr/src/assertions/core/partial_eq.rs @@ -6,29 +6,38 @@ use indoc::writedoc; use crate::{AssertThat, AssertrPartialEq, EqContext, Mode, tracking::AssertionTracking}; pub trait PartialEqAssertions { - fn be_equal_to(self, expected: E) -> Self + fn is_equal_to(self, expected: E) -> Self where T: AssertrPartialEq + Debug, E: Debug; - fn is_equal_to(self, expected: E) -> Self + fn be_equal_to(self, expected: E) -> Self where T: AssertrPartialEq + Debug, E: Debug, Self: Sized, { - self.be_equal_to(expected) + self.is_equal_to(expected) } fn is_not_equal_to(self, expected: E) -> Self where T: AssertrPartialEq + Debug, E: Debug; + + fn be_not_equal_to(self, expected: E) -> Self + where + T: AssertrPartialEq + Debug, + E: Debug, + Self: Sized, + { + self.is_not_equal_to(expected) + } } impl PartialEqAssertions for AssertThat<'_, T, M> { #[track_caller] - fn be_equal_to(self, expected: E) -> Self + fn is_equal_to(self, expected: E) -> Self where T: AssertrPartialEq + Debug, E: Debug, @@ -89,14 +98,14 @@ mod tests { #[test] fn succeeds_when_equal() { - assert_that("foo").is_equal_to("foo"); - assert_that("foo".to_owned()).is_equal_to("foo".to_owned()); - assert_that::<&String>(&"foo".to_owned()).is_equal_to(&"foo".to_owned()); + "foo".must().be_equal_to("foo"); + "foo".to_string().must().be_equal_to("foo".to_string()); + "foo".to_string().must().be_equal_to("foo"); } #[test] fn panics_when_not_equal() { - assert_that_panic_by(|| assert_that("foo").with_location(false).is_equal_to("bar")) + assert_that_panic_by(|| "foo".assert().with_location(false).is_equal_to("bar")) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -121,7 +130,7 @@ mod tests { } } - assert_that(Foo {}).is_equal_to(Bar {}); + Foo {}.must().be_equal_to(Bar {}); } } } diff --git a/assertr/src/assertions/core/partial_ord.rs b/assertr/src/assertions/core/partial_ord.rs index 1741c59..61594c8 100644 --- a/assertr/src/assertions/core/partial_ord.rs +++ b/assertr/src/assertions/core/partial_ord.rs @@ -9,20 +9,56 @@ pub trait PartialOrdAssertions { E: Debug, T: PartialOrd; + fn be_less_than(self, expected: impl Borrow) -> Self + where + E: Debug, + T: PartialOrd, + Self: Sized, + { + self.is_less_than(expected) + } + fn is_greater_than(self, expected: impl Borrow) -> Self where E: Debug, T: PartialOrd; + fn be_greater_than(self, expected: impl Borrow) -> Self + where + E: Debug, + T: PartialOrd, + Self: Sized, + { + self.is_greater_than(expected) + } + fn is_less_or_equal_to(self, expected: impl Borrow) -> Self where E: Debug, T: PartialOrd; + fn be_less_or_equal_to(self, expected: impl Borrow) -> Self + where + E: Debug, + T: PartialOrd, + Self: Sized, + { + self.is_less_or_equal_to(expected) + } + fn is_greater_or_equal_to(self, expected: impl Borrow) -> Self where E: Debug, T: PartialOrd; + + fn be_greater_or_equal_to(self, expected: impl Borrow) -> Self + where + E: Debug, + T: PartialOrd, + Self: Sized, + { + self.is_greater_or_equal_to(expected) + } } impl PartialOrdAssertions for AssertThat<'_, T, M> { @@ -115,37 +151,37 @@ mod tests { #[test] fn is_less_than_succeeds_when_less() { - assert_that(3).is_less_than(4); - assert_that(3).is_less_than(&4); + 3.must().be_less_than(4); + 3.must().be_less_than(&4); } #[test] fn is_greater_than_succeeds_when_greater() { - assert_that(7).is_greater_than(6); - assert_that(7).is_greater_than(&6); + 7.must().be_greater_than(6); + 7.must().be_greater_than(&6); } #[test] fn is_less_or_equal_to_than_succeeds_when_less() { - assert_that(3).is_less_or_equal_to(4); - assert_that(3).is_less_or_equal_to(&4); + 3.must().be_less_or_equal_to(4); + 3.must().be_less_or_equal_to(&4); } #[test] fn is_less_or_equal_to_than_succeeds_when_equal() { - assert_that(3).is_less_or_equal_to(3); - assert_that(3).is_less_or_equal_to(&3); + 3.must().be_less_or_equal_to(3); + 3.must().be_less_or_equal_to(&3); } #[test] fn is_greater_or_equal_to_succeeds_when_greater() { - assert_that(7).is_greater_or_equal_to(6); - assert_that(7).is_greater_or_equal_to(&6); + 7.must().be_greater_or_equal_to(6); + 7.must().be_greater_or_equal_to(&6); } #[test] fn is_greater_or_equal_to_succeeds_when_equal() { - assert_that(7).is_greater_or_equal_to(7); - assert_that(7).is_greater_or_equal_to(&7); + 7.must().be_greater_or_equal_to(7); + 7.must().be_greater_or_equal_to(&7); } } diff --git a/assertr/src/assertions/core/poll.rs b/assertr/src/assertions/core/poll.rs index e93a054..2732eec 100644 --- a/assertr/src/assertions/core/poll.rs +++ b/assertr/src/assertions/core/poll.rs @@ -10,7 +10,21 @@ use crate::tracking::AssertionTracking; pub trait PollAssertions<'t, T, M: Mode> { fn is_pending(self) -> Self; + fn be_pending(self) -> Self + where + Self: Sized, + { + self.is_pending() + } + fn is_ready(self) -> AssertThat<'t, T, M>; + + fn be_ready(self) -> AssertThat<'t, T, M> + where + Self: Sized, + { + self.is_ready() + } } impl<'t, T: Debug, M: Mode> PollAssertions<'t, T, M> for AssertThat<'t, Poll, M> { @@ -71,17 +85,19 @@ mod tests { #[test] fn succeeds_when_ready() { - assert_that(Poll::Ready(Foo { val: 42 })) - .is_ready() - .is_equal_to(Foo { val: 42 }); + Poll::Ready(Foo { val: 42 }) + .must() + .be_ready() + .be_equal_to(Foo { val: 42 }); } #[test] fn panics_when_not_ready() { assert_that_panic_by(|| { - assert_that(Poll::::Pending) + Poll::::Pending + .assert() .with_location(false) - .is_ready() + .is_ready(); }) .has_type::() .is_equal_to(formatdoc! {r#" @@ -102,15 +118,16 @@ mod tests { #[test] fn succeeds_when_pending() { - assert_that(Poll::::Pending).is_pending(); + Poll::::Pending.must().be_pending(); } #[test] fn panics_when_ready() { assert_that_panic_by(|| { - assert_that(Poll::Ready(Foo { val: 42 })) + Poll::Ready(Foo { val: 42 }) + .assert() .with_location(false) - .is_pending() + .is_pending(); }) .has_type::() .is_equal_to(formatdoc! {r#" diff --git a/assertr/src/assertions/core/range.rs b/assertr/src/assertions/core/range.rs index 17d861f..34000b0 100644 --- a/assertr/src/assertions/core/range.rs +++ b/assertr/src/assertions/core/range.rs @@ -13,10 +13,26 @@ pub trait RangeBoundAssertions> { R: Debug, B: PartialOrd + Debug; + fn contain_element(&self, expected: B) + where + R: Debug, + B: PartialOrd + Debug, + { + self.contains_element(expected) + } + fn does_not_contain_element(&self, expected: B) where R: Debug, B: PartialOrd + Debug; + + fn not_contain_element(&self, expected: B) + where + R: Debug, + B: PartialOrd + Debug, + { + self.does_not_contain_element(expected) + } } /// Assertions for any type `B` that can interact with a range `R` (using bound type `B`). @@ -25,10 +41,26 @@ pub trait RangeAssertions { where B: PartialOrd + Debug; + fn be_in_range(self, expected: impl RangeBounds) -> Self + where + B: PartialOrd + Debug, + Self: Sized, + { + self.is_in_range(expected) + } + fn is_not_in_range(self, expected: impl RangeBounds) -> Self where B: PartialOrd + Debug; + fn not_be_in_range(self, expected: impl RangeBounds) -> Self + where + B: PartialOrd + Debug, + Self: Sized, + { + self.is_not_in_range(expected) + } + fn is_outside_of_range(self, expected: impl RangeBounds) -> Self where Self: Sized, @@ -36,6 +68,14 @@ pub trait RangeAssertions { { self.is_not_in_range(expected) } + + fn be_outside_of_range(self, expected: impl RangeBounds) -> Self + where + Self: Sized, + B: PartialOrd + Debug, + { + self.is_outside_of_range(expected) + } } impl, M: Mode> RangeBoundAssertions for AssertThat<'_, R, M> { @@ -152,18 +192,19 @@ mod tests { #[test] fn succeeds_when_element_is_contained() { - assert_that("aa"..="zz").contains_element("aa"); - assert_that("aa"..="zz").contains_element("ab"); - assert_that("aa"..="zz").contains_element("ac"); - assert_that("aa"..="zz").contains_element("zx"); - assert_that("aa"..="zz").contains_element("zy"); - assert_that("aa"..="zz").contains_element("zz"); + ("aa"..="zz").must().contain_element("aa"); + ("aa"..="zz").must().contain_element("ab"); + ("aa"..="zz").must().contain_element("ac"); + ("aa"..="zz").must().contain_element("zx"); + ("aa"..="zz").must().contain_element("zy"); + ("aa"..="zz").must().contain_element("zz"); } #[test] fn panics_when_element_is_not_contained() { assert_that_panic_by(|| { - assert_that("aa".."zz") + ("aa".."zz") + .assert() .with_location(false) .contains_element("zz") }) @@ -184,14 +225,15 @@ mod tests { #[test] fn succeeds_when_element_is_not_contained() { - assert_that("aa"..="zz").does_not_contain_element("a"); - assert_that("aa"..="zz").does_not_contain_element("AA"); + ("aa"..="zz").must().not_contain_element("a"); + ("aa"..="zz").must().not_contain_element("AA"); } #[test] fn panics_when_element_is_contained() { assert_that_panic_by(|| { - assert_that("aa".."zz") + ("aa".."zz") + .assert() .with_location(false) .does_not_contain_element("cc") }) @@ -212,14 +254,14 @@ mod tests { #[test] fn succeeds_when_in_range() { - assert_that('a').is_in_range('a'..='z'); - assert_that('p').is_in_range('a'..='z'); - assert_that('z').is_in_range('a'..='z'); + 'a'.must().be_in_range('a'..='z'); + 'p'.must().be_in_range('a'..='z'); + 'z'.must().be_in_range('a'..='z'); } #[test] fn panics_when_not_in_range() { - assert_that_panic_by(|| assert_that('A').with_location(false).is_in_range('a'..='z')) + assert_that_panic_by(|| 'A'.assert().with_location(false).is_in_range('a'..='z')) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -236,14 +278,14 @@ mod tests { #[test] fn succeeds_when_not_in_range() { - assert_that(-1).is_not_in_range(0..=7); - assert_that(8).is_not_in_range(0..=7); - assert_that(9).is_not_in_range(0..=7); + (-1).must().not_be_in_range(0..=7); + 8.must().not_be_in_range(0..=7); + 9.must().not_be_in_range(0..=7); } #[test] fn panics_when_in_range() { - assert_that_panic_by(|| assert_that(5).with_location(false).is_not_in_range(0..=7)) + assert_that_panic_by(|| 5.assert().with_location(false).is_not_in_range(0..=7)) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- diff --git a/assertr/src/assertions/core/ref_cell.rs b/assertr/src/assertions/core/ref_cell.rs index fdaa4ab..5d64a81 100644 --- a/assertr/src/assertions/core/ref_cell.rs +++ b/assertr/src/assertions/core/ref_cell.rs @@ -9,18 +9,34 @@ pub trait RefCellAssertions { /// Check that the RefCell is immutably or mutably borrowed. fn is_borrowed(self) -> Self; + /// Check that the RefCell is immutably or mutably borrowed. + fn be_borrowed(self) -> Self + where + Self: Sized, + { + self.is_borrowed() + } + /// Check that the RefCell is mutably borrowed. fn is_mutably_borrowed(self) -> Self; + /// Check that the RefCell is mutably borrowed. + fn be_mutably_borrowed(self) -> Self + where + Self: Sized, + { + self.is_mutably_borrowed() + } + /// Check that the RefCell is not mutably borrowed, wither by being not borrowed at all, or only borrowed immutably. - fn not_be_mutably_borrowed(self) -> Self; + fn is_not_mutably_borrowed(self) -> Self; /// Check that the RefCell is not mutably borrowed, wither by being not borrowed at all, or only borrowed immutably. - fn is_not_mutably_borrowed(self) -> Self + fn not_be_mutably_borrowed(self) -> Self where Self: Sized, { - self.not_be_mutably_borrowed() + self.is_not_mutably_borrowed() } } @@ -58,7 +74,7 @@ impl RefCellAssertions for AssertThat<'_, RefCell, M> { } #[track_caller] - fn not_be_mutably_borrowed(self) -> Self { + fn is_not_mutably_borrowed(self) -> Self { self.track_assertion(); let actual = self.actual(); if actual.try_borrow_mut().is_ok() { @@ -86,7 +102,7 @@ mod tests { fn succeeds_when_borrowed() { let cell = RefCell::new(42); let borrow = cell.borrow(); - assert_that!(&cell).is_borrowed(); + cell.must().be_borrowed(); drop(borrow); } @@ -94,14 +110,14 @@ mod tests { fn succeeds_when_mutably_borrowed() { let cell = RefCell::new(42); let borrow = cell.borrow_mut(); - assert_that!(&cell).is_borrowed(); + cell.must().be_borrowed(); drop(borrow); } #[test] fn panics_when_not_borrowed() { let cell = RefCell::new(42); - assert_that_panic_by(|| assert_that!(&cell).with_location(false).is_borrowed()) + assert_that_panic_by(|| cell.assert().with_location(false).is_borrowed()) .has_type::() .is_equal_to(formatdoc! {r#" -------- assertr -------- @@ -123,8 +139,8 @@ mod tests { fn succeeds_when_mutably_borrowed() { let cell = RefCell::new(42); let borrow = cell.borrow_mut(); - assert_that!(&cell).is_borrowed(); - assert_that!(&cell).is_mutably_borrowed(); + cell.must().be_borrowed(); + cell.must().be_mutably_borrowed(); drop(borrow); } } @@ -137,7 +153,7 @@ mod tests { fn succeeds_when_not_borrowed_at_all() { let cell = RefCell::new(42); let borrow = cell.borrow(); - cell.must_ref().not_be_mutably_borrowed(); + cell.must().not_be_mutably_borrowed(); drop(borrow); } @@ -145,7 +161,7 @@ mod tests { fn succeeds_when_immutably_borrowed() { let cell = RefCell::new(42); let borrow = cell.borrow(); - assert_that!(&cell).is_not_mutably_borrowed(); + cell.must().not_be_mutably_borrowed(); drop(borrow); } } diff --git a/assertr/src/assertions/core/result.rs b/assertr/src/assertions/core/result.rs index da4bdd3..43f8975 100644 --- a/assertr/src/assertions/core/result.rs +++ b/assertr/src/assertions/core/result.rs @@ -2,64 +2,64 @@ use crate::{AssertThat, actual::Actual, mode::Mode, tracking::AssertionTracking} use core::fmt::Debug; pub trait ResultAssertions<'t, M: Mode, T, E> { - fn be_ok(self) -> AssertThat<'t, T, M> + fn is_ok(self) -> AssertThat<'t, T, M> where T: Debug, E: Debug; - fn is_ok(self) -> AssertThat<'t, T, M> + fn be_ok(self) -> AssertThat<'t, T, M> where T: Debug, E: Debug, Self: Sized, { - self.be_ok() + self.is_ok() } - fn be_err(self) -> AssertThat<'t, E, M> + fn is_err(self) -> AssertThat<'t, E, M> where T: Debug, E: Debug; - fn is_err(self) -> AssertThat<'t, E, M> + fn be_err(self) -> AssertThat<'t, E, M> where T: Debug, E: Debug, Self: Sized, { - self.be_err() + self.is_err() } - fn be_ok_satisfying(self, assertions: A) -> Self + fn is_ok_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, A: for<'a> FnOnce(AssertThat<'a, &'a T, M>); - fn is_ok_satisfying(self, assertions: A) -> Self + fn be_ok_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, A: for<'a> FnOnce(AssertThat<'a, &'a T, M>), Self: Sized, { - self.be_ok_satisfying(assertions) + self.is_ok_satisfying(assertions) } - fn be_err_satisfying(self, assertions: A) -> Self + fn is_err_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, A: for<'a> FnOnce(AssertThat<'a, &'a E, M>); - fn is_err_satisfying(self, assertions: A) -> Self + fn be_err_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, A: for<'a> FnOnce(AssertThat<'a, &'a E, M>), Self: Sized, { - self.be_err_satisfying(assertions) + self.is_err_satisfying(assertions) } } @@ -69,7 +69,7 @@ impl<'t, M: Mode, T, E> ResultAssertions<'t, M, T, E> for AssertThat<'t, Result< /// as there is little meaningful to do with the result if its variant was ensured. /// This allows you to chain additional expectations on the contained success value. #[track_caller] - fn be_ok(self) -> AssertThat<'t, T, M> + fn is_ok(self) -> AssertThat<'t, T, M> where T: Debug, E: Debug, @@ -94,7 +94,7 @@ impl<'t, M: Mode, T, E> ResultAssertions<'t, M, T, E> for AssertThat<'t, Result< /// as there is little meaningful to do with the result if its variant was ensured. /// This allows you to chain additional expectations on the contained error value. #[track_caller] - fn be_err(self) -> AssertThat<'t, E, M> + fn is_err(self) -> AssertThat<'t, E, M> where T: Debug, E: Debug, @@ -116,7 +116,7 @@ impl<'t, M: Mode, T, E> ResultAssertions<'t, M, T, E> for AssertThat<'t, Result< } #[track_caller] - fn be_ok_satisfying(self, assertions: A) -> Self + fn is_ok_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, @@ -136,7 +136,7 @@ impl<'t, M: Mode, T, E> ResultAssertions<'t, M, T, E> for AssertThat<'t, Result< } #[track_caller] - fn be_err_satisfying(self, assertions: A) -> Self + fn is_err_satisfying(self, assertions: A) -> Self where T: Debug, E: Debug, @@ -195,7 +195,8 @@ mod tests { #[test] fn is_err_panics_when_ok() { assert_that_panic_by(|| { - assert_that(Result::::Ok(42)) + Result::::Ok(42) + .assert() .with_location(false) .is_err(); }) diff --git a/assertr/src/assertions/core/slice.rs b/assertr/src/assertions/core/slice.rs index 51a56a9..29f7c52 100644 --- a/assertr/src/assertions/core/slice.rs +++ b/assertr/src/assertions/core/slice.rs @@ -11,6 +11,15 @@ pub trait SliceAssertions<'t, T> { E: Debug, T: AssertrPartialEq + Debug; + fn contain(self, expected: E) -> Self + where + E: Debug, + T: AssertrPartialEq + Debug, + Self: Sized, + { + self.contains(expected) + } + /// Test that the subject contains exactly the expected elements. Order is important. Lengths must be identical. /// /// - [T]: Original subject type. The "actual value" is of type `&[T]` (slice T). @@ -22,15 +31,48 @@ pub trait SliceAssertions<'t, T> { EE: AsRef<[E]>, T: AssertrPartialEq + Debug; + /// Test that the subject contains exactly the expected elements. Order is important. Lengths must be identical. + /// + /// - [T]: Original subject type. The "actual value" is of type `&[T]` (slice T). + /// - [E]: Type of elements in our "expected value" slice. + /// - [EE]: The "expected value". Anything that can be seen as `&[E]` (slice E). Having this extra type, instead of directly accepting `&[E]` allows us to be generic over the input in both the element type and collection type. + fn contain_exactly(self, expected: EE) -> Self + where + E: Debug + 't, + EE: AsRef<[E]>, + T: AssertrPartialEq + Debug, + Self: Sized, + { + self.contains_exactly(expected) + } + fn contains_exactly_in_any_order>(self, expected: E) -> Self where T: PartialEq + Debug; + fn contain_exactly_in_any_order>(self, expected: E) -> Self + where + T: PartialEq + Debug, + Self: Sized, + { + self.contains_exactly_in_any_order(expected) + } + /// [P] - Predicate fn contains_exactly_matching_in_any_order