From 00934bc344666c231490295b9a04bd7f17e04d5e Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Tue, 24 Oct 2023 01:34:46 +0200 Subject: [PATCH] LibTest: Add the REJECT and ASSUME macros REJECT and ASSUME are useful for filtering out unwanted generated values. While this is not ideal, it is ocassionally useful and so we include it for convenience. The main loop of RANDOMIZED_TEST_CASE runs the test case 100 times, each time trying to generate a different set of values. Inside that loop, if it sees a REJECT (ASSUME is implemented in terms of REJECT), it retries up to 15 times before giving up (perhaps it's impossible or just very improbable to generate a value that will survive REJECT or ASSUME). REJECT("Reason for rejecting") will just outright fail, while ASSUME(bool) is more of an equivalent of a .filter() method from functional languages. --- Userland/Libraries/LibTest/Macros.h | 19 +++++++++++++++++++ Userland/Libraries/LibTest/TestResult.h | 5 +++++ Userland/Libraries/LibTest/TestSuite.cpp | 2 ++ 3 files changed, 26 insertions(+) diff --git a/Userland/Libraries/LibTest/Macros.h b/Userland/Libraries/LibTest/Macros.h index 004154ee3e..5f2f3cdd24 100644 --- a/Userland/Libraries/LibTest/Macros.h +++ b/Userland/Libraries/LibTest/Macros.h @@ -109,6 +109,25 @@ void disable_reporting(); #define EXPECT_APPROXIMATE(a, b) EXPECT_APPROXIMATE_WITH_ERROR(a, b, 0.0000005) +#define REJECT(message) \ + do { \ + if (::Test::is_reporting_enabled()) \ + ::AK::warnln("\033[31;1mREJECTED\033[0m: {}:{}: {}", \ + __FILE__, __LINE__, #message); \ + ::Test::set_current_test_result(::Test::TestResult::Rejected); \ + } while (false) + +#define ASSUME(x) \ + do { \ + if (!(x)) { \ + if (::Test::is_reporting_enabled()) \ + ::AK::warnln("\033[31;1mREJECTED\033[0m: {}:{}: Couldn't generate random value satisfying ASSUME({})", \ + __FILE__, __LINE__, #x); \ + ::Test::set_current_test_result(::Test::TestResult::Rejected); \ + return; \ + } \ + } while (false) + #define FAIL(message) \ do { \ if (::Test::is_reporting_enabled()) \ diff --git a/Userland/Libraries/LibTest/TestResult.h b/Userland/Libraries/LibTest/TestResult.h index d63b763800..513a60e5d5 100644 --- a/Userland/Libraries/LibTest/TestResult.h +++ b/Userland/Libraries/LibTest/TestResult.h @@ -18,6 +18,11 @@ enum class TestResult { // Didn't get through EXPECT(...). Failed, + // Didn't get through the ASSUME(...) filter 15 times in a row + // (in a randomized test). + // Alternatively, user used REJECT(...). + Rejected, + // Ran out of RandomRun data (in a randomized test, when shrinking). // This is fine, we'll just try some other shrink. Overrun, diff --git a/Userland/Libraries/LibTest/TestSuite.cpp b/Userland/Libraries/LibTest/TestSuite.cpp index 76076de110..53cd499932 100644 --- a/Userland/Libraries/LibTest/TestSuite.cpp +++ b/Userland/Libraries/LibTest/TestSuite.cpp @@ -103,6 +103,8 @@ static DeprecatedString test_result_to_string(TestResult result) return "Completed"; case TestResult::Failed: return "Failed"; + case TestResult::Rejected: + return "Rejected"; case TestResult::Overrun: return "Ran out of randomness"; default: