1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef TEST_SUPPORT_ASSERT_MACROS_H 10 #define TEST_SUPPORT_ASSERT_MACROS_H 11 12 // Contains a set of validation macros. 13 // 14 // Note these test were added after C++20 was well supported by the compilers 15 // used. To make the implementation simple the macros require C++20 or newer. 16 // It's not expected that existing tests start to use these new macros. 17 // 18 // These macros are an alternative to using assert. The differences are: 19 // - The assert message isn't localized. 20 // - It's possible to log additional information. This is useful when the 21 // function asserting is a helper function. In these cases the assertion 22 // failure contains to little information to find the issue. For example, in 23 // the format functions, the really useful information is the actual output, 24 // the expected output, and the format string used. These macros allow 25 // logging additional arguments. 26 27 #include "test_macros.h" 28 29 #include <cstdio> 30 #include <cstdlib> 31 32 // This function prints the given arguments to standard error. 33 // 34 // Keeping this as a separate function is important since it provides a single point for 35 // downstreams to customize how errors are printed on exotic targets, if needed. 36 template <class ...Args> 37 void test_eprintf(char const* fmt, Args const& ...args) { 38 std::fprintf(stderr, fmt, args...); 39 } 40 41 void test_log(const char* condition, const char* file, int line, const char* message) { 42 const char* msg = condition ? "Assertion failure: " : "Unconditional failure:"; 43 test_eprintf("%s%s %s %d\n%s", msg, condition, file, line, message); 44 } 45 46 template <class F> 47 void test_log(const char* condition, const char* file, int line, const F& functor) { 48 test_eprintf("Assertion failure: %s %s %d\n", condition, file, line); 49 functor(); 50 } 51 52 template <class Arg> 53 [[noreturn]] void test_fail(const char* file, int line, const Arg& arg) { 54 test_log("", file, line, arg); 55 std::abort(); 56 } 57 58 template <class Arg> 59 void test_require(bool condition, const char* condition_str, const char* file, int line, const Arg& arg) { 60 if (condition) 61 return; 62 63 test_log(condition_str, file, line, arg); 64 std::abort(); 65 } 66 67 // assert(false) replacement 68 // The ARG is either a 69 // - c-string or std::string, in which case the string is printed to stderr, 70 // - an invocable object, which will be invoked. 71 #define TEST_FAIL(ARG) ::test_fail(__FILE__, __LINE__, ARG) 72 73 // assert replacement. 74 // ARG is the same as for TEST_FAIL 75 #define TEST_REQUIRE(CONDITION, ARG) ::test_require(CONDITION, #CONDITION, __FILE__, __LINE__, ARG) 76 77 // LIBCPP_ASSERT replacement 78 // 79 // This requirement is only tested when the test suite is used for libc++. 80 // This allows checking libc++ specific requirements, for example the error 81 // messages of exceptions. 82 // ARG is the same as for TEST_FAIL 83 #if defined(_LIBCPP_VERSION) 84 # define TEST_LIBCPP_REQUIRE(CONDITION, ARG) ::test_require(CONDITION, #CONDITION, __FILE__, __LINE__, ARG) 85 #else 86 # define TEST_LIBCPP_REQUIRE(...) /* DO NOTHING */ 87 #endif 88 89 // Helper macro to test an expression does not throw any exception. 90 #ifndef TEST_HAS_NO_EXCEPTIONS 91 # define TEST_DOES_NOT_THROW(EXPR) \ 92 do { \ 93 try { \ 94 static_cast<void>(EXPR); \ 95 } catch (...) { \ 96 ::test_log(#EXPR, __FILE__, __LINE__, "no exception was expected\n"); \ 97 ::std::abort(); \ 98 } \ 99 } while (false) /* */ 100 101 // Helper macro to test an expression throws an exception of the expected type. 102 # define TEST_THROWS_TYPE(TYPE, EXPR) \ 103 do { \ 104 try { \ 105 static_cast<void>(EXPR); \ 106 ::test_log(nullptr, \ 107 __FILE__, \ 108 __LINE__, \ 109 "no exception is thrown while an exception of type " #TYPE " was expected\n"); \ 110 ::std::abort(); \ 111 } catch (const TYPE&) { \ 112 /* DO NOTHING */ \ 113 } catch (...) { \ 114 ::test_log(nullptr, \ 115 __FILE__, \ 116 __LINE__, \ 117 "the type of the exception caught differs from the expected type " #TYPE "\n"); \ 118 ::std::abort(); \ 119 } \ 120 } while (false) /* */ 121 122 // Helper macro to test an expression throws an exception of the expected type and satisfies a predicate. 123 // 124 // In order to log additional information the predicate can use log macros. 125 // The exception caught is used as argument to the predicate. 126 # define TEST_VALIDATE_EXCEPTION(TYPE, PRED, EXPR) \ 127 do { \ 128 try { \ 129 static_cast<void>(EXPR); \ 130 ::test_log(nullptr, \ 131 __FILE__, \ 132 __LINE__, \ 133 "no exception is thrown while an exception of type " #TYPE " was expected\n"); \ 134 ::std::abort(); \ 135 } catch (const TYPE& EXCEPTION) { \ 136 PRED(EXCEPTION); \ 137 } catch (...) { \ 138 ::test_log(nullptr, \ 139 __FILE__, \ 140 __LINE__, \ 141 "the type of the exception caught differs from the expected type " #TYPE "\n"); \ 142 ::std::abort(); \ 143 } \ 144 } while (false) /* */ 145 146 #else // TEST_HAS_NO_EXCEPTIONS 147 # define TEST_DOES_NOT_THROW(EXPR) static_cast<void>(EXPR); 148 # define TEST_THROWS_TYPE(...) /* DO NOTHING */ 149 # define TEST_VALIDATE_EXCEPTION(...) /* DO NOTHING */ 150 #endif // TEST_HAS_NO_EXCEPTIONS 151 152 #endif // TEST_SUPPORT_ASSERT_MACROS_H 153