/* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2021, Andrew Kaster * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace AK { template void warnln(CheckedFormatString&& fmtstr, Parameters const&...); } namespace Test { // Declare a helper so that we can call it from VERIFY in included headers void current_test_case_did_fail(); } #undef VERIFY #define VERIFY(x) \ do { \ if (!(x)) { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: VERIFY({}) failed", __FILE__, __LINE__, #x); \ ::Test::current_test_case_did_fail(); \ } \ } while (false) #undef VERIFY_NOT_REACHED #define VERIFY_NOT_REACHED() \ do { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: VERIFY_NOT_REACHED() called", __FILE__, __LINE__); \ ::abort(); \ } while (false) #undef TODO #define TODO() \ do { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: TODO() called", __FILE__, __LINE__); \ ::abort(); \ } while (false) #define EXPECT_EQ(a, b) \ do { \ auto lhs = (a); \ auto rhs = (b); \ if (lhs != rhs) { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_EQ({}, {}) failed with lhs={} and rhs={}", __FILE__, __LINE__, #a, #b, FormatIfSupported { lhs }, FormatIfSupported { rhs }); \ ::Test::current_test_case_did_fail(); \ } \ } while (false) #define EXPECT_EQ_TRUTH(a, b) \ do { \ auto lhs = (a); \ auto rhs = (b); \ bool ltruth = static_cast(lhs); \ bool rtruth = static_cast(rhs); \ if (ltruth != rtruth) { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_EQ_TRUTH({}, {}) failed with lhs={} ({}) and rhs={} ({})", \ __FILE__, __LINE__, #a, #b, FormatIfSupported { lhs }, ltruth, FormatIfSupported { rhs }, rtruth); \ ::Test::current_test_case_did_fail(); \ } \ } while (false) // If you're stuck and `EXPECT_EQ` seems to refuse to print anything useful, // try this: It'll spit out a nice compiler error telling you why it doesn't print. #define EXPECT_EQ_FORCE(a, b) \ do { \ auto lhs = (a); \ auto rhs = (b); \ if (lhs != rhs) { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_EQ({}, {}) failed with lhs={} and rhs={}", __FILE__, __LINE__, #a, #b, lhs, rhs); \ ::Test::current_test_case_did_fail(); \ } \ } while (false) #define EXPECT_NE(a, b) \ do { \ auto lhs = (a); \ auto rhs = (b); \ if (lhs == rhs) { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_NE({}, {}) failed with lhs={} and rhs={}", __FILE__, __LINE__, #a, #b, FormatIfSupported { lhs }, FormatIfSupported { rhs }); \ ::Test::current_test_case_did_fail(); \ } \ } while (false) #define EXPECT(x) \ do { \ if (!(x)) { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT({}) failed", __FILE__, __LINE__, #x); \ ::Test::current_test_case_did_fail(); \ } \ } while (false) #define EXPECT_APPROXIMATE_WITH_ERROR(a, b, err) \ do { \ auto expect_close_lhs = a; \ auto expect_close_rhs = b; \ auto expect_close_diff = static_cast(expect_close_lhs) - static_cast(expect_close_rhs); \ if (AK::fabs(expect_close_diff) > (err)) { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_APPROXIMATE({}, {})" \ " failed with lhs={}, rhs={}, (lhs-rhs)={}", \ __FILE__, __LINE__, #a, #b, expect_close_lhs, expect_close_rhs, expect_close_diff); \ ::Test::current_test_case_did_fail(); \ } \ } while (false) #define EXPECT_APPROXIMATE(a, b) EXPECT_APPROXIMATE_WITH_ERROR(a, b, 0.0000005) #define FAIL(message) \ do { \ ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: {}", __FILE__, __LINE__, message); \ ::Test::current_test_case_did_fail(); \ } while (false) // To use, specify the lambda to execute in a sub process and verify it exits: // EXPECT_CRASH("This should fail", []{ // return Test::Crash::Failure::DidNotCrash; // }); #define EXPECT_CRASH(test_message, test_func) \ do { \ Test::Crash crash(test_message, test_func); \ if (!crash.run()) \ ::Test::current_test_case_did_fail(); \ } while (false) #define EXPECT_CRASH_WITH_SIGNAL(test_message, signal, test_func) \ do { \ Test::Crash crash(test_message, test_func, (signal)); \ if (!crash.run()) \ ::Test::current_test_case_did_fail(); \ } while (false) #define EXPECT_NO_CRASH(test_message, test_func) \ do { \ Test::Crash crash(test_message, test_func, 0); \ if (!crash.run()) \ ::Test::current_test_case_did_fail(); \ } while (false) #define TRY_OR_FAIL(expression) \ ({ \ /* Ignore -Wshadow to allow nesting the macro. */ \ AK_IGNORE_DIAGNOSTIC("-Wshadow", \ auto&& _temporary_result = (expression)); \ static_assert(!::AK::Detail::IsLvalueReference, \ "Do not return a reference from a fallible expression"); \ if (_temporary_result.is_error()) [[unlikely]] { \ FAIL(_temporary_result.release_error()); \ return; \ } \ _temporary_result.release_value(); \ })