From 3adda450dd5bf1b65bca868b455785a9c719c432 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 21 Feb 2023 18:03:17 +0100 Subject: [PATCH] Add `defensive_assert!` macro (#13423) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add defensive_assert macro Signed-off-by: Oliver Tale-Yazdi * Apply review suggestions Co-authored-by: Bastian Köcher Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- frame/support/src/traits/misc.rs | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 734b84ebd9d85..5a13fc4ab6509 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -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", "{}: {:?}", @@ -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", "{}: {:?}: {:?}", @@ -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}; @@ -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() {