From 7294bd15d765f7818991ef5aa6fedfa949613b3b Mon Sep 17 00:00:00 2001 From: Matthew Parnell Date: Tue, 14 Aug 2018 11:13:30 +0100 Subject: [PATCH] Add STATIC_REQUIRE for compile time assertions issue #1356 A constant expression can be checked at compile time; if the user wishes to check something they known can be checked at compile time, then they can now STATIC_REQUIRE. By default this will use REQUIRE and be at runtime, such that other assertions can be run. It can be enabled by defining CATCH_USE_STATIC_REQUIRE This uses static_assert; as some compilers cannot handle the modern: static_assert(expr) and require the older form with a message: static_assert(expr, desc) the expression has been included as the message, rather than leaving it as an empty string, which can be a warning on some linters. --- include/catch.hpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/catch.hpp b/include/catch.hpp index 0a49cb31..6ea5cee3 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -144,6 +144,14 @@ #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() +#ifdef CATCH_USE_STATIC_REQUIRE +#define CATCH_STATIC_REQUIRE( expr ) static_assert( expr, #expr ); CATCH_SUCCEED( #expr ) +#define CATCH_STATIC_REQUIRE_FALSE( expr ) static_assert( !(expr), "!(" #expr ")" ); CATCH_SUCCEED( !(#expr) ) +#else // CATCH_USE_STATIC_REQUIRE +#define CATCH_STATIC_REQUIRE( expr ) CATCH_REQUIRE( #expr ) +#define CATCH_STATIC_REQUIRE_FALSE( expr ) CATCH_REQUIRE_FALSE( #expr ) +#endif // CATCH_USE_STATIC_REQUIRE + // "BDD-style" convenience wrappers #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) @@ -203,6 +211,14 @@ #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() +#ifdef CATCH_USE_STATIC_REQUIRE +#define STATIC_REQUIRE( expr ) static_assert( expr, #expr ); SUCCEED( #expr ) +#define STATIC_REQUIRE_FALSE( expr ) static_assert( !(expr), "!(" #expr ")" ); SUCCEED( !(#expr) ) +#else // CATCH_USE_STATIC_REQUIRE +#define STATIC_REQUIRE( expr ) REQUIRE( #expr ) +#define STATIC_REQUIRE_FALSE( expr ) REQUIRE_FALSE( #expr ) +#endif // CATCH_USE_STATIC_REQUIRE + #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) @@ -281,6 +297,9 @@ using Catch::Detail::Approx; #define CATCH_THEN( desc ) #define CATCH_AND_THEN( desc ) +#define CATCH_STATIC_REQUIRE( expr ) (void)(0) +#define CATCH_STATIC_REQUIRE_FALSE( expr ) (void)(0) + // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -331,6 +350,10 @@ using Catch::Detail::Approx; #define SUCCEED( ... ) (void)(0) #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define STATIC_REQUIRE( expr ) (void)(0) +#define STATIC_REQUIRE_FALSE( expr ) (void)(0) + + #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )