diff --git a/AK/TestSuite.h b/AK/TestSuite.h deleted file mode 100644 index 0f062db9a7..0000000000 --- a/AK/TestSuite.h +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace AK { - -template -void warnln(CheckedFormatString&& fmtstr, const Parameters&...); - -// Declare a helper so that we can call it from VERIFY in included headers -// before defining TestSuite -inline void current_test_case_did_fail(); - -} - -using AK::warnln; - -#undef VERIFY -#define VERIFY(x) \ - do { \ - if (!(x)) { \ - ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: VERIFY({}) failed", __FILE__, __LINE__, #x); \ - 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(stderr, "\033[31;1mFAIL\033[0m: {}:{}: TODO() called", __FILE__, __LINE__); \ - ::abort(); \ - } while (false) - -#include -#include -#include -#include -#include -#include -#include - -namespace AK { - -class TestElapsedTimer { -public: - TestElapsedTimer() { restart(); } - - void restart() { gettimeofday(&m_started, nullptr); } - - u64 elapsed_milliseconds() - { - struct timeval now; - gettimeofday(&now, nullptr); - - struct timeval delta; - timersub(&now, &m_started, &delta); - - return delta.tv_sec * 1000 + delta.tv_usec / 1000; - } - -private: - struct timeval m_started; -}; - -using TestFunction = Function; - -class TestCase : public RefCounted { -public: - TestCase(const String& name, TestFunction&& fn, bool is_benchmark) - : m_name(name) - , m_function(move(fn)) - , m_is_benchmark(is_benchmark) - { - } - - bool is_benchmark() const { return m_is_benchmark; } - const String& name() const { return m_name; } - const TestFunction& func() const { return m_function; } - -private: - String m_name; - TestFunction m_function; - bool m_is_benchmark; -}; - -class TestSuite { -public: - static TestSuite& the() - { - if (s_global == nullptr) - s_global = new TestSuite(); - return *s_global; - } - - static void release() - { - if (s_global) - delete s_global; - s_global = nullptr; - } - - int run(const NonnullRefPtrVector&); - int main(const String& suite_name, int argc, char** argv); - NonnullRefPtrVector find_cases(const String& search, bool find_tests, bool find_benchmarks); - void add_case(const NonnullRefPtr& test_case) - { - m_cases.append(test_case); - } - - void current_test_case_did_fail() { m_current_test_case_passed = false; } - -private: - static TestSuite* s_global; - NonnullRefPtrVector m_cases; - u64 m_testtime = 0; - u64 m_benchtime = 0; - String m_suite_name; - bool m_current_test_case_passed = true; -}; - -inline void current_test_case_did_fail() { TestSuite::the().current_test_case_did_fail(); } - -int TestSuite::main(const String& suite_name, int argc, char** argv) -{ - m_suite_name = suite_name; - - Core::ArgsParser args_parser; - - bool do_tests_only = getenv("TESTS_ONLY") != nullptr; - bool do_benchmarks_only = false; - bool do_list_cases = false; - const char* search_string = "*"; - - args_parser.add_option(do_tests_only, "Only run tests.", "tests", 0); - args_parser.add_option(do_benchmarks_only, "Only run benchmarks.", "bench", 0); - args_parser.add_option(do_list_cases, "List available test cases.", "list", 0); - args_parser.add_positional_argument(search_string, "Only run matching cases.", "pattern", Core::ArgsParser::Required::No); - args_parser.parse(argc, argv); - - const auto& matching_tests = find_cases(search_string, !do_benchmarks_only, !do_tests_only); - - if (do_list_cases) { - outln("Available cases for {}:", suite_name); - for (const auto& test : matching_tests) { - outln(" {}", test.name()); - } - return 0; - } - - outln("Running {} cases out of {}.", matching_tests.size(), m_cases.size()); - - return run(matching_tests); -} - -NonnullRefPtrVector TestSuite::find_cases(const String& search, bool find_tests, bool find_benchmarks) -{ - NonnullRefPtrVector matches; - for (const auto& t : m_cases) { - if (!search.is_empty() && !t.name().matches(search, CaseSensitivity::CaseInsensitive)) { - continue; - } - - if (!find_tests && !t.is_benchmark()) { - continue; - } - if (!find_benchmarks && t.is_benchmark()) { - continue; - } - - matches.append(t); - } - return matches; -} - -int TestSuite::run(const NonnullRefPtrVector& tests) -{ - size_t test_count = 0; - size_t test_failed_count = 0; - size_t benchmark_count = 0; - TestElapsedTimer global_timer; - - for (const auto& t : tests) { - const auto test_type = t.is_benchmark() ? "benchmark" : "test"; - - warnln("Running {} '{}'.", test_type, t.name()); - m_current_test_case_passed = true; - - TestElapsedTimer timer; - t.func()(); - const auto time = timer.elapsed_milliseconds(); - - dbgln("{} {} '{}' in {}ms", m_current_test_case_passed ? "Completed" : "Failed", test_type, t.name(), time); - - if (t.is_benchmark()) { - m_benchtime += time; - benchmark_count++; - } else { - m_testtime += time; - test_count++; - } - - if (!m_current_test_case_passed) { - test_failed_count++; - } - } - - dbgln("Finished {} tests and {} benchmarks in {}ms ({}ms tests, {}ms benchmarks, {}ms other).", - test_count, - benchmark_count, - global_timer.elapsed_milliseconds(), - m_testtime, - m_benchtime, - global_timer.elapsed_milliseconds() - (m_testtime + m_benchtime)); - dbgln("Out of {} tests, {} passed and {} failed.", test_count, test_count - test_failed_count, test_failed_count); - - return (int)test_failed_count; -} - -} - -using AK::current_test_case_did_fail; -using AK::TestCase; -using AK::TestSuite; - -#define __TESTCASE_FUNC(x) __test_##x -#define __TESTCASE_TYPE(x) __TestCase_##x - -#define TEST_CASE(x) \ - static void __TESTCASE_FUNC(x)(); \ - struct __TESTCASE_TYPE(x) { \ - __TESTCASE_TYPE(x) \ - () { TestSuite::the().add_case(adopt_ref(*new TestCase(#x, __TESTCASE_FUNC(x), false))); } \ - }; \ - static struct __TESTCASE_TYPE(x) __TESTCASE_TYPE(x); \ - static void __TESTCASE_FUNC(x)() - -#define __BENCHMARK_FUNC(x) __benchmark_##x -#define __BENCHMARK_TYPE(x) __BenchmarkCase_##x - -#define BENCHMARK_CASE(x) \ - static void __BENCHMARK_FUNC(x)(); \ - struct __BENCHMARK_TYPE(x) { \ - __BENCHMARK_TYPE(x) \ - () { TestSuite::the().add_case(adopt_ref(*new TestCase(#x, __BENCHMARK_FUNC(x), true))); } \ - }; \ - static struct __BENCHMARK_TYPE(x) __BENCHMARK_TYPE(x); \ - static void __BENCHMARK_FUNC(x)() - -#define TEST_MAIN(x) \ - TestSuite* TestSuite::s_global = nullptr; \ - template \ - constexpr size_t compiletime_lenof(const char(&)[N]) \ - { \ - return N - 1; \ - } \ - int main(int argc, char** argv) \ - { \ - static_assert(compiletime_lenof(#x) != 0, "Set SuiteName"); \ - int ret = TestSuite::the().main(#x, argc, argv); \ - TestSuite::release(); \ - return ret; \ - } - -#define EXPECT_EQ(a, b) \ - do { \ - auto lhs = (a); \ - auto rhs = (b); \ - if (lhs != rhs) { \ - warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_EQ({}, {}) failed with lhs={} and rhs={}", __FILE__, __LINE__, #a, #b, FormatIfSupported { lhs }, FormatIfSupported { rhs }); \ - 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) { \ - warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_EQ({}, {}) failed with lhs={} and rhs={}", __FILE__, __LINE__, #a, #b, lhs, rhs); \ - current_test_case_did_fail(); \ - } \ - } while (false) - -#define EXPECT(x) \ - do { \ - if (!(x)) { \ - warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT({}) failed", __FILE__, __LINE__, #x); \ - current_test_case_did_fail(); \ - } \ - } while (false) - -#define EXPECT_APPROXIMATE(a, b) \ - 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 (fabs(expect_close_diff) > 0.0000005) { \ - 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); \ - current_test_case_did_fail(); \ - } \ - } while (false) diff --git a/AK/Tests/CMakeLists.txt b/AK/Tests/CMakeLists.txt index e2de8f372d..28c7468a94 100644 --- a/AK/Tests/CMakeLists.txt +++ b/AK/Tests/CMakeLists.txt @@ -61,10 +61,7 @@ set(AK_TEST_SOURCES ) foreach(source ${AK_TEST_SOURCES}) - get_filename_component(name ${source} NAME_WE) - add_executable(${name} ${source}) - target_link_libraries(${name} LibCore) - install(TARGETS ${name} RUNTIME DESTINATION usr/Tests/AK) + serenity_test(${source} AK) endforeach() get_filename_component(TEST_FRM_RESOLVED ./test.frm REALPATH) diff --git a/AK/Tests/TestAllOf.cpp b/AK/Tests/TestAllOf.cpp index c953a14468..48f5d0f7aa 100644 --- a/AK/Tests/TestAllOf.cpp +++ b/AK/Tests/TestAllOf.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -19,5 +19,3 @@ TEST_CASE(should_determine_if_predicate_applies_to_all_elements_in_container) EXPECT(all_of(a.begin(), a.end(), [](auto elem) { return elem == 0; })); EXPECT(!all_of(a.begin(), a.end(), [](auto elem) { return elem == 1; })); } - -TEST_MAIN(AllOf) diff --git a/AK/Tests/TestAnyOf.cpp b/AK/Tests/TestAnyOf.cpp index e85c2fb17b..2fcfaf29e6 100644 --- a/AK/Tests/TestAnyOf.cpp +++ b/AK/Tests/TestAnyOf.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -21,5 +21,3 @@ TEST_CASE(should_determine_if_predicate_applies_to_any_element_in_container) EXPECT(any_of(a.begin(), a.end(), [](auto elem) { return elem == 1; })); EXPECT(!any_of(a.begin(), a.end(), [](auto elem) { return elem == 2; })); } - -TEST_MAIN(AllOf) diff --git a/AK/Tests/TestArray.cpp b/AK/Tests/TestArray.cpp index 901dda2ae5..440a9935ae 100644 --- a/AK/Tests/TestArray.cpp +++ b/AK/Tests/TestArray.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -28,5 +28,3 @@ TEST_CASE(compile_time_iterable) constexpr Array array = { 0, 1, 2, 3, 4, 5, 6, 7 }; static_assert(constexpr_sum(array) == 28); } - -TEST_MAIN(Array) diff --git a/AK/Tests/TestAtomic.cpp b/AK/Tests/TestAtomic.cpp index 0b0aa23bfd..eb7a3843ef 100644 --- a/AK/Tests/TestAtomic.cpp +++ b/AK/Tests/TestAtomic.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -340,5 +340,3 @@ TEST_CASE(fetch_xor) a_u8 = 0xe2; EXPECT((a_u8 ^= 0xef) == 0x0d); } - -TEST_MAIN(Atomic) diff --git a/AK/Tests/TestBadge.cpp b/AK/Tests/TestBadge.cpp index cebd3fdd27..8f12b9dcb3 100644 --- a/AK/Tests/TestBadge.cpp +++ b/AK/Tests/TestBadge.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -12,5 +12,3 @@ TEST_CASE(should_provide_underlying_type) { static_assert(IsSame::Type>); } - -TEST_MAIN(Badge) diff --git a/AK/Tests/TestBase64.cpp b/AK/Tests/TestBase64.cpp index 71a2c36588..698a86c354 100644 --- a/AK/Tests/TestBase64.cpp +++ b/AK/Tests/TestBase64.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -44,5 +44,3 @@ TEST_CASE(test_encode) encode_equal("fooba", "Zm9vYmE="); encode_equal("foobar", "Zm9vYmFy"); } - -TEST_MAIN(Base64) diff --git a/AK/Tests/TestBinaryHeap.cpp b/AK/Tests/TestBinaryHeap.cpp index 10865e84b0..dbd4a9a4af 100644 --- a/AK/Tests/TestBinaryHeap.cpp +++ b/AK/Tests/TestBinaryHeap.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -65,5 +65,3 @@ TEST_CASE(large_populate_reverse) EXPECT_EQ(ints.pop_min(), i); } } - -TEST_MAIN(BinaryHeap) diff --git a/AK/Tests/TestBinarySearch.cpp b/AK/Tests/TestBinarySearch.cpp index 6a7098220d..3e5d65c240 100644 --- a/AK/Tests/TestBinarySearch.cpp +++ b/AK/Tests/TestBinarySearch.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -116,5 +116,3 @@ TEST_CASE(unsigned_to_signed_regression) EXPECT_EQ(binary_search(input, 1u, &nearby_index), &input[1]); EXPECT_EQ(nearby_index, 1u); } - -TEST_MAIN(BinarySearch) diff --git a/AK/Tests/TestBitCast.cpp b/AK/Tests/TestBitCast.cpp index e341e79e12..baf270f9b6 100644 --- a/AK/Tests/TestBitCast.cpp +++ b/AK/Tests/TestBitCast.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -21,5 +21,3 @@ TEST_CASE(double_int_conversion) check_cast_both_ways(static_cast(1) << 63, -0.0); check_cast_both_ways(static_cast(0x4172f58bc0000000), 19880124.0); } - -TEST_MAIN(BitCast) diff --git a/AK/Tests/TestBitmap.cpp b/AK/Tests/TestBitmap.cpp index 5271353a79..b4326dcd54 100644 --- a/AK/Tests/TestBitmap.cpp +++ b/AK/Tests/TestBitmap.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -248,5 +248,3 @@ TEST_CASE(count_in_range) test_with_value(true); test_with_value(false); } - -TEST_MAIN(Bitmap) diff --git a/AK/Tests/TestByteBuffer.cpp b/AK/Tests/TestByteBuffer.cpp index 380022184b..a6fabd7085 100644 --- a/AK/Tests/TestByteBuffer.cpp +++ b/AK/Tests/TestByteBuffer.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -49,5 +49,3 @@ TEST_CASE(negative_operator_lt) // error: error: use of deleted function ‘bool AK::ByteBuffer::operator<(const AK::ByteBuffer&) const’ } #endif /* COMPILE_NEGATIVE_TESTS */ - -TEST_MAIN(ByteBuffer) diff --git a/AK/Tests/TestChecked.cpp b/AK/Tests/TestChecked.cpp index ec98872629..a4c932d696 100644 --- a/AK/Tests/TestChecked.cpp +++ b/AK/Tests/TestChecked.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -386,5 +386,3 @@ TEST_CASE(should_constexpr_make_via_factory) { [[maybe_unused]] constexpr auto value = make_checked(42); } - -TEST_MAIN(Checked) diff --git a/AK/Tests/TestCircularDeque.cpp b/AK/Tests/TestCircularDeque.cpp index 06218cb3f5..3fa5189bb8 100644 --- a/AK/Tests/TestCircularDeque.cpp +++ b/AK/Tests/TestCircularDeque.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -61,5 +61,3 @@ TEST_CASE(deque_end) EXPECT_EQ(ints.dequeue_end(), 0); EXPECT(ints.is_empty()); } - -TEST_MAIN(CircularDeque) diff --git a/AK/Tests/TestCircularDuplexStream.cpp b/AK/Tests/TestCircularDuplexStream.cpp index b2f3fa6ab2..62b5534bfb 100644 --- a/AK/Tests/TestCircularDuplexStream.cpp +++ b/AK/Tests/TestCircularDuplexStream.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -61,5 +61,3 @@ TEST_CASE(overwritting_is_well_defined) EXPECT(stream.eof()); } - -TEST_MAIN(CircularDuplexStream) diff --git a/AK/Tests/TestCircularQueue.cpp b/AK/Tests/TestCircularQueue.cpp index edbbd8a98d..edc3cb5184 100644 --- a/AK/Tests/TestCircularQueue.cpp +++ b/AK/Tests/TestCircularQueue.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -66,5 +66,3 @@ TEST_CASE(should_not_call_value_type_constructor_when_created) CircularQueue queue; EXPECT_EQ(0u, ConstructorCounter::s_num_constructor_calls); } - -TEST_MAIN(CircularQueue) diff --git a/AK/Tests/TestComplex.cpp b/AK/Tests/TestComplex.cpp index b3c9b17735..5079569d18 100644 --- a/AK/Tests/TestComplex.cpp +++ b/AK/Tests/TestComplex.cpp @@ -4,8 +4,9 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include -#include TEST_CASE(Complex) { @@ -41,5 +42,3 @@ TEST_CASE(Complex) EXPECT_APPROXIMATE(cexp(Complex(0., 1.) * M_PI).real(), -1.); #endif } - -TEST_MAIN(Complex) diff --git a/AK/Tests/TestDistinctNumeric.cpp b/AK/Tests/TestDistinctNumeric.cpp index 94638c1a23..1ecc740098 100644 --- a/AK/Tests/TestDistinctNumeric.cpp +++ b/AK/Tests/TestDistinctNumeric.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -283,5 +283,3 @@ TEST_CASE(negative_incompatible) // | DistinctNumeric<[...],true,true,true,true,true,[...],[...],64> } #endif /* COMPILE_NEGATIVE_TESTS */ - -TEST_MAIN(DistinctNumeric) diff --git a/AK/Tests/TestDoublyLinkedList.cpp b/AK/Tests/TestDoublyLinkedList.cpp index d663efbc99..407484e443 100644 --- a/AK/Tests/TestDoublyLinkedList.cpp +++ b/AK/Tests/TestDoublyLinkedList.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -41,5 +41,3 @@ TEST_CASE(should_find_const) EXPECT_EQ(sut.end(), sut.find(42)); } - -TEST_MAIN(DoublyLinkedList) diff --git a/AK/Tests/TestEndian.cpp b/AK/Tests/TestEndian.cpp index 104a281ad6..7f7f1a57ff 100644 --- a/AK/Tests/TestEndian.cpp +++ b/AK/Tests/TestEndian.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -15,5 +15,3 @@ static_assert(BigEndian { 42 } == 42, "Big endian values should be value co static_assert(LittleEndian {} == 0, "Little endian values should be default constructed in a constexpr context."); static_assert(LittleEndian { 42 } == 42, "Little endian values should be value constructed in a constexpr context."); - -TEST_MAIN(Endian); diff --git a/AK/Tests/TestEnumBits.cpp b/AK/Tests/TestEnumBits.cpp index 9a357a1667..dc9eadf32d 100644 --- a/AK/Tests/TestEnumBits.cpp +++ b/AK/Tests/TestEnumBits.cpp @@ -4,8 +4,9 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include -#include enum class VideoIntro : u8 { None = 0x0, @@ -66,5 +67,3 @@ TEST_CASE(has_flag) EXPECT(has_flag(intro, VideoIntro::Friends)); EXPECT(!has_flag(intro, VideoIntro::Well)); } - -TEST_MAIN(EnumBits) diff --git a/AK/Tests/TestFind.cpp b/AK/Tests/TestFind.cpp index d7df2bd9c6..26d4ab11fd 100644 --- a/AK/Tests/TestFind.cpp +++ b/AK/Tests/TestFind.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -52,5 +52,3 @@ TEST_CASE(should_return_index_to_first_predicate_matching_value_in_container) EXPECT(4 == AK::find_index(a.begin(), a.end(), 0)); } - -TEST_MAIN(Find) diff --git a/AK/Tests/TestFormat.cpp b/AK/Tests/TestFormat.cpp index cc7b2db8a4..525082b38f 100644 --- a/AK/Tests/TestFormat.cpp +++ b/AK/Tests/TestFormat.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -290,5 +290,3 @@ TEST_CASE(long_long_regression) EXPECT_EQ(builder.string_view(), "81985529216486895"); } - -TEST_MAIN(Format) diff --git a/AK/Tests/TestGenericLexer.cpp b/AK/Tests/TestGenericLexer.cpp index 6b5d09bef2..8b9a08cd1d 100644 --- a/AK/Tests/TestGenericLexer.cpp +++ b/AK/Tests/TestGenericLexer.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -156,5 +156,3 @@ TEST_CASE(should_constexpr_ignore_until_pred) }(); static_assert(sut.peek() == 'c'); } - -TEST_MAIN(GenericLexer) diff --git a/AK/Tests/TestHashFunctions.cpp b/AK/Tests/TestHashFunctions.cpp index 75c284b355..fa8eafae9e 100644 --- a/AK/Tests/TestHashFunctions.cpp +++ b/AK/Tests/TestHashFunctions.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -59,5 +59,3 @@ TEST_CASE(constexpr_ptr_hash) // "ptr_hash" test binds the result. static_assert(ptr_hash(FlatPtr(42))); } - -TEST_MAIN(HashFunctions) diff --git a/AK/Tests/TestHashMap.cpp b/AK/Tests/TestHashMap.cpp index dac0685d36..a057319309 100644 --- a/AK/Tests/TestHashMap.cpp +++ b/AK/Tests/TestHashMap.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -172,5 +172,3 @@ TEST_CASE(basic_contains) EXPECT_EQ(map.remove(1), true); EXPECT_EQ(map.contains(1), false); } - -TEST_MAIN(HashMap) diff --git a/AK/Tests/TestHashTable.cpp b/AK/Tests/TestHashTable.cpp index a0cae5014c..55c297e774 100644 --- a/AK/Tests/TestHashTable.cpp +++ b/AK/Tests/TestHashTable.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -173,5 +173,3 @@ TEST_CASE(basic_contains) EXPECT_EQ(table.remove(1), true); EXPECT_EQ(table.contains(1), false); } - -TEST_MAIN(HashTable) diff --git a/AK/Tests/TestHex.cpp b/AK/Tests/TestHex.cpp index 7bbf0f8e2a..0f94cc03c8 100644 --- a/AK/Tests/TestHex.cpp +++ b/AK/Tests/TestHex.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -59,5 +59,3 @@ TEST_CASE(should_constexpr_decode_hex_digit) static_assert(14u == decode_hex_digit('E')); static_assert(15u == decode_hex_digit('F')); } - -TEST_MAIN(Hex) diff --git a/AK/Tests/TestIPv4Address.cpp b/AK/Tests/TestIPv4Address.cpp index e0a787ded3..b8f07d1e3c 100644 --- a/AK/Tests/TestIPv4Address.cpp +++ b/AK/Tests/TestIPv4Address.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -151,5 +151,3 @@ TEST_CASE(should_compare) EXPECT(addr_a != addr_b); EXPECT(addr_a == addr_a); } - -TEST_MAIN(IPv4Address) diff --git a/AK/Tests/TestIndexSequence.cpp b/AK/Tests/TestIndexSequence.cpp index d7943873f6..31b9401651 100644 --- a/AK/Tests/TestIndexSequence.cpp +++ b/AK/Tests/TestIndexSequence.cpp @@ -4,8 +4,9 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include -#include #include template @@ -46,5 +47,3 @@ TEST_CASE(TypeList) static_assert(IsSame, bool>, ""); static_assert(IsSame, char>, ""); } - -TEST_MAIN(IndexSequence); diff --git a/AK/Tests/TestIntrusiveList.cpp b/AK/Tests/TestIntrusiveList.cpp index 3e3012bc20..f75db9afb7 100644 --- a/AK/Tests/TestIntrusiveList.cpp +++ b/AK/Tests/TestIntrusiveList.cpp @@ -4,10 +4,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include #include #include -#include class IntrusiveTestItem { public: @@ -120,5 +121,3 @@ TEST_CASE(intrusive_nonnull_ref_ptr_intrusive) EXPECT(nonnull_ref_list.is_empty()); } - -TEST_MAIN(IntrusiveList) diff --git a/AK/Tests/TestIntrusiveRedBlackTree.cpp b/AK/Tests/TestIntrusiveRedBlackTree.cpp index 0271e4af11..207b026cec 100644 --- a/AK/Tests/TestIntrusiveRedBlackTree.cpp +++ b/AK/Tests/TestIntrusiveRedBlackTree.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -114,5 +114,3 @@ TEST_CASE(clear) test.clear(); EXPECT_EQ(test.size(), 0u); } - -TEST_MAIN(RedBlackTree) diff --git a/AK/Tests/TestJSON.cpp b/AK/Tests/TestJSON.cpp index e0c85e1e03..d85f68c2b5 100644 --- a/AK/Tests/TestJSON.cpp +++ b/AK/Tests/TestJSON.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -121,5 +121,3 @@ TEST_CASE(json_duplicate_keys) json.set("test", "baz"); EXPECT_EQ(json.to_string(), "{\"test\":\"baz\"}"); } - -TEST_MAIN(JSON) diff --git a/AK/Tests/TestLexicalPath.cpp b/AK/Tests/TestLexicalPath.cpp index ac96bf58d6..044f5f157a 100644 --- a/AK/Tests/TestLexicalPath.cpp +++ b/AK/Tests/TestLexicalPath.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -74,5 +74,3 @@ TEST_CASE(relative_path) EXPECT_EQ(LexicalPath::relative_path("/tmp/foo.txt", "tmp"), String {}); EXPECT_EQ(LexicalPath::relative_path("tmp/foo.txt", "/tmp"), String {}); } - -TEST_MAIN(LexicalPath) diff --git a/AK/Tests/TestMACAddress.cpp b/AK/Tests/TestMACAddress.cpp index 7f87967f87..f91ae043a2 100644 --- a/AK/Tests/TestMACAddress.cpp +++ b/AK/Tests/TestMACAddress.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -82,5 +82,3 @@ TEST_CASE(should_string_format) MACAddress sut(1, 2, 3, 4, 5, 6); EXPECT_EQ("01:02:03:04:05:06", sut.to_string()); } - -TEST_MAIN(MACAddress) diff --git a/AK/Tests/TestMemMem.cpp b/AK/Tests/TestMemMem.cpp index 8e1266f5c7..f4dd0a3e52 100644 --- a/AK/Tests/TestMemMem.cpp +++ b/AK/Tests/TestMemMem.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -66,5 +66,3 @@ TEST_CASE(kmp_two_chunks) EXPECT_EQ(result_2.value_or(9), 4u); EXPECT(!result_3.has_value()); } - -TEST_MAIN(MemMem) diff --git a/AK/Tests/TestMemoryStream.cpp b/AK/Tests/TestMemoryStream.cpp index 23d1dfff6d..90512fe456 100644 --- a/AK/Tests/TestMemoryStream.cpp +++ b/AK/Tests/TestMemoryStream.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -220,5 +220,3 @@ TEST_CASE(offset_calculation_error_regression) EXPECT_EQ(input, output); } - -TEST_MAIN(MemoryStream) diff --git a/AK/Tests/TestNeverDestroyed.cpp b/AK/Tests/TestNeverDestroyed.cpp index 29931f2757..7b72d6bae3 100644 --- a/AK/Tests/TestNeverDestroyed.cpp +++ b/AK/Tests/TestNeverDestroyed.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -71,5 +71,3 @@ TEST_CASE(should_provide_basic_getter) AK::NeverDestroyed n {}; EXPECT_EQ(0, n.get().num_destroys); } - -TEST_MAIN(NeverDestroyed) diff --git a/AK/Tests/TestNonnullRefPtr.cpp b/AK/Tests/TestNonnullRefPtr.cpp index 19d43fc2e2..c26adadacc 100644 --- a/AK/Tests/TestNonnullRefPtr.cpp +++ b/AK/Tests/TestNonnullRefPtr.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -59,5 +59,3 @@ TEST_CASE(swap_with_self) swap(object, object); EXPECT_EQ(object->ref_count(), 1u); } - -TEST_MAIN(NonnullRefPtr) diff --git a/AK/Tests/TestNumberFormat.cpp b/AK/Tests/TestNumberFormat.cpp index f4f9d64426..373d3bef98 100644 --- a/AK/Tests/TestNumberFormat.cpp +++ b/AK/Tests/TestNumberFormat.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -125,5 +125,3 @@ TEST_CASE(extremes_8byte) warnln("(Skipping 8-byte-size_t test on 32-bit platform)"); } } - -TEST_MAIN(NumberFormat) diff --git a/AK/Tests/TestOptional.cpp b/AK/Tests/TestOptional.cpp index e14c513d0e..583d11f0eb 100644 --- a/AK/Tests/TestOptional.cpp +++ b/AK/Tests/TestOptional.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -53,5 +53,3 @@ TEST_CASE(short_notation) EXPECT_EQ(value->length(), 3u); EXPECT_EQ(*value, "foo"); } - -TEST_MAIN(Optional) diff --git a/AK/Tests/TestQueue.cpp b/AK/Tests/TestQueue.cpp index 12e240c275..6e11e6e685 100644 --- a/AK/Tests/TestQueue.cpp +++ b/AK/Tests/TestQueue.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -57,5 +57,3 @@ TEST_CASE(order) EXPECT(strings.is_empty()); } - -TEST_MAIN(Queue) diff --git a/AK/Tests/TestQuickSort.cpp b/AK/Tests/TestQuickSort.cpp index 70c8c74edc..23fc7692dc 100644 --- a/AK/Tests/TestQuickSort.cpp +++ b/AK/Tests/TestQuickSort.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -98,5 +98,3 @@ TEST_CASE(maximum_stack_depth) delete[] data; } - -TEST_MAIN(QuickSort) diff --git a/AK/Tests/TestRedBlackTree.cpp b/AK/Tests/TestRedBlackTree.cpp index 9940a968c6..51f9549957 100644 --- a/AK/Tests/TestRedBlackTree.cpp +++ b/AK/Tests/TestRedBlackTree.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -86,5 +86,3 @@ TEST_CASE(clear) test.clear(); EXPECT_EQ(test.size(), 0u); } - -TEST_MAIN(RedBlackTree) diff --git a/AK/Tests/TestRefPtr.cpp b/AK/Tests/TestRefPtr.cpp index f8461183f8..8c85ace774 100644 --- a/AK/Tests/TestRefPtr.cpp +++ b/AK/Tests/TestRefPtr.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -147,5 +147,3 @@ TEST_CASE(self_observers) object->unref(); EXPECT_EQ(SelfAwareObject::num_destroyed, 1u); } - -TEST_MAIN(RefPtr) diff --git a/AK/Tests/TestSinglyLinkedList.cpp b/AK/Tests/TestSinglyLinkedList.cpp index 9d5b51c790..3df43d2cb5 100644 --- a/AK/Tests/TestSinglyLinkedList.cpp +++ b/AK/Tests/TestSinglyLinkedList.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -59,5 +59,3 @@ TEST_CASE(should_find_const_with_predicate) EXPECT_EQ(sut.end(), sut.find_if([](const auto v) { return v == 42; })); } - -TEST_MAIN(SinglyLinkedList) diff --git a/AK/Tests/TestSourceGenerator.cpp b/AK/Tests/TestSourceGenerator.cpp index c6cd3fd6ea..9b8a3b7b6c 100644 --- a/AK/Tests/TestSourceGenerator.cpp +++ b/AK/Tests/TestSourceGenerator.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -69,5 +69,3 @@ TEST_CASE(scoped) EXPECT_EQ(global_generator.as_string_view(), "\nfoo-0 bar-0\nfoo-0 bar-0\nfoo-0 bar-0\nfoo-2 bar-0\nfoo-2 bar-3\nfoo-0 bar-0\nfoo-2 bar-0\n"); } - -TEST_MAIN(SourceGenerator) diff --git a/AK/Tests/TestSourceLocation.cpp b/AK/Tests/TestSourceLocation.cpp index 12f2e16c17..15910062f3 100644 --- a/AK/Tests/TestSourceLocation.cpp +++ b/AK/Tests/TestSourceLocation.cpp @@ -5,9 +5,10 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include #include -#include TEST_CASE(basic_scenario) { @@ -29,5 +30,3 @@ TEST_CASE(default_arg_scenario) EXPECT_EQ(expected_calling_function, actual_calling_function); } - -TEST_MAIN(SourceLocation) diff --git a/AK/Tests/TestSpan.cpp b/AK/Tests/TestSpan.cpp index 1b3587d755..2668133c4e 100644 --- a/AK/Tests/TestSpan.cpp +++ b/AK/Tests/TestSpan.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -123,5 +123,3 @@ TEST_CASE(span_from_c_string) const char* str = "Serenity"; [[maybe_unused]] ReadonlyBytes bytes { str, strlen(str) }; } - -TEST_MAIN(Span) diff --git a/AK/Tests/TestString.cpp b/AK/Tests/TestString.cpp index ab5dde54a6..b61828199e 100644 --- a/AK/Tests/TestString.cpp +++ b/AK/Tests/TestString.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -235,5 +235,3 @@ TEST_CASE(sprintf) EXPECT_EQ(String(buf1), String("+12")); EXPECT_EQ(String(buf2), String("-12")); } - -TEST_MAIN(String) diff --git a/AK/Tests/TestStringUtils.cpp b/AK/Tests/TestStringUtils.cpp index 1f13594468..315c14f1da 100644 --- a/AK/Tests/TestStringUtils.cpp +++ b/AK/Tests/TestStringUtils.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -304,5 +304,3 @@ TEST_CASE(to_snakecase) EXPECT_EQ(AK::StringUtils::to_snakecase("FBar"), "f_bar"); EXPECT_EQ(AK::StringUtils::to_snakecase("FooB"), "foo_b"); } - -TEST_MAIN(StringUtils) diff --git a/AK/Tests/TestStringView.cpp b/AK/Tests/TestStringView.cpp index 28a35a301e..2ffbdf65fd 100644 --- a/AK/Tests/TestStringView.cpp +++ b/AK/Tests/TestStringView.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -177,5 +177,3 @@ TEST_CASE(split_view) EXPECT_EQ(test_string_view.split_view_if(predicate), Vector({ "a", "b", "c", "d" })); EXPECT_EQ(test_string_view.split_view_if(predicate, true), Vector({ "a", "", "b", "c", "d" })); } - -TEST_MAIN(StringView) diff --git a/AK/Tests/TestTime.cpp b/AK/Tests/TestTime.cpp index 732450b75d..61319cd605 100644 --- a/AK/Tests/TestTime.cpp +++ b/AK/Tests/TestTime.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -261,5 +261,3 @@ TEST_CASE(truncation) EXPECT_EQ(TIME(9223372036854, 775'807'000).to_truncated_microseconds(), 0x7fff'ffff'ffff'ffff); EXPECT_EQ(TIME(9223372036854, 775'808'000).to_truncated_microseconds(), 0x7fff'ffff'ffff'ffff); } - -TEST_MAIN(Time) diff --git a/AK/Tests/TestTrie.cpp b/AK/Tests/TestTrie.cpp index 83279d8a2a..50b574cced 100644 --- a/AK/Tests/TestTrie.cpp +++ b/AK/Tests/TestTrie.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -66,5 +66,3 @@ TEST_CASE(iterate) ++i; } } - -TEST_MAIN(Trie) diff --git a/AK/Tests/TestTypeTraits.cpp b/AK/Tests/TestTypeTraits.cpp index 810efa99b7..ecea1bfc15 100644 --- a/AK/Tests/TestTypeTraits.cpp +++ b/AK/Tests/TestTypeTraits.cpp @@ -4,8 +4,9 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include -#include #include #define STATIC_EXPECT_EQ(lhs, rhs) \ @@ -104,5 +105,3 @@ TEST_CASE(UnderlyingType) STATIC_EXPECT_EQ(Type, u8); } - -TEST_MAIN(TypeTraits) diff --git a/AK/Tests/TestTypedTransfer.cpp b/AK/Tests/TestTypedTransfer.cpp index 72380f6a7e..5a0c347092 100644 --- a/AK/Tests/TestTypedTransfer.cpp +++ b/AK/Tests/TestTypedTransfer.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -39,5 +39,3 @@ TEST_CASE(overlapping_source_and_destination_2) for (size_t i = 0; i < 6; ++i) EXPECT_EQ(actual[i].m_value, expected[i].m_value); } - -TEST_MAIN(TypedTransfer) diff --git a/AK/Tests/TestURL.cpp b/AK/Tests/TestURL.cpp index 104dd7c214..c92ee4fc5b 100644 --- a/AK/Tests/TestURL.cpp +++ b/AK/Tests/TestURL.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -200,5 +200,3 @@ TEST_CASE(port_int_overflow_wrap) EXPECT_EQ(url.port(), expected_port); EXPECT_EQ(url.is_valid(), true); } - -TEST_MAIN(URL) diff --git a/AK/Tests/TestUtf8.cpp b/AK/Tests/TestUtf8.cpp index 1336fa3537..4a3f4e8029 100644 --- a/AK/Tests/TestUtf8.cpp +++ b/AK/Tests/TestUtf8.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include @@ -67,5 +67,3 @@ TEST_CASE(validate_invalid_ut8) EXPECT(!utf8_4.validate(valid_bytes)); EXPECT(valid_bytes == 0); } - -TEST_MAIN(UTF8) diff --git a/AK/Tests/TestVector.cpp b/AK/Tests/TestVector.cpp index b81c01ac75..0439a0605f 100644 --- a/AK/Tests/TestVector.cpp +++ b/AK/Tests/TestVector.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -399,5 +399,3 @@ TEST_CASE(should_find_index) EXPECT_EQ(4u, v.find_first_index(0).value()); EXPECT(!v.find_first_index(42).has_value()); } - -TEST_MAIN(Vector) diff --git a/AK/Tests/TestWeakPtr.cpp b/AK/Tests/TestWeakPtr.cpp index 63651204b1..8a573276cd 100644 --- a/AK/Tests/TestWeakPtr.cpp +++ b/AK/Tests/TestWeakPtr.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -64,5 +64,3 @@ TEST_CASE(weakptr_move) EXPECT_EQ(weak2.is_null(), true); } - -TEST_MAIN(WeakPtr) diff --git a/Meta/CMake/utils.cmake b/Meta/CMake/utils.cmake index e3aa4e136e..a57cee686c 100644 --- a/Meta/CMake/utils.cmake +++ b/Meta/CMake/utils.cmake @@ -29,7 +29,6 @@ endfunction() function(serenity_lib target_name fs_name) serenity_install_headers(${target_name}) serenity_install_sources("Userland/Libraries/${target_name}") - #add_library(${target_name} SHARED ${SOURCES} ${GENERATED_SOURCES}) add_library(${target_name} SHARED ${SOURCES} ${GENERATED_SOURCES}) install(TARGETS ${target_name} DESTINATION usr/lib) set_target_properties(${target_name} PROPERTIES OUTPUT_NAME ${fs_name}) @@ -74,6 +73,21 @@ function(serenity_bin target_name) serenity_generated_sources(${target_name}) endfunction() +function(serenity_test test_src sub_dir) + cmake_parse_arguments(SERENITY_TEST "CUSTOM_MAIN" "" "LIBS" ${ARGN}) + set(TEST_SOURCES ${test_src}) + if (NOT ${SERENITY_TEST_CUSTOM_MAIN}) + list(APPEND TEST_SOURCES "${CMAKE_SOURCE_DIR}/Userland/Libraries/LibTest/TestMain.cpp") + endif() + get_filename_component(test_name ${test_src} NAME_WE) + add_executable(${test_name} ${TEST_SOURCES}) + target_link_libraries(${test_name} LibTest LibCore) + foreach(lib ${SERENITY_TEST_LIBS}) + target_link_libraries(${test_name} ${lib}) + endforeach() + install(TARGETS ${test_name} RUNTIME DESTINATION usr/Tests/${sub_dir}) +endfunction() + function(serenity_app target_name) cmake_parse_arguments(SERENITY_APP "" "ICON" "" ${ARGN}) diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt index 556345d5ed..ccc4a58915 100644 --- a/Meta/Lagom/CMakeLists.txt +++ b/Meta/Lagom/CMakeLists.txt @@ -77,9 +77,14 @@ list(FILTER SHELL_SOURCES EXCLUDE REGEX ".*main.cpp$") file(GLOB LIBSQL_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibSQL/*.cpp") file(GLOB LIBSQL_TEST_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibSQL/Tests/*.cpp") +file(GLOB LIBTEST_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibTest/*.cpp") +list(FILTER LIBTEST_SOURCES EXCLUDE REGEX ".*Main.cpp$") +file(GLOB LIBTEST_MAIN CONFIGURE_DEPENDS "../../Userland/Libraries/LibTest/TestMain.cpp") + set(LAGOM_REGEX_SOURCES ${LIBREGEX_LIBC_SOURCES} ${LIBREGEX_SOURCES}) set(LAGOM_CORE_SOURCES ${AK_SOURCES} ${LIBCORE_SOURCES}) set(LAGOM_MORE_SOURCES ${LIBARCHIVE_SOURCES} ${LIBAUDIO_SOURCES} ${LIBELF_SOURCES} ${LIBIPC_SOURCES} ${LIBLINE_SOURCES} ${LIBJS_SOURCES} ${LIBJS_SUBDIR_SOURCES} ${LIBX86_SOURCES} ${LIBCRYPTO_SOURCES} ${LIBCOMPRESS_SOURCES} ${LIBCRYPTO_SUBDIR_SOURCES} ${LIBTLS_SOURCES} ${LIBTTF_SOURCES} ${LIBTEXTCODEC_SOURCES} ${LIBMARKDOWN_SOURCES} ${LIBGEMINI_SOURCES} ${LIBGFX_SOURCES} ${LIBGUI_GML_SOURCES} ${LIBHTTP_SOURCES} ${LAGOM_REGEX_SOURCES} ${SHELL_SOURCES} ${LIBSQL_SOURCES}) +set(LAGOM_TEST_SOURCES ${LIBTEST_SOURCES}) # FIXME: This is a hack, because the lagom stuff can be build individually or # in combination with the system, we generate two Debug.h files. One in @@ -98,6 +103,7 @@ if (BUILD_LAGOM) if (NOT ENABLE_OSS_FUZZ AND NOT ENABLE_FUZZER_SANITIZER) enable_testing() + add_library(LagomTest $ ${LAGOM_TEST_SOURCES}) add_executable(TestApp TestApp.cpp) target_link_libraries(TestApp Lagom) target_link_libraries(TestApp stdc++) @@ -178,8 +184,8 @@ if (BUILD_LAGOM) foreach(source ${AK_TEST_SOURCES}) get_filename_component(name ${source} NAME_WE) - add_executable(${name}_lagom ${source}) - target_link_libraries(${name}_lagom LagomCore) + add_executable(${name}_lagom ${source} ${LIBTEST_MAIN}) + target_link_libraries(${name}_lagom LagomTest) add_test( NAME ${name}_lagom COMMAND ${name}_lagom @@ -190,8 +196,8 @@ if (BUILD_LAGOM) foreach(source ${LIBREGEX_TESTS}) get_filename_component(name ${source} NAME_WE) - add_executable(${name}_lagom ${source} ${LAGOM_REGEX_SOURCES}) - target_link_libraries(${name}_lagom LagomCore) + add_executable(${name}_lagom ${source} ${LAGOM_REGEX_SOURCES} ${LIBTEST_MAIN}) + target_link_libraries(${name}_lagom LagomTest) add_test( NAME ${name}_lagom COMMAND ${name}_lagom @@ -201,8 +207,8 @@ if (BUILD_LAGOM) foreach(source ${LIBCOMPRESS_TESTS}) get_filename_component(name ${source} NAME_WE) - add_executable(${name}_lagom ${source} ${LIBCOMPRESS_SOURCES}) - target_link_libraries(${name}_lagom Lagom) + add_executable(${name}_lagom ${source} ${LIBCOMPRESS_SOURCES} ${LIBTEST_MAIN}) + target_link_libraries(${name}_lagom Lagom LagomTest) add_test( NAME ${name}_lagom COMMAND ${name}_lagom @@ -212,8 +218,8 @@ if (BUILD_LAGOM) foreach(source ${LIBSQL_TEST_SOURCES}) get_filename_component(name ${source} NAME_WE) - add_executable(${name}_lagom ${source} ${LIBSQL_SOURCES}) - target_link_libraries(${name}_lagom LagomCore) + add_executable(${name}_lagom ${source} ${LIBSQL_SOURCES} ${LIBTEST_MAIN}) + target_link_libraries(${name}_lagom LagomTest) add_test( NAME ${name}_lagom COMMAND ${name}_lagom diff --git a/Userland/Applications/Spreadsheet/CMakeLists.txt b/Userland/Applications/Spreadsheet/CMakeLists.txt index 15a9f6c020..73945a9a5f 100644 --- a/Userland/Applications/Spreadsheet/CMakeLists.txt +++ b/Userland/Applications/Spreadsheet/CMakeLists.txt @@ -37,3 +37,7 @@ set(GENERATED_SOURCES serenity_app(Spreadsheet ICON app-spreadsheet) target_link_libraries(Spreadsheet LibGUI LibJS LibWeb) + +# FIXME: build these tests +#serenity_test(Writers/Test/TestXSVWriter.cpp Spreadsheet) +#serenity_test(Readers/Test/TestXSV.cpp Spreadsheet) diff --git a/Userland/Applications/Spreadsheet/Readers/Test/TestXSV.cpp b/Userland/Applications/Spreadsheet/Readers/Test/TestXSV.cpp index 196a496c55..0155912fb2 100644 --- a/Userland/Applications/Spreadsheet/Readers/Test/TestXSV.cpp +++ b/Userland/Applications/Spreadsheet/Readers/Test/TestXSV.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include "../CSV.h" #include "../XSV.h" @@ -86,5 +86,3 @@ BENCHMARK_CASE(fairly_big_data) EXPECT(!csv.has_error()); EXPECT_EQ(csv.size(), 100000u); } - -TEST_MAIN(XSV) diff --git a/Userland/Applications/Spreadsheet/Writers/Test/TestXSVWriter.cpp b/Userland/Applications/Spreadsheet/Writers/Test/TestXSVWriter.cpp index 5dad1dcfdd..8f0348bf8d 100644 --- a/Userland/Applications/Spreadsheet/Writers/Test/TestXSVWriter.cpp +++ b/Userland/Applications/Spreadsheet/Writers/Test/TestXSVWriter.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include "../CSV.h" #include "../XSV.h" @@ -72,5 +72,3 @@ We"ll,"Hello,", Friends EXPECT_EQ(StringView { stream.bytes() }, expected_output); } - -TEST_MAIN(XSV) diff --git a/Userland/Libraries/LibC/Tests/CMakeLists.txt b/Userland/Libraries/LibC/Tests/CMakeLists.txt index 768d984227..5dff11b9a3 100644 --- a/Userland/Libraries/LibC/Tests/CMakeLists.txt +++ b/Userland/Libraries/LibC/Tests/CMakeLists.txt @@ -1,8 +1,5 @@ file(GLOB TEST_SOURCES CONFIGURE_DEPENDS "*.cpp") foreach(source ${TEST_SOURCES}) - get_filename_component(name ${source} NAME_WE) - add_executable(${name} ${source}) - target_link_libraries(${name} LibC LibCore) - install(TARGETS ${name} RUNTIME DESTINATION usr/Tests/LibC) + serenity_test(${source} LibC) endforeach() diff --git a/Userland/Libraries/LibC/Tests/TestLibCTime.cpp b/Userland/Libraries/LibC/Tests/TestLibCTime.cpp index 4e4c3dd303..fcf2327639 100644 --- a/Userland/Libraries/LibC/Tests/TestLibCTime.cpp +++ b/Userland/Libraries/LibC/Tests/TestLibCTime.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include const auto expected_epoch = "Thu Jan 1 00:00:00 1970\n"sv; @@ -41,5 +41,3 @@ TEST_CASE(ctime_r) EXPECT_EQ(expected_epoch, StringView(result)); } - -TEST_MAIN(LibCTime) diff --git a/Userland/Libraries/LibCompress/Tests/CMakeLists.txt b/Userland/Libraries/LibCompress/Tests/CMakeLists.txt index 8b15789971..bfd8880d1d 100644 --- a/Userland/Libraries/LibCompress/Tests/CMakeLists.txt +++ b/Userland/Libraries/LibCompress/Tests/CMakeLists.txt @@ -1,8 +1,5 @@ file(GLOB TEST_SOURCES CONFIGURE_DEPENDS "*.cpp") foreach(source ${TEST_SOURCES}) - get_filename_component(name ${source} NAME_WE) - add_executable(${name} ${source}) - target_link_libraries(${name} LibCore LibCompress) - install(TARGETS ${name} RUNTIME DESTINATION usr/Tests/LibCompress) + serenity_test(${source} LibCompress LIBS LibCompress) endforeach() diff --git a/Userland/Libraries/LibCompress/Tests/TestDeflate.cpp b/Userland/Libraries/LibCompress/Tests/TestDeflate.cpp index af88c9f180..7b992d8fee 100644 --- a/Userland/Libraries/LibCompress/Tests/TestDeflate.cpp +++ b/Userland/Libraries/LibCompress/Tests/TestDeflate.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -155,5 +155,3 @@ TEST_CASE(deflate_compress_literals) auto compressed = Compress::DeflateCompressor::compress_all(test, Compress::DeflateCompressor::CompressionLevel::GOOD); EXPECT(compressed.has_value()); } - -TEST_MAIN(Deflate) diff --git a/Userland/Libraries/LibCompress/Tests/TestGzip.cpp b/Userland/Libraries/LibCompress/Tests/TestGzip.cpp index 8d04b238a5..189d5b52c9 100644 --- a/Userland/Libraries/LibCompress/Tests/TestGzip.cpp +++ b/Userland/Libraries/LibCompress/Tests/TestGzip.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -95,5 +95,3 @@ TEST_CASE(gzip_round_trip) EXPECT(uncompressed.has_value()); EXPECT(uncompressed.value() == original); } - -TEST_MAIN(Gzip) diff --git a/Userland/Libraries/LibCompress/Tests/TestZlib.cpp b/Userland/Libraries/LibCompress/Tests/TestZlib.cpp index 1d6b0a0408..8ab5b81a95 100644 --- a/Userland/Libraries/LibCompress/Tests/TestZlib.cpp +++ b/Userland/Libraries/LibCompress/Tests/TestZlib.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -23,5 +23,3 @@ TEST_CASE(zlib_decompress_simple) const auto decompressed = Compress::Zlib::decompress_all(compressed); EXPECT(decompressed.value().bytes() == (ReadonlyBytes { uncompressed, sizeof(uncompressed) - 1 })); } - -TEST_MAIN(Zlib) diff --git a/Userland/Libraries/LibRegex/Tests/Benchmark.cpp b/Userland/Libraries/LibRegex/Tests/Benchmark.cpp index 8e13cce111..b51316fdb5 100644 --- a/Userland/Libraries/LibRegex/Tests/Benchmark.cpp +++ b/Userland/Libraries/LibRegex/Tests/Benchmark.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include // import first, to prevent warning of VERIFY* redefinition +#include // import first, to prevent warning of VERIFY* redefinition #include #include @@ -967,5 +967,3 @@ BENCHMARK_CASE(simple_notbol_noteol_benchmark_reference_stdcpp) # endif #endif - -TEST_MAIN(Regex) diff --git a/Userland/Libraries/LibRegex/Tests/CMakeLists.txt b/Userland/Libraries/LibRegex/Tests/CMakeLists.txt index 66478f6ad6..a9ccade427 100644 --- a/Userland/Libraries/LibRegex/Tests/CMakeLists.txt +++ b/Userland/Libraries/LibRegex/Tests/CMakeLists.txt @@ -2,8 +2,5 @@ file(GLOB TEST_SOURCES CONFIGURE_DEPENDS "*.cpp") file(GLOB REGEX_SOURCES CONFIGURE_DEPENDS "../*.cpp" "../C/*.cpp") foreach(source ${TEST_SOURCES}) - get_filename_component(name ${source} NAME_WE) - add_executable(${name} ${source} ${REGEX_SOURCES}) - target_link_libraries(${name} LibCore) - install(TARGETS ${name} RUNTIME DESTINATION usr/Tests/LibRegex) + serenity_test(${source} LibRegex LIBS LibRegex) endforeach() diff --git a/Userland/Libraries/LibRegex/Tests/Regex.cpp b/Userland/Libraries/LibRegex/Tests/Regex.cpp index 5aeb4ccbf8..054c54485b 100644 --- a/Userland/Libraries/LibRegex/Tests/Regex.cpp +++ b/Userland/Libraries/LibRegex/Tests/Regex.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include // import first, to prevent warning of VERIFY* redefinition +#include // import first, to prevent warning of VERIFY* redefinition #include #include @@ -595,5 +595,3 @@ TEST_CASE(replace) EXPECT_EQ(re.replace(test.subject, test.replacement), test.expected); } } - -TEST_MAIN(Regex) diff --git a/Userland/Libraries/LibRegex/Tests/RegexLibC.cpp b/Userland/Libraries/LibRegex/Tests/RegexLibC.cpp index 7e001f4b65..bea5e5984c 100644 --- a/Userland/Libraries/LibRegex/Tests/RegexLibC.cpp +++ b/Userland/Libraries/LibRegex/Tests/RegexLibC.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -1116,5 +1116,3 @@ TEST_CASE(simple_notbol_noteol) regfree(®ex); } - -TEST_MAIN(Regex) diff --git a/Userland/Libraries/LibSQL/Tests/CMakeLists.txt b/Userland/Libraries/LibSQL/Tests/CMakeLists.txt index b028333c61..f002a1e864 100644 --- a/Userland/Libraries/LibSQL/Tests/CMakeLists.txt +++ b/Userland/Libraries/LibSQL/Tests/CMakeLists.txt @@ -1,8 +1,5 @@ file(GLOB TEST_SOURCES CONFIGURE_DEPENDS "*.cpp") foreach(source ${TEST_SOURCES}) - get_filename_component(name ${source} NAME_WE) - add_executable(${name} ${source}) - target_link_libraries(${name} LibSQL) - install(TARGETS ${name} RUNTIME DESTINATION usr/Tests/LibSQL) + serenity_test(${source} LibSQL LIBS LibSQL) endforeach() diff --git a/Userland/Libraries/LibSQL/Tests/TestSqlExpressionParser.cpp b/Userland/Libraries/LibSQL/Tests/TestSqlExpressionParser.cpp index a3d2e6d32f..c2a6b3bfd7 100644 --- a/Userland/Libraries/LibSQL/Tests/TestSqlExpressionParser.cpp +++ b/Userland/Libraries/LibSQL/Tests/TestSqlExpressionParser.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -602,5 +602,3 @@ TEST_CASE(in_selection_expression) validate("15 IN (SELECT * FROM table)", false); validate("15 NOT IN (SELECT * FROM table)", true); } - -TEST_MAIN(SqlExpressionParser) diff --git a/Userland/Libraries/LibSQL/Tests/TestSqlStatementParser.cpp b/Userland/Libraries/LibSQL/Tests/TestSqlStatementParser.cpp index 7438311bdc..0126a85e4e 100644 --- a/Userland/Libraries/LibSQL/Tests/TestSqlStatementParser.cpp +++ b/Userland/Libraries/LibSQL/Tests/TestSqlStatementParser.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -735,5 +735,3 @@ TEST_CASE(common_table_expression) validate("WITH table (column1, column2) AS (SELECT * FROM table) DELETE FROM table;", { false, { { "table", { "column1", "column2" } } } }); validate("WITH RECURSIVE table AS (SELECT * FROM table) DELETE FROM table;", { true, { { "table", {} } } }); } - -TEST_MAIN(SqlStatementParser) diff --git a/Userland/Libraries/LibTest/CMakeLists.txt b/Userland/Libraries/LibTest/CMakeLists.txt index a924ea3e3f..7816fdac71 100644 --- a/Userland/Libraries/LibTest/CMakeLists.txt +++ b/Userland/Libraries/LibTest/CMakeLists.txt @@ -1 +1,8 @@ serenity_install_sources("Userland/Libraries/LibTest") + +set(SOURCES + TestSuite.cpp +) + +serenity_lib(LibTest test) +target_link_libraries(LibTest LibC) diff --git a/Userland/Libraries/LibTest/Macros.h b/Userland/Libraries/LibTest/Macros.h new file mode 100644 index 0000000000..b4704508e2 --- /dev/null +++ b/Userland/Libraries/LibTest/Macros.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace AK { +template +void warnln(CheckedFormatString&& fmtstr, const Parameters&...); +} + +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(stderr, "\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) + +// 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(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(a, b) \ + 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 (fabs(expect_close_diff) > 0.0000005) { \ + ::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) diff --git a/Userland/Libraries/LibTest/TestCase.h b/Userland/Libraries/LibTest/TestCase.h new file mode 100644 index 0000000000..d0fb713567 --- /dev/null +++ b/Userland/Libraries/LibTest/TestCase.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include // intentionally first -- we redefine VERIFY and friends in here + +#include +#include +#include +#include + +namespace Test { + +using TestFunction = Function; + +class TestCase : public RefCounted { +public: + TestCase(const String& name, TestFunction&& fn, bool is_benchmark) + : m_name(name) + , m_function(move(fn)) + , m_is_benchmark(is_benchmark) + { + } + + bool is_benchmark() const { return m_is_benchmark; } + const String& name() const { return m_name; } + const TestFunction& func() const { return m_function; } + +private: + String m_name; + TestFunction m_function; + bool m_is_benchmark; +}; + +// Helper to hide implementation of TestSuite from users +void add_test_case_to_suite(const NonnullRefPtr& test_case); + +} + +#define __TESTCASE_FUNC(x) __test_##x +#define __TESTCASE_TYPE(x) __TestCase_##x + +#define TEST_CASE(x) \ + static void __TESTCASE_FUNC(x)(); \ + struct __TESTCASE_TYPE(x) { \ + __TESTCASE_TYPE(x) \ + () { add_test_case_to_suite(adopt_ref(*new ::Test::TestCase(#x, __TESTCASE_FUNC(x), false))); } \ + }; \ + static struct __TESTCASE_TYPE(x) __TESTCASE_TYPE(x); \ + static void __TESTCASE_FUNC(x)() + +#define __BENCHMARK_FUNC(x) __benchmark_##x +#define __BENCHMARK_TYPE(x) __BenchmarkCase_##x + +#define BENCHMARK_CASE(x) \ + static void __BENCHMARK_FUNC(x)(); \ + struct __BENCHMARK_TYPE(x) { \ + __BENCHMARK_TYPE(x) \ + () { add_test_case_to_suite(adopt_ref(*new ::Test::TestCase(#x, __BENCHMARK_FUNC(x), true))); } \ + }; \ + static struct __BENCHMARK_TYPE(x) __BENCHMARK_TYPE(x); \ + static void __BENCHMARK_FUNC(x)() diff --git a/Userland/Libraries/LibTest/TestMain.cpp b/Userland/Libraries/LibTest/TestMain.cpp new file mode 100644 index 0000000000..6a232e1618 --- /dev/null +++ b/Userland/Libraries/LibTest/TestMain.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include +#include + +#ifdef KERNEL +# define TEST_MAIN test_main +#else +# define TEST_MAIN main +#endif + +int TEST_MAIN(int argc, char** argv) +{ + if (argc < 1 || !argv[0] || '\0' == *argv[0]) { + warnln("Test main does not have a valid test name!"); + return 1; + } + int ret = ::Test::TestSuite::the().main(argv[0], argc, argv); + ::Test::TestSuite::release(); + return ret; +} diff --git a/Userland/Libraries/LibTest/TestSuite.cpp b/Userland/Libraries/LibTest/TestSuite.cpp new file mode 100644 index 0000000000..ac2b93b7de --- /dev/null +++ b/Userland/Libraries/LibTest/TestSuite.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include // intentionally first -- we redefine VERIFY and friends in here + +#include +#include +#include +#include + +namespace Test { + +TestSuite* TestSuite::s_global = nullptr; + +class TestElapsedTimer { +public: + TestElapsedTimer() { restart(); } + + void restart() { gettimeofday(&m_started, nullptr); } + + u64 elapsed_milliseconds() + { + struct timeval now = {}; + gettimeofday(&now, nullptr); + + struct timeval delta = {}; + timersub(&now, &m_started, &delta); + + return delta.tv_sec * 1000 + delta.tv_usec / 1000; + } + +private: + struct timeval m_started = {}; +}; + +// Declared in Macros.h +void current_test_case_did_fail() +{ + TestSuite::the().current_test_case_did_fail(); +} + +// Declared in TestCase.h +void add_test_case_to_suite(const NonnullRefPtr& test_case) +{ + TestSuite::the().add_case(test_case); +} + +int TestSuite::main(const String& suite_name, int argc, char** argv) +{ + m_suite_name = suite_name; + + Core::ArgsParser args_parser; + + bool do_tests_only = getenv("TESTS_ONLY") != nullptr; + bool do_benchmarks_only = false; + bool do_list_cases = false; + const char* search_string = "*"; + + args_parser.add_option(do_tests_only, "Only run tests.", "tests", 0); + args_parser.add_option(do_benchmarks_only, "Only run benchmarks.", "bench", 0); + args_parser.add_option(do_list_cases, "List available test cases.", "list", 0); + args_parser.add_positional_argument(search_string, "Only run matching cases.", "pattern", Core::ArgsParser::Required::No); + args_parser.parse(argc, argv); + + const auto& matching_tests = find_cases(search_string, !do_benchmarks_only, !do_tests_only); + + if (do_list_cases) { + outln("Available cases for {}:", suite_name); + for (const auto& test : matching_tests) { + outln(" {}", test.name()); + } + return 0; + } + + outln("Running {} cases out of {}.", matching_tests.size(), m_cases.size()); + + return run(matching_tests); +} + +NonnullRefPtrVector TestSuite::find_cases(const String& search, bool find_tests, bool find_benchmarks) +{ + NonnullRefPtrVector matches; + for (const auto& t : m_cases) { + if (!search.is_empty() && !t.name().matches(search, CaseSensitivity::CaseInsensitive)) { + continue; + } + + if (!find_tests && !t.is_benchmark()) { + continue; + } + if (!find_benchmarks && t.is_benchmark()) { + continue; + } + + matches.append(t); + } + return matches; +} + +int TestSuite::run(const NonnullRefPtrVector& tests) +{ + size_t test_count = 0; + size_t test_failed_count = 0; + size_t benchmark_count = 0; + TestElapsedTimer global_timer; + + for (const auto& t : tests) { + const auto test_type = t.is_benchmark() ? "benchmark" : "test"; + + warnln("Running {} '{}'.", test_type, t.name()); + m_current_test_case_passed = true; + + TestElapsedTimer timer; + t.func()(); + const auto time = timer.elapsed_milliseconds(); + + dbgln("{} {} '{}' in {}ms", m_current_test_case_passed ? "Completed" : "Failed", test_type, t.name(), time); + + if (t.is_benchmark()) { + m_benchtime += time; + benchmark_count++; + } else { + m_testtime += time; + test_count++; + } + + if (!m_current_test_case_passed) { + test_failed_count++; + } + } + + dbgln("Finished {} tests and {} benchmarks in {}ms ({}ms tests, {}ms benchmarks, {}ms other).", + test_count, + benchmark_count, + global_timer.elapsed_milliseconds(), + m_testtime, + m_benchtime, + global_timer.elapsed_milliseconds() - (m_testtime + m_benchtime)); + dbgln("Out of {} tests, {} passed and {} failed.", test_count, test_count - test_failed_count, test_failed_count); + + return (int)test_failed_count; +} + +} diff --git a/Userland/Libraries/LibTest/TestSuite.h b/Userland/Libraries/LibTest/TestSuite.h new file mode 100644 index 0000000000..694b6d1a69 --- /dev/null +++ b/Userland/Libraries/LibTest/TestSuite.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include // intentionally first -- we redefine VERIFY and friends in here + +#include +#include +#include +#include +#include + +namespace Test { + +class TestSuite { +public: + static TestSuite& the() + { + if (s_global == nullptr) + s_global = new TestSuite(); + return *s_global; + } + + static void release() + { + if (s_global) + delete s_global; + s_global = nullptr; + } + + int run(const NonnullRefPtrVector&); + int main(const String& suite_name, int argc, char** argv); + NonnullRefPtrVector find_cases(const String& search, bool find_tests, bool find_benchmarks); + void add_case(const NonnullRefPtr& test_case) + { + m_cases.append(test_case); + } + + void current_test_case_did_fail() { m_current_test_case_passed = false; } + +private: + static TestSuite* s_global; + NonnullRefPtrVector m_cases; + u64 m_testtime = 0; + u64 m_benchtime = 0; + String m_suite_name; + bool m_current_test_case_passed = true; +}; + +} diff --git a/Userland/Tests/Kernel/CMakeLists.txt b/Userland/Tests/Kernel/CMakeLists.txt index cd9438dc4a..408d82163c 100644 --- a/Userland/Tests/Kernel/CMakeLists.txt +++ b/Userland/Tests/Kernel/CMakeLists.txt @@ -1,5 +1,6 @@ file(GLOB CMD_SOURCES CONFIGURE_DEPENDS "*.cpp") +# FIXME: These tests do not use LibTest foreach(CMD_SRC ${CMD_SOURCES}) get_filename_component(CMD_NAME ${CMD_SRC} NAME_WE) add_executable(${CMD_NAME} ${CMD_SRC}) diff --git a/Userland/Tests/LibC/CMakeLists.txt b/Userland/Tests/LibC/CMakeLists.txt index 799dfa9ff4..a42c42b47e 100644 --- a/Userland/Tests/LibC/CMakeLists.txt +++ b/Userland/Tests/LibC/CMakeLists.txt @@ -1,5 +1,8 @@ file(GLOB CMD_SOURCES CONFIGURE_DEPENDS "*.cpp") +list(REMOVE_ITEM CMD_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/snprintf-correctness.cpp) +list(REMOVE_ITEM CMD_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/strlcpy-correctness.cpp) +# FIXME: These tests do not use LibTest foreach(CMD_SRC ${CMD_SOURCES}) get_filename_component(CMD_NAME ${CMD_SRC} NAME_WE) add_executable(${CMD_NAME} ${CMD_SRC}) @@ -7,4 +10,5 @@ foreach(CMD_SRC ${CMD_SOURCES}) install(TARGETS ${CMD_NAME} RUNTIME DESTINATION usr/Tests/LibC) endforeach() -#target_link_libraries(foobar LibPthread) +serenity_test(snprintf-correctness.cpp LibC) +serenity_test(strlcpy-correctness.cpp LibC) diff --git a/Userland/Tests/LibC/snprintf-correctness.cpp b/Userland/Tests/LibC/snprintf-correctness.cpp index 5b8200db4f..0df2a5cc30 100644 --- a/Userland/Tests/LibC/snprintf-correctness.cpp +++ b/Userland/Tests/LibC/snprintf-correctness.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -141,5 +141,3 @@ TEST_CASE(special_cases) EXPECT(test_single({ LITERAL("x"), "whf", POISON, 3, LITERAL("\0") })); EXPECT(test_single({ LITERAL("xx"), "whf", POISON, 3, LITERAL("w\0") })); } - -TEST_MAIN(Sprintf) diff --git a/Userland/Tests/LibC/strlcpy-correctness.cpp b/Userland/Tests/LibC/strlcpy-correctness.cpp index c7e4cb0401..e23765cd29 100644 --- a/Userland/Tests/LibC/strlcpy-correctness.cpp +++ b/Userland/Tests/LibC/strlcpy-correctness.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -162,5 +162,3 @@ TEST_CASE(to_nullptr) EXPECT(test_single({ LITERAL("Hello World!\0\0\0"), LITERAL("Hello Friend!"), LITERAL("Hello Friend!\0\0") })); EXPECT(test_single({ LITERAL("aaaaaaaaaa"), LITERAL("whf"), LITERAL("whf\0aaaaaa") })); } - -TEST_MAIN(Sprintf) diff --git a/Userland/Tests/LibGfx/CMakeLists.txt b/Userland/Tests/LibGfx/CMakeLists.txt index 1c2bc2f17e..f0f5cecab9 100644 --- a/Userland/Tests/LibGfx/CMakeLists.txt +++ b/Userland/Tests/LibGfx/CMakeLists.txt @@ -1,12 +1,12 @@ file(GLOB CMD_SOURCES CONFIGURE_DEPENDS "*.cpp") +list(REMOVE_ITEM CMD_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/painter.cpp) +# FIXME These tests do not use LibTest foreach(CMD_SRC ${CMD_SOURCES}) get_filename_component(CMD_NAME ${CMD_SRC} NAME_WE) add_executable(${CMD_NAME} ${CMD_SRC}) - target_link_libraries(${CMD_NAME} LibCore) + target_link_libraries(${CMD_NAME} LibCore LibGUI) install(TARGETS ${CMD_NAME} RUNTIME DESTINATION usr/Tests/LibGfx) endforeach() -target_link_libraries(font LibGUI LibCore) -target_link_libraries(image-decoder LibGUI LibCore) -target_link_libraries(painter LibGUI LibCore) +serenity_test(painter.cpp LibGfx LIBS LibGUI) diff --git a/Userland/Tests/LibGfx/painter.cpp b/Userland/Tests/LibGfx/painter.cpp index 50210f51a7..ca4fef41cf 100644 --- a/Userland/Tests/LibGfx/painter.cpp +++ b/Userland/Tests/LibGfx/painter.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -51,5 +51,3 @@ BENCHMARK_CASE(fill_with_gradient) painter.fill_rect_with_gradient(bitmap->rect(), Color::Blue, Color::Red); } } - -TEST_MAIN(Painter) diff --git a/Userland/Tests/LibM/CMakeLists.txt b/Userland/Tests/LibM/CMakeLists.txt index de7c217201..bf1c0cc927 100644 --- a/Userland/Tests/LibM/CMakeLists.txt +++ b/Userland/Tests/LibM/CMakeLists.txt @@ -1,8 +1,5 @@ file(GLOB CMD_SOURCES CONFIGURE_DEPENDS "*.cpp") foreach(CMD_SRC ${CMD_SOURCES}) - get_filename_component(CMD_NAME ${CMD_SRC} NAME_WE) - add_executable(${CMD_NAME} ${CMD_SRC}) - target_link_libraries(${CMD_NAME} LibCore) - install(TARGETS ${CMD_NAME} RUNTIME DESTINATION usr/Tests/LibM) + serenity_test(${CMD_SRC} LibM) endforeach() diff --git a/Userland/Tests/LibM/test-math.cpp b/Userland/Tests/LibM/test-math.cpp index cdc5f35173..e48a5955e2 100644 --- a/Userland/Tests/LibM/test-math.cpp +++ b/Userland/Tests/LibM/test-math.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include @@ -250,5 +250,3 @@ TEST_CASE(fmax_and_fmin) EXPECT(fmin(0, NAN) == 0); EXPECT(isnan(fmin(NAN, NAN))); } - -TEST_MAIN(Math) diff --git a/Userland/Tests/UserspaceEmulator/CMakeLists.txt b/Userland/Tests/UserspaceEmulator/CMakeLists.txt index f39e141ee6..3fbbbc4120 100644 --- a/Userland/Tests/UserspaceEmulator/CMakeLists.txt +++ b/Userland/Tests/UserspaceEmulator/CMakeLists.txt @@ -1,5 +1,6 @@ file(GLOB CMD_SOURCES CONFIGURE_DEPENDS "*.cpp") +# FIXME: These tests do not use LibTest foreach(CMD_SRC ${CMD_SOURCES}) get_filename_component(CMD_NAME ${CMD_SRC} NAME_WE) add_executable(${CMD_NAME} ${CMD_SRC})