From 054d356332a05ce3590b256597105e1f564c4ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Sat, 13 Oct 2018 21:29:59 +0200 Subject: [PATCH] Add STATIC_REQUIRE assertion By default, it expands into a `static_assert` + `SUCCEED` pair, but it can also be deferred to runtime by defining `CATCH_CONFIG_RUNTIME_STATIC_REQUIRE`, which causes it to expand into plain old `REQUIRE`. Closes #1362 Closes #1356 --- include/catch.hpp | 24 +++++++++++++++++++ projects/ExtraTests/X01-PrefixedMacros.cpp | 17 +++++++++---- .../Baselines/compact.sw.approved.txt | 2 ++ .../Baselines/console.std.approved.txt | 4 ++-- .../Baselines/console.sw.approved.txt | 20 ++++++++++++++-- .../SelfTest/Baselines/junit.sw.approved.txt | 3 ++- .../SelfTest/Baselines/xml.sw.approved.txt | 7 ++++-- .../SelfTest/UsageTests/Compilation.tests.cpp | 16 ++++++++----- 8 files changed, 75 insertions(+), 18 deletions(-) diff --git a/include/catch.hpp b/include/catch.hpp index f8b380c4..f6786e8d 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -145,6 +145,15 @@ #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() +#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) +#define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) +#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) +#else +#define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ ) +#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ ) +#endif + + // "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__ ) @@ -205,6 +214,14 @@ #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() +#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) +#define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) +#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) +#else +#define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ ) +#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ ) +#endif + #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) @@ -285,6 +302,9 @@ using Catch::Detail::Approx; #define CATCH_THEN( desc ) #define CATCH_AND_THEN( desc ) +#define CATCH_STATIC_REQUIRE( ... ) (void)(0) +#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0) + // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -335,6 +355,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( ... ) (void)(0) +#define STATIC_REQUIRE_FALSE( ... ) (void)(0) + #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) diff --git a/projects/ExtraTests/X01-PrefixedMacros.cpp b/projects/ExtraTests/X01-PrefixedMacros.cpp index 08bf404f..7671cbc4 100644 --- a/projects/ExtraTests/X01-PrefixedMacros.cpp +++ b/projects/ExtraTests/X01-PrefixedMacros.cpp @@ -2,8 +2,12 @@ // Test that Catch's prefixed macros compile and run properly. #define CATCH_CONFIG_MAIN +// This won't provide full coverage, but it might be worth checking +// the other branch as well +#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE #include +#include #include [[noreturn]] @@ -23,7 +27,7 @@ CATCH_TEST_CASE("PrefixedMacros") { CATCH_REQUIRE_THROWS_WITH(this_throws(), "Some msg"); CATCH_REQUIRE_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate([](std::runtime_error const&) { return true; })); CATCH_REQUIRE_NOTHROW(this_doesnt_throw()); - + CATCH_CHECK( 1 == 1 ); CATCH_CHECK_FALSE( 1 != 1 ); CATCH_CHECKED_IF( 1 == 1 ) { @@ -31,15 +35,15 @@ CATCH_TEST_CASE("PrefixedMacros") { } CATCH_CHECKED_ELSE ( 1 == 1 ) { CATCH_SUCCEED("don't care"); } - + CATCH_CHECK_NOFAIL(1 == 2); - + CATCH_CHECK_THROWS(this_throws()); CATCH_CHECK_THROWS_AS(this_throws(), std::runtime_error); CATCH_CHECK_THROWS_WITH(this_throws(), "Some msg"); CATCH_CHECK_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate([](std::runtime_error const&) { return true; })); - CATCH_CHECK_NOTHROW(this_doesnt_throw()); - + CATCH_CHECK_NOTHROW(this_doesnt_throw()); + CATCH_REQUIRE_THAT("abcd", Equals("abcd")); CATCH_CHECK_THAT("bdef", Equals("bdef")); @@ -52,6 +56,9 @@ CATCH_TEST_CASE("PrefixedMacros") { CATCH_FAIL_CHECK( "failure" ); } } + + CATCH_STATIC_REQUIRE( std::is_void::value ); + CATCH_STATIC_REQUIRE_FALSE( std::is_void::value ); } CATCH_ANON_TEST_CASE() { diff --git a/projects/SelfTest/Baselines/compact.sw.approved.txt b/projects/SelfTest/Baselines/compact.sw.approved.txt index dff69a66..91674957 100644 --- a/projects/SelfTest/Baselines/compact.sw.approved.txt +++ b/projects/SelfTest/Baselines/compact.sw.approved.txt @@ -496,6 +496,8 @@ Exception.tests.cpp:: failed: unexpected exception with message: 'c Tricky.tests.cpp:: passed: True for: {?} Tricky.tests.cpp:: passed: !False for: true Tricky.tests.cpp:: passed: !(False) for: !{?} +Compilation.tests.cpp:: passed: with 1 message: 'std::is_void::value' +Compilation.tests.cpp:: passed: with 1 message: '!(std::is_void::value)' Condition.tests.cpp:: failed: data.int_seven > 7 for: 7 > 7 Condition.tests.cpp:: failed: data.int_seven < 7 for: 7 < 7 Condition.tests.cpp:: failed: data.int_seven > 8 for: 7 > 8 diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 4876305d..525a193c 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -1098,6 +1098,6 @@ due to unexpected exception with message: Why would you throw a std::string? =============================================================================== -test cases: 214 | 161 passed | 49 failed | 4 failed as expected -assertions: 1229 | 1100 passed | 108 failed | 21 failed as expected +test cases: 215 | 162 passed | 49 failed | 4 failed as expected +assertions: 1231 | 1102 passed | 108 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 6f77223c..6642a06e 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -4411,6 +4411,22 @@ PASSED: with expansion: !{?} +------------------------------------------------------------------------------- +Optionally static assertions +------------------------------------------------------------------------------- +Compilation.tests.cpp: +............................................................................... + +Compilation.tests.cpp:: +PASSED: +with message: + std::is_void::value + +Compilation.tests.cpp:: +PASSED: +with message: + !(std::is_void::value) + ------------------------------------------------------------------------------- Ordering comparison checks that should fail ------------------------------------------------------------------------------- @@ -10848,6 +10864,6 @@ Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 214 | 148 passed | 62 failed | 4 failed as expected -assertions: 1243 | 1100 passed | 122 failed | 21 failed as expected +test cases: 215 | 149 passed | 62 failed | 4 failed as expected +assertions: 1245 | 1102 passed | 122 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index 0926d4b0..f3644485 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,7 +1,7 @@ - + @@ -375,6 +375,7 @@ Exception.tests.cpp: + Condition.tests.cpp: diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index cd04fa0d..02509e08 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -4409,6 +4409,9 @@ + + + @@ -11333,7 +11336,7 @@ loose text artifact - + - + diff --git a/projects/SelfTest/UsageTests/Compilation.tests.cpp b/projects/SelfTest/UsageTests/Compilation.tests.cpp index 91b65ca1..325a8142 100644 --- a/projects/SelfTest/UsageTests/Compilation.tests.cpp +++ b/projects/SelfTest/UsageTests/Compilation.tests.cpp @@ -5,13 +5,12 @@ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ +#include + // Setup for #1403 -- look for global overloads of operator << for classes // in a different namespace. - #include - - namespace foo { struct helper_1403 { bool operator==(helper_1403) const { return true; } @@ -25,7 +24,7 @@ std::ostream& operator<<(std::ostream& out, foo::helper_1403 const&) { return out << "[1403 helper]"; } /////////////////////////////// - + #include "catch.hpp" #include @@ -174,12 +173,17 @@ namespace { namespace CompilationTests { TEST_CASE_METHOD((Fixture_1245), "#1245", "[compilation]") { SUCCEED(); } - + TEST_CASE("#1403", "[compilation]") { ::foo::helper_1403 h1, h2; REQUIRE(h1 == h2); } - + + TEST_CASE("Optionally static assertions", "[compilation]") { + STATIC_REQUIRE( std::is_void::value ); + STATIC_REQUIRE_FALSE( std::is_void::value ); + } + }} // namespace CompilationTests