TestCase.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/ByteString.h>
  9. #include <AK/Function.h>
  10. #include <AK/NonnullRefPtr.h>
  11. #include <AK/RefCounted.h>
  12. #include <LibTest/Macros.h>
  13. #include <LibTest/Randomized/RandomnessSource.h>
  14. #include <LibTest/Randomized/Shrink.h>
  15. namespace Test {
  16. using TestFunction = Function<void()>;
  17. inline void run_with_randomness_source(Randomized::RandomnessSource source, TestFunction const& test_function)
  18. {
  19. set_randomness_source(move(source));
  20. set_current_test_result(TestResult::NotRun);
  21. test_function();
  22. if (current_test_result() == TestResult::NotRun) {
  23. set_current_test_result(TestResult::Passed);
  24. }
  25. }
  26. class TestCase : public RefCounted<TestCase> {
  27. public:
  28. TestCase(ByteString const& name, TestFunction&& fn, bool is_benchmark)
  29. : m_name(name)
  30. , m_function(move(fn))
  31. , m_is_benchmark(is_benchmark)
  32. {
  33. }
  34. bool is_benchmark() const { return m_is_benchmark; }
  35. ByteString const& name() const { return m_name; }
  36. TestFunction const& func() const { return m_function; }
  37. static NonnullRefPtr<TestCase> randomized(ByteString const& name, TestFunction&& test_function)
  38. {
  39. using namespace Randomized;
  40. constexpr u8 MAX_GEN_ATTEMPTS_PER_VALUE = 30;
  41. TestFunction test_case_function = [test_function = move(test_function)]() {
  42. u64 max_randomized_runs = randomized_runs();
  43. for (u64 i = 0; i < max_randomized_runs; ++i) {
  44. bool generated_successfully = false;
  45. u8 gen_attempt;
  46. for (gen_attempt = 0; gen_attempt < MAX_GEN_ATTEMPTS_PER_VALUE && !generated_successfully; ++gen_attempt) {
  47. // We're going to run the test function many times, so let's turn off the reporting until we finish.
  48. disable_reporting();
  49. set_current_test_result(TestResult::NotRun);
  50. run_with_randomness_source(RandomnessSource::live(), test_function);
  51. switch (current_test_result()) {
  52. case TestResult::NotRun:
  53. VERIFY_NOT_REACHED();
  54. break;
  55. case TestResult::Passed: {
  56. generated_successfully = true;
  57. break;
  58. }
  59. case TestResult::Failed: {
  60. generated_successfully = true;
  61. RandomRun first_failure = randomness_source().run();
  62. RandomRun best_failure = shrink(first_failure, test_function);
  63. // Run one last time with reporting on, so that the user can see the minimal failure
  64. enable_reporting();
  65. run_with_randomness_source(RandomnessSource::recorded(best_failure), test_function);
  66. return;
  67. }
  68. case TestResult::Rejected:
  69. break;
  70. case TestResult::Overrun:
  71. break;
  72. default:
  73. VERIFY_NOT_REACHED();
  74. break;
  75. }
  76. }
  77. enable_reporting();
  78. if (!generated_successfully) {
  79. // The loop above got to the full MAX_GEN_ATTEMPTS_PER_VALUE and gave up.
  80. // Run one last time with reporting on, so that the user gets the REJECTED message.
  81. RandomRun last_failure = randomness_source().run();
  82. run_with_randomness_source(RandomnessSource::recorded(last_failure), test_function);
  83. return;
  84. }
  85. }
  86. // All randomized_runs() values generated + passed the test.
  87. };
  88. return make_ref_counted<TestCase>(name, move(test_case_function), false);
  89. }
  90. private:
  91. ByteString m_name;
  92. TestFunction m_function;
  93. bool m_is_benchmark;
  94. };
  95. // Helper to hide implementation of TestSuite from users
  96. void add_test_case_to_suite(NonnullRefPtr<TestCase> const& test_case);
  97. void set_suite_setup_function(Function<void()> setup);
  98. }
  99. #define TEST_SETUP \
  100. static void __setup(); \
  101. struct __setup_type { \
  102. __setup_type() \
  103. { \
  104. Test::set_suite_setup_function(__setup); \
  105. } \
  106. }; \
  107. static struct __setup_type __setup_type; \
  108. static void __setup()
  109. // Unit test
  110. #define __TESTCASE_FUNC(x) __test_##x
  111. #define __TESTCASE_TYPE(x) __TestCase_##x
  112. #define TEST_CASE(x) \
  113. static void __TESTCASE_FUNC(x)(); \
  114. struct __TESTCASE_TYPE(x) { \
  115. __TESTCASE_TYPE(x) \
  116. () \
  117. { \
  118. add_test_case_to_suite(adopt_ref(*new ::Test::TestCase(#x, __TESTCASE_FUNC(x), false))); \
  119. } \
  120. }; \
  121. static struct __TESTCASE_TYPE(x) __TESTCASE_TYPE(x); \
  122. static void __TESTCASE_FUNC(x)()
  123. // Benchmark
  124. #define __BENCHMARK_FUNC(x) __benchmark_##x
  125. #define __BENCHMARK_TYPE(x) __BenchmarkCase_##x
  126. #define BENCHMARK_CASE(x) \
  127. static void __BENCHMARK_FUNC(x)(); \
  128. struct __BENCHMARK_TYPE(x) { \
  129. __BENCHMARK_TYPE(x) \
  130. () \
  131. { \
  132. add_test_case_to_suite(adopt_ref(*new ::Test::TestCase(#x, __BENCHMARK_FUNC(x), true))); \
  133. } \
  134. }; \
  135. static struct __BENCHMARK_TYPE(x) __BENCHMARK_TYPE(x); \
  136. static void __BENCHMARK_FUNC(x)()
  137. // Randomized test
  138. #define __RANDOMIZED_TEST_FUNC(x) __randomized_test_##x
  139. #define __RANDOMIZED_TEST_TYPE(x) __RandomizedTestCase_##x
  140. #define RANDOMIZED_TEST_CASE(x) \
  141. static void __RANDOMIZED_TEST_FUNC(x)(); \
  142. struct __RANDOMIZED_TEST_TYPE(x) { \
  143. __RANDOMIZED_TEST_TYPE(x) \
  144. () \
  145. { \
  146. add_test_case_to_suite(::Test::TestCase::randomized(#x, __RANDOMIZED_TEST_FUNC(x))); \
  147. } \
  148. }; \
  149. static struct __RANDOMIZED_TEST_TYPE(x) __RANDOMIZED_TEST_TYPE(x); \
  150. static void __RANDOMIZED_TEST_FUNC(x)()
  151. // This allows us to print the generated locals in the test after a failure is fully shrunk.
  152. #define GEN(identifier, value) \
  153. auto identifier = (value); \
  154. if (::Test::current_test_result() == ::Test::TestResult::Overrun) \
  155. return; \
  156. if (::Test::is_reporting_enabled()) \
  157. ::AK::warnln("{} = {}", #identifier, (identifier))