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 all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 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,25 @@ 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
///
/// ```should_panic
/// frame_support::defensive_assert!(1 == 0, "Must fail")
/// ```
#[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 +1160,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