diff --git a/src/derived_spec/tests.rs b/src/derived_spec/tests.rs index 10e550f..1f9bfa3 100644 --- a/src/derived_spec/tests.rs +++ b/src/derived_spec/tests.rs @@ -941,8 +941,6 @@ fn extracting_ref_vec_contains_all_in_order() { mod iterator_all_elements { use super::*; - #[cfg(feature = "std")] - use crate::assert_panic_message; #[derive(Debug, Clone)] struct Person { @@ -992,19 +990,16 @@ mod iterator_all_elements { }); } - #[cfg(feature = "std")] #[test] + #[should_panic = "expected numbers.val[1] to be not equal to 4\n but was: 4\n expected: not 4\n"] fn assert_each_element_of_an_iterator_panics_if_one_assertion_fails() { let subject = Numbers(vec![2, 4, 6, 8, 10]); - assert_panic_message!( - assert_that(subject) - .named("numbers") - .extracting_ref("val", |numbers| &numbers.0) - .is_not_empty() - .each_element(|e| e.is_not_equal_to(4)), - "expected numbers.val[1] to be not equal to 4\n but was: 4\n expected: not 4\n" - ); + assert_that(subject) + .named("numbers") + .extracting_ref("val", |numbers| &numbers.0) + .is_not_empty() + .each_element(|e| e.is_not_equal_to(4)); } #[test] diff --git a/src/iterator/tests.rs b/src/iterator/tests.rs index df31ae7..edfae0e 100644 --- a/src/iterator/tests.rs +++ b/src/iterator/tests.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "std")] -use crate::assert_panic_message; use crate::prelude::*; use crate::std::{string::String, vec, vec::Vec}; @@ -296,18 +294,15 @@ mod all_elements { .each_element(|person| person.extracting("name", |p| &p.name).starts_with('J')); } - #[cfg(feature = "std")] #[test] + #[should_panic = "expected numbers [1] to be not equal to 4\n but was: 4\n expected: not 4\n"] fn assert_each_element_of_an_iterator_panics_if_one_assertion_fails() { let subject = [2, 4, 6, 8, 10]; - assert_panic_message!( - assert_that(subject) - .named("numbers") - .is_not_empty() - .each_element(|e| e.is_not_equal_to(4)), - "expected numbers [1] to be not equal to 4\n but was: 4\n expected: not 4\n" - ); + assert_that(subject) + .named("numbers") + .is_not_empty() + .each_element(|e| e.is_not_equal_to(4)); } #[test] diff --git a/src/lib.rs b/src/lib.rs index 8286c50..816b6d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1114,7 +1114,6 @@ pub mod assertions; pub mod colored; pub mod derived_spec; pub mod expectations; -pub mod panic; pub mod prelude; pub mod properties; #[cfg(feature = "recursive")] diff --git a/src/option/mod.rs b/src/option/mod.rs index 774990b..bb494d2 100644 --- a/src/option/mod.rs +++ b/src/option/mod.rs @@ -7,7 +7,7 @@ use crate::spec::{ DiffFormat, DisplayRepresentation, Expectation, Expecting, Expression, FailingStrategy, Invertible, Represent, Represented, RepresentedBy, Spec, }; -use crate::std::{format, string::String}; +use crate::std::{format, panic, string::String}; impl AssertOption for Spec<'_, Option, D, R> where @@ -48,7 +48,7 @@ where let value_representation = self.representation().clone(); self.mapping(|subject| match subject { None => { - crate::panic::trigger_panic("expected the subject to be `Some(_)`, but was `None`") + panic!("expected the subject to be `Some(_)`, but was `None`") }, Some(value) => value, }) @@ -67,7 +67,7 @@ where let value_representation = self.representation().clone(); self.mapping(|subject| match subject { None => { - crate::panic::trigger_panic("expected the subject to be `Some(_)`, but was `None`") + panic!("expected the subject to be `Some(_)`, but was `None`") }, Some(value) => value, }) diff --git a/src/panic/mod.rs b/src/panic/mod.rs deleted file mode 100644 index 3abdd75..0000000 --- a/src/panic/mod.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Handle panics in `std` and `no_std` environments. -//! -//! In assertion functions we use the [`trigger_panic`] function of this module -//! which supports a custom payload in panics when in `std` environment and -//! a string-formatted payload in `no_std` environments. The custom payload adds -//! the ability to verify the location of the test assertion by using the -//! [`assert_panic_location!`] macro. -//! -//! The macros [`assert_panic_location!`] and [`assert_panic_message!`] provide -//! a convenient way for verifying the panic location and the panic message. -//! Note: These macros are intended for testing of assertion functions itself -//! but not for being used in end-user tests testing a project's code. -//! -//! [`assert_panic_location!`]: crate::assert_panic_location -//! [`assert_panic_message!`]: crate::assert_panic_message - -use crate::std::string::String; - -/// Panics with the given message and the location of the caller. -/// -/// Using this function instead of the std `panic!` macro provides the -/// possibility to verify the panic location of assertions by using the macro -/// [`assert_panic_location!`]. -/// -/// In `std`-environments this function triggers a `std::panic::panic_any` with -/// a payload of type [`AssertionPanicPayload`]. In `no_std`-environments it -/// panics with a string-formatted payload. -/// -/// # Panics -/// -/// Calling this function **always** leads to a panic. -/// -/// * If the `std` crate feature is active, the panic is triggered by calling -/// [`std::panic::panic_any`] with a payload of type [`AssertionPanicPayload`]. -/// * In `no_std`-environments it panics with a string-formatted payload using -/// the [`std::panic!`] macro. -/// -/// [`assert_panic_location!`]: crate::assert_panic_location -#[track_caller] -pub fn trigger_panic(message: impl Into) -> ! { - #[cfg(feature = "std")] - { - std::panic::panic_any(AssertionPanicPayload { - message: message.into(), - location: core::panic::Location::caller(), - }) - } - #[cfg(not(feature = "std"))] - { - let message = message.into(); - crate::std::panic!("{message}") - } -} - -/// A payload for panic calls that contains the panic message and the panic -/// location. -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -#[derive(Debug)] -pub struct AssertionPanicPayload { - /// The panic message. - pub message: String, - /// The location where the panic occurred. - pub location: &'static core::panic::Location<'static>, -} - -#[cfg(feature = "std")] -mod std_impl { - use super::AssertionPanicPayload; - use crate::std::{fmt, fmt::Display}; - - impl Display for AssertionPanicPayload { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.message) - } - } -} - -/// Verifies that an assertion panics at the location in the tests. -/// -/// This macro is intended for testing of assertion functions itself but not -/// for being used in end-user tests testing a project's code. -/// -/// The expected location is taken from the line where the macro call starts. -/// This macro works only properly if the given assertion is located at the -/// same line as the macro call. For longer lines it might be necessary to -/// suppress automatic code formatting using the attribute `#[rustfmt::skip]`. -/// -/// # Examples -/// -/// ``` -/// use asserting::prelude::*; -/// use asserting::assert_panic_location; -/// -/// assert_panic_location!(assert_that!(41).is_equal_to(42)); -/// -/// #[rustfmt::skip] -/// assert_panic_location!(assert_that!("some longer assertion").starts_with("some").contains("much longer")); -/// ``` -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -#[macro_export] -macro_rules! assert_panic_location { - ($expression:expr) => {{ - let expected_line = line!(); - let expected_file = file!(); - - let result = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| { - $expression; - })); - - let panic_error = result.expect_err("the assertion should have panicked!"); - let panic_payload = panic_error - .downcast_ref::<$crate::panic::AssertionPanicPayload>() - .expect("panic is not caused by an assertion!"); - - // normalize file path - let expected_file = expected_file.replace("\\", "/"); - let actual_file = panic_payload.location.file().replace("\\", "/"); - let actual_line = panic_payload.location.line(); - - assert!( - actual_file == expected_file && actual_line == expected_line, - "wrong location in panic message!\n expected location: {expected_file}:{expected_line}\n actual location: {actual_file}:{actual_line}", - ); - }}; -} - -/// Verifies that an assertion panics with the given message. -/// -/// This macro is intended for testing of assertion functions itself but not -/// for being used in end-user tests testing a project's code. -/// -/// # Examples -/// -/// ``` -/// use asserting::prelude::*; -/// use asserting::assert_panic_message; -/// -/// assert_panic_message!( -/// assert_that!(41) -/// .with_diff_format(DIFF_FORMAT_RED_YELLOW) -/// .is_zero(), -/// "expected 41 to be zero\n but was: \u{1b}[31m41\u{1b}[0m\n expected: \u{1b}[33m0\u{1b}[0m\n" -/// ); -/// -/// assert_panic_message!( -/// assert_that!(-42) -/// .with_diff_format(DIFF_FORMAT_NO_HIGHLIGHT) -/// .is_positive(), -/// "expected -42 to be positive\n but was: -42\n expected: > 0\n" -/// ); -/// ``` -#[cfg(feature = "std")] -#[macro_export] -macro_rules! assert_panic_message { - ($expression:expr, $expected_message:expr) => {{ - let result = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| { - $expression; - })); - - let panic_error = result.expect_err("the assertion should have panicked!"); - - let actual_message = panic_error - .downcast_ref::<$crate::panic::AssertionPanicPayload>() - .map(|payload| payload.message.clone()) - .or_else(|| panic_error.downcast_ref::().cloned()) - .or_else(|| panic_error.downcast_ref::<&str>().map(ToString::to_string)) - .expect("panic is not caused by an assertion!"); - - let expected_message = $expected_message; - - assert_eq!( - &actual_message, expected_message, - "the panic message differs from the expected one!\n expected message: {expected_message}\n actual message: {actual_message}", - ); - }}; -} diff --git a/src/panic_assertion/mod.rs b/src/panic_assertion/mod.rs index 4aec597..466b918 100644 --- a/src/panic_assertion/mod.rs +++ b/src/panic_assertion/mod.rs @@ -3,7 +3,6 @@ use crate::assertions::AssertCodePanics; use crate::colored::{mark_missing, mark_unexpected}; use crate::expectations::{DoesNotPanic, DoesPanic, does_not_panic, does_panic}; -use crate::panic::AssertionPanicPayload; use crate::spec::{ Code, DebugRepresentation, DiffFormat, DisplayRepresentation, Expectation, Expecting, Expression, FailingStrategy, Spec, @@ -147,9 +146,8 @@ fn read_panic_message(error: Option<&Box>) -> Option { error.and_then(|message| { let message = &**message; message - .downcast_ref::() - .map(|payload| payload.message.clone()) - .or_else(|| message.downcast_ref::().cloned()) + .downcast_ref::() + .cloned() .or_else(|| message.downcast_ref::<&str>().map(ToString::to_string)) }) } diff --git a/src/result/mod.rs b/src/result/mod.rs index 32b8614..11c26a8 100644 --- a/src/result/mod.rs +++ b/src/result/mod.rs @@ -13,7 +13,7 @@ use crate::spec::{ }; use crate::std::fmt::{Debug, Display}; use crate::std::{ - format, + format, panic, string::{String, ToString}, }; @@ -58,9 +58,7 @@ where Ok(value) => value, Err(error) => { let error = Represented::from((&error, &representation)); - crate::panic::trigger_panic(format!( - "expected the subject to be `Ok(_)`, but was `Err({error:?})`" - )) + panic!("expected the subject to be `Ok(_)`, but was `Err({error:?})`") }, }) .represented_by(representation) @@ -71,9 +69,7 @@ where self.mapping(|subject| match subject { Ok(value) => { let value = Represented::from((&value, &representation)); - crate::panic::trigger_panic(format!( - "expected the subject to be `Err(_)`, but was `Ok({value:?})`" - )) + panic!("expected the subject to be `Err(_)`, but was `Ok({value:?})`") }, Err(error) => error, }) @@ -94,9 +90,7 @@ where Ok(value) => value, Err(error) => { let error = Represented::from((error, &representation)); - crate::panic::trigger_panic(format!( - "expected the subject to be `Ok(_)`, but was `Err({error:?})`" - )) + panic!("expected the subject to be `Ok(_)`, but was `Err({error:?})`") }, }) .represented_by(representation) @@ -107,9 +101,7 @@ where self.mapping(|subject| match subject { Ok(value) => { let value = Represented::from((value, &representation)); - crate::panic::trigger_panic(format!( - "expected the subject to be `Err(_)`, but was `Ok({value:?})`" - )) + panic!("expected the subject to be `Err(_)`, but was `Ok({value:?})`") }, Err(error) => error, }) @@ -180,9 +172,9 @@ where Err(error) => Err(error.to_string()), }; self.mapping(|_result| match subject { - Ok(value) => crate::panic::trigger_panic(format!( + Ok(value) => panic!( r"expected the subject to be `Err(_)` with message {expected:?}, but was `{value}`" - )), + ), Err(error) => error, }) .expecting(is_equal_to(expected)) @@ -208,9 +200,9 @@ where Err(error) => Err(error.to_string()), }; self.mapping(|_result| match subject { - Ok(value) => crate::panic::trigger_panic(format!( + Ok(value) => panic!( r"expected the subject to be `Err(_)` with message {expected:?}, but was `{value}`" - )), + ), Err(error) => error, }) .expecting(is_equal_to(expected)) diff --git a/src/spec/mod.rs b/src/spec/mod.rs index 73560a7..39a814f 100644 --- a/src/spec/mod.rs +++ b/src/spec/mod.rs @@ -15,7 +15,7 @@ use crate::std::{ fmt::{self, Debug, Display}, format, ops::Deref, - slice, + panic, slice, string::{String, ToString}, vec, vec::Vec, @@ -1657,7 +1657,7 @@ impl FailingStrategy for PanicOnFail { .map(ToString::to_string) .collect::>() .join("\n"); - crate::panic::trigger_panic(message); + panic!("{message}"); } } diff --git a/src/spec/tests.rs b/src/spec/tests.rs index 2ae12c5..690a817 100644 --- a/src/spec/tests.rs +++ b/src/spec/tests.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "std")] -use crate::assert_panic_message; use crate::prelude::*; use crate::spec::{AssertFailure, Expression, OwnedLocation}; #[cfg(feature = "colored")] @@ -151,17 +149,14 @@ fn assert_that_macro_with_borrowed_str_subject() { assert_that!(input_string).is_equal_to("adipiscing rebum amet iusto"); } -#[cfg(feature = "std")] #[test] +#[should_panic = "expected ultimate_answer to be equal to 42\n but was: 51\n expected: 42\n"] fn assert_that_macro_is_equal_to_with_integers_fails() { let ultimate_answer = 51; - assert_panic_message!( - assert_that!(ultimate_answer) - .with_diff_format(DIFF_FORMAT_NO_HIGHLIGHT) - .is_equal_to(42), - "expected ultimate_answer to be equal to 42\n but was: 51\n expected: 42\n" - ); + assert_that!(ultimate_answer) + .with_diff_format(DIFF_FORMAT_NO_HIGHLIGHT) + .is_equal_to(42); } #[test] @@ -244,49 +239,43 @@ fn soft_assertions_with_chained_assertion_methods() { .soft_panic(); } -#[cfg(feature = "std")] #[test] -fn soft_assertions_panic_once_with_multiple_failure_messages() { - let subject = "the answer to all important questions is 42".to_string(); - - assert_panic_message!( - verify_that(subject) - .contains("unimportant") - .has_at_most_length(41) - .soft_panic(), - "expected subject to contain \"unimportant\"\n \ +#[should_panic = "expected subject to contain \"unimportant\"\n \ but was: \"the answer to all important questions is 42\"\n \ expected: \"unimportant\"\n\ \n\ expected subject to have at most a length of 41\n \ but was: 43\n \ - expected: <= 41\n" - ); + expected: <= 41\n"] +fn soft_assertions_panic_once_with_multiple_failure_messages() { + let subject = "the answer to all important questions is 42".to_string(); + + verify_that(subject) + .contains("unimportant") + .has_at_most_length(41) + .soft_panic(); } #[cfg(feature = "colored")] mod colored { use super::*; - #[cfg(feature = "std")] #[test] + #[should_panic = "expected subject to contain \"unimportant\"\n \ + but was: \"\u{1b}[31mthe answer to all important questions is 42\u{1b}[0m\"\n \ + expected: \"\u{1b}[32munimportant\u{1b}[0m\"\n\ + \n\ + expected subject to have at most a length of 41\n \ + but was: \u{1b}[31m43\u{1b}[0m\n \ + expected: <= \u{1b}[32m41\u{1b}[0m\n"] fn soft_assertions_panic_message_contains_highlighted_diffs() { let subject = "the answer to all important questions is 42"; - assert_panic_message!( - verify_that(subject) - .with_configured_diff_format() - .contains("unimportant") - .has_at_most_length(41) - .soft_panic(), - "expected subject to contain \"unimportant\"\n \ - but was: \"\u{1b}[31mthe answer to all important questions is 42\u{1b}[0m\"\n \ - expected: \"\u{1b}[32munimportant\u{1b}[0m\"\n\ - \n\ - expected subject to have at most a length of 41\n \ - but was: \u{1b}[31m43\u{1b}[0m\n \ - expected: <= \u{1b}[32m41\u{1b}[0m\n" - ); + verify_that(subject) + .with_configured_diff_format() + .contains("unimportant") + .has_at_most_length(41) + .soft_panic(); } #[test] diff --git a/tests/location_in_panic_message.rs b/tests/location_in_panic_message.rs deleted file mode 100644 index 09cdb37..0000000 --- a/tests/location_in_panic_message.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! Tests that assure that the location in the panic message of the various -//! assertions is correct. -#![allow(unused_crate_dependencies)] - -#[cfg(feature = "std")] -mod with_std { - use asserting::assert_panic_location; - use asserting::prelude::*; - - #[test] - fn failing_location_of_is_equal_to() { - assert_panic_location!(assert_that!(2).is_equal_to(1)); - } - - #[test] - fn failing_location_of_is_zero() { - assert_panic_location!(assert_that!(2).is_zero()); - } - - #[test] - fn failing_location_of_is_none() { - assert_panic_location!(assert_that!(Some(42)).is_none()); - } - - #[test] - fn failing_location_of_is_err() { - assert_panic_location!(assert_that!(Ok::<_, String>(42)).is_err()); - } -} - -#[cfg(not(feature = "std"))] -mod with_no_std { - use asserting::prelude::*; - - #[test] - #[should_panic = "expected 2 to be equal to 1\n but was: 2\n expected: 1\n"] - fn a_failing_test_panics_in_no_std_environment() { - assert_that!(2) - .with_diff_format(DIFF_FORMAT_NO_HIGHLIGHT) - .is_equal_to(1); - } -}