Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Add defensive_assert! macro #13423

Merged
merged 2 commits into from
Feb 21, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions frame/support/src/traits/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ macro_rules! defensive {
);
debug_assert!(false, "{}", $crate::traits::DEFENSIVE_OP_INTERNAL_ERROR);
};
($error:tt) => {
($error:expr $(,)?) => {
frame_support::log::error!(
target: "runtime",
"{}: {:?}",
Expand All @@ -58,7 +58,7 @@ macro_rules! defensive {
);
debug_assert!(false, "{}: {:?}", $crate::traits::DEFENSIVE_OP_INTERNAL_ERROR, $error);
};
($error:tt, $proof:tt) => {
($error:expr, $proof:expr $(,)?) => {
frame_support::log::error!(
target: "runtime",
"{}: {:?}: {:?}",
Expand All @@ -70,6 +70,29 @@ macro_rules! defensive {
}
}

/// Trigger a defensive failure if a condition is not met.
///
/// Similar to [`assert!`] but will print an error without `debug_assertions` instead of silently
/// ignoring it. Only accepts one instead of variable formatting arguments.
///
/// # Example
///
/// ```
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
/// use frame_support::defensive_assert;
///
/// std::panic::catch_unwind(|| {
/// defensive_assert!(1 == 0, "Must fail")
/// }).unwrap_err();
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
/// ```
#[macro_export]
macro_rules! defensive_assert {
($cond:expr $(, $proof:expr )? $(,)?) => {
if !($cond) {
$crate::defensive!(::core::stringify!($cond) $(, $proof )?);
}
};
}

/// Prelude module for all defensive traits to be imported at once.
pub mod defensive_prelude {
pub use super::{Defensive, DefensiveOption, DefensiveResult};
Expand Down Expand Up @@ -1141,6 +1164,27 @@ mod test {
use sp_core::bounded::{BoundedSlice, BoundedVec};
use sp_std::marker::PhantomData;

#[test]
fn defensive_assert_works() {
defensive_assert!(true);
defensive_assert!(true,);
defensive_assert!(true, "must work");
defensive_assert!(true, "must work",);
}

#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "Defensive failure has been triggered!: \"1 == 0\": \"Must fail\"")]
fn defensive_assert_panics() {
defensive_assert!(1 == 0, "Must fail");
}

#[test]
#[cfg(not(debug_assertions))]
fn defensive_assert_does_not_panic() {
defensive_assert!(1 == 0, "Must fail");
}

#[test]
#[cfg(not(debug_assertions))]
fn defensive_saturating_accrue_works() {
Expand Down