AK+Userland: Move AK/TestSuite.h into LibTest and rework Tests' CMake

As many macros as possible are moved to Macros.h, while the
macros to create a test case are moved to TestCase.h. TestCase is now
the only user-facing header for creating a test case. TestSuite and its
helpers have moved into a .cpp file. Instead of requiring a TEST_MAIN
macro to be instantiated into the test file, a TestMain.cpp file is
provided instead that will be linked against each test. This has the
side effect that, if we wanted to have test cases split across multiple
files, it's as simple as adding them all to the same executable.

The test main should be portable to kernel mode as well, so if
there's a set of tests that should be run in self-test mode in kernel
space, we can accomodate that.

A new serenity_test CMake function streamlines adding a new test with
arguments for the test source file, subdirectory under /usr/Tests to
install the test application and an optional list of libraries to link
against the test application. To accomodate future test where the
provided TestMain.cpp is not suitable (e.g. test-js), a CUSTOM_MAIN
parameter can be passed to the function to not link against the
boilerplate main function.
This commit is contained in:
Andrew Kaster 2021-04-24 23:53:23 -06:00 committed by Andreas Kling
parent 89ee38fe5c
commit 35c0a6c54d
Notes: sideshowbarker 2024-07-18 19:08:02 +09:00
94 changed files with 522 additions and 579 deletions

View file

@ -1,319 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Assertions.h>
#include <AK/CheckedFormatString.h>
namespace AK {
template<typename... Parameters>
void warnln(CheckedFormatString<Parameters...>&& 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 <AK/Format.h>
#include <AK/Function.h>
#include <AK/NonnullRefPtrVector.h>
#include <AK/String.h>
#include <LibCore/ArgsParser.h>
#include <stdlib.h>
#include <sys/time.h>
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<void()>;
class TestCase : public RefCounted<TestCase> {
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<TestCase>&);
int main(const String& suite_name, int argc, char** argv);
NonnullRefPtrVector<TestCase> find_cases(const String& search, bool find_tests, bool find_benchmarks);
void add_case(const NonnullRefPtr<TestCase>& 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<TestCase> 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<TestCase> TestSuite::find_cases(const String& search, bool find_tests, bool find_benchmarks)
{
NonnullRefPtrVector<TestCase> 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<TestCase>& 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<size_t N> \
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<double>(expect_close_lhs) - static_cast<double>(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)

View file

@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/AllOf.h>
#include <AK/Array.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/AnyOf.h>
#include <AK/Array.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Array.h>
@ -28,5 +28,3 @@ TEST_CASE(compile_time_iterable)
constexpr Array<int, 8> array = { 0, 1, 2, 3, 4, 5, 6, 7 };
static_assert(constexpr_sum(array) == 28);
}
TEST_MAIN(Array)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Atomic.h>
@ -340,5 +340,3 @@ TEST_CASE(fetch_xor)
a_u8 = 0xe2;
EXPECT((a_u8 ^= 0xef) == 0x0d);
}
TEST_MAIN(Atomic)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Badge.h>
@ -12,5 +12,3 @@ TEST_CASE(should_provide_underlying_type)
{
static_assert(IsSame<int, Badge<int>::Type>);
}
TEST_MAIN(Badge)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Base64.h>
#include <AK/ByteBuffer.h>
@ -44,5 +44,3 @@ TEST_CASE(test_encode)
encode_equal("fooba", "Zm9vYmE=");
encode_equal("foobar", "Zm9vYmFy");
}
TEST_MAIN(Base64)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/BinaryHeap.h>
#include <AK/String.h>
@ -65,5 +65,3 @@ TEST_CASE(large_populate_reverse)
EXPECT_EQ(ints.pop_min(), i);
}
}
TEST_MAIN(BinaryHeap)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/BinarySearch.h>
#include <AK/Span.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/BitCast.h>
@ -21,5 +21,3 @@ TEST_CASE(double_int_conversion)
check_cast_both_ways(static_cast<u64>(1) << 63, -0.0);
check_cast_both_ways(static_cast<u64>(0x4172f58bc0000000), 19880124.0);
}
TEST_MAIN(BitCast)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Bitmap.h>
@ -248,5 +248,3 @@ TEST_CASE(count_in_range)
test_with_value(true);
test_with_value(false);
}
TEST_MAIN(Bitmap)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/ByteBuffer.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Checked.h>
#include <AK/NumericLimits.h>
@ -386,5 +386,3 @@ TEST_CASE(should_constexpr_make_via_factory)
{
[[maybe_unused]] constexpr auto value = make_checked(42);
}
TEST_MAIN(Checked)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/CircularDeque.h>
#include <AK/StdLibExtras.h>
@ -61,5 +61,3 @@ TEST_CASE(deque_end)
EXPECT_EQ(ints.dequeue_end(), 0);
EXPECT(ints.is_empty());
}
TEST_MAIN(CircularDeque)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/CircularDuplexStream.h>
@ -61,5 +61,3 @@ TEST_CASE(overwritting_is_well_defined)
EXPECT(stream.eof());
}
TEST_MAIN(CircularDuplexStream)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/CircularQueue.h>
#include <AK/String.h>
@ -66,5 +66,3 @@ TEST_CASE(should_not_call_value_type_constructor_when_created)
CircularQueue<ConstructorCounter, 10> queue;
EXPECT_EQ(0u, ConstructorCounter::s_num_constructor_calls);
}
TEST_MAIN(CircularQueue)

View file

@ -4,8 +4,9 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/Complex.h>
#include <AK/TestSuite.h>
TEST_CASE(Complex)
{
@ -41,5 +42,3 @@ TEST_CASE(Complex)
EXPECT_APPROXIMATE(cexp(Complex<double>(0., 1.) * M_PI).real(), -1.);
#endif
}
TEST_MAIN(Complex)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/DistinctNumeric.h>
@ -283,5 +283,3 @@ TEST_CASE(negative_incompatible)
// | DistinctNumeric<[...],true,true,true,true,true,[...],[...],64>
}
#endif /* COMPILE_NEGATIVE_TESTS */
TEST_MAIN(DistinctNumeric)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/DoublyLinkedList.h>
@ -41,5 +41,3 @@ TEST_CASE(should_find_const)
EXPECT_EQ(sut.end(), sut.find(42));
}
TEST_MAIN(DoublyLinkedList)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Endian.h>
@ -15,5 +15,3 @@ static_assert(BigEndian<u32> { 42 } == 42, "Big endian values should be value co
static_assert(LittleEndian<u32> {} == 0, "Little endian values should be default constructed in a constexpr context.");
static_assert(LittleEndian<u32> { 42 } == 42, "Little endian values should be value constructed in a constexpr context.");
TEST_MAIN(Endian);

View file

@ -4,8 +4,9 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/EnumBits.h>
#include <AK/TestSuite.h>
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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Array.h>
#include <AK/Find.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/String.h>
#include <AK/StringBuilder.h>
@ -290,5 +290,3 @@ TEST_CASE(long_long_regression)
EXPECT_EQ(builder.string_view(), "81985529216486895");
}
TEST_MAIN(Format)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/GenericLexer.h>
#include <AK/StringView.h>
@ -156,5 +156,3 @@ TEST_CASE(should_constexpr_ignore_until_pred)
}();
static_assert(sut.peek() == 'c');
}
TEST_MAIN(GenericLexer)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/HashFunctions.h>
#include <AK/Types.h>
@ -59,5 +59,3 @@ TEST_CASE(constexpr_ptr_hash)
// "ptr_hash" test binds the result.
static_assert(ptr_hash(FlatPtr(42)));
}
TEST_MAIN(HashFunctions)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/HashMap.h>
#include <AK/String.h>
@ -172,5 +172,3 @@ TEST_CASE(basic_contains)
EXPECT_EQ(map.remove(1), true);
EXPECT_EQ(map.contains(1), false);
}
TEST_MAIN(HashMap)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/HashTable.h>
#include <AK/String.h>
@ -173,5 +173,3 @@ TEST_CASE(basic_contains)
EXPECT_EQ(table.remove(1), true);
EXPECT_EQ(table.contains(1), false);
}
TEST_MAIN(HashTable)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Hex.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Endian.h>
#include <AK/IPv4Address.h>
@ -151,5 +151,3 @@ TEST_CASE(should_compare)
EXPECT(addr_a != addr_b);
EXPECT(addr_a == addr_a);
}
TEST_MAIN(IPv4Address)

View file

@ -4,8 +4,9 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/StdLibExtras.h>
#include <AK/TestSuite.h>
#include <AK/TypeList.h>
template<typename F, typename... Args>
@ -46,5 +47,3 @@ TEST_CASE(TypeList)
static_assert(IsSame<MyTypes::Type<1>, bool>, "");
static_assert(IsSame<MyTypes::Type<2>, char>, "");
}
TEST_MAIN(IndexSequence);

View file

@ -4,10 +4,11 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/IntrusiveList.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/RefPtr.h>
#include <AK/TestSuite.h>
class IntrusiveTestItem {
public:
@ -120,5 +121,3 @@ TEST_CASE(intrusive_nonnull_ref_ptr_intrusive)
EXPECT(nonnull_ref_list.is_empty());
}
TEST_MAIN(IntrusiveList)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/IntrusiveRedBlackTree.h>
#include <AK/NonnullOwnPtrVector.h>
@ -114,5 +114,3 @@ TEST_CASE(clear)
test.clear();
EXPECT_EQ(test.size(), 0u);
}
TEST_MAIN(RedBlackTree)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/HashMap.h>
#include <AK/JsonArray.h>
@ -121,5 +121,3 @@ TEST_CASE(json_duplicate_keys)
json.set("test", "baz");
EXPECT_EQ(json.to_string(), "{\"test\":\"baz\"}");
}
TEST_MAIN(JSON)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/LexicalPath.h>
#include <AK/String.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/MACAddress.h>
#include <AK/Types.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/MemMem.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Array.h>
#include <AK/MemoryStream.h>
@ -220,5 +220,3 @@ TEST_CASE(offset_calculation_error_regression)
EXPECT_EQ(input, output);
}
TEST_MAIN(MemoryStream)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/NeverDestroyed.h>
#include <AK/StdLibExtras.h>
@ -71,5 +71,3 @@ TEST_CASE(should_provide_basic_getter)
AK::NeverDestroyed<Counter> n {};
EXPECT_EQ(0, n.get().num_destroys);
}
TEST_MAIN(NeverDestroyed)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/NonnullRefPtr.h>
#include <AK/String.h>
@ -59,5 +59,3 @@ TEST_CASE(swap_with_self)
swap(object, object);
EXPECT_EQ(object->ref_count(), 1u);
}
TEST_MAIN(NonnullRefPtr)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/NumberFormat.h>
@ -125,5 +125,3 @@ TEST_CASE(extremes_8byte)
warnln("(Skipping 8-byte-size_t test on 32-bit platform)");
}
}
TEST_MAIN(NumberFormat)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Optional.h>
#include <AK/String.h>
@ -53,5 +53,3 @@ TEST_CASE(short_notation)
EXPECT_EQ(value->length(), 3u);
EXPECT_EQ(*value, "foo");
}
TEST_MAIN(Optional)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Queue.h>
#include <AK/String.h>
@ -57,5 +57,3 @@ TEST_CASE(order)
EXPECT(strings.is_empty());
}
TEST_MAIN(Queue)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Checked.h>
#include <AK/Noncopyable.h>
@ -98,5 +98,3 @@ TEST_CASE(maximum_stack_depth)
delete[] data;
}
TEST_MAIN(QuickSort)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Random.h>
#include <AK/RedBlackTree.h>
@ -86,5 +86,3 @@ TEST_CASE(clear)
test.clear();
EXPECT_EQ(test.size(), 0u);
}
TEST_MAIN(RedBlackTree)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/NonnullRefPtr.h>
#include <AK/String.h>
@ -147,5 +147,3 @@ TEST_CASE(self_observers)
object->unref();
EXPECT_EQ(SelfAwareObject::num_destroyed, 1u);
}
TEST_MAIN(RefPtr)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/SinglyLinkedList.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/SourceGenerator.h>
@ -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)

View file

@ -5,9 +5,10 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/SourceLocation.h>
#include <AK/StringView.h>
#include <AK/TestSuite.h>
TEST_CASE(basic_scenario)
{
@ -29,5 +30,3 @@ TEST_CASE(default_arg_scenario)
EXPECT_EQ(expected_calling_function, actual_calling_function);
}
TEST_MAIN(SourceLocation)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Checked.h>
#include <AK/Span.h>
@ -123,5 +123,3 @@ TEST_CASE(span_from_c_string)
const char* str = "Serenity";
[[maybe_unused]] ReadonlyBytes bytes { str, strlen(str) };
}
TEST_MAIN(Span)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/FlyString.h>
#include <AK/String.h>
@ -235,5 +235,3 @@ TEST_CASE(sprintf)
EXPECT_EQ(String(buf1), String("+12"));
EXPECT_EQ(String(buf2), String("-12"));
}
TEST_MAIN(String)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/StringUtils.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/String.h>
@ -177,5 +177,3 @@ TEST_CASE(split_view)
EXPECT_EQ(test_string_view.split_view_if(predicate), Vector<StringView>({ "a", "b", "c", "d" }));
EXPECT_EQ(test_string_view.split_view_if(predicate, true), Vector<StringView>({ "a", "", "b", "c", "d" }));
}
TEST_MAIN(StringView)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Time.h>
#include <sys/time.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Trie.h>
@ -66,5 +66,3 @@ TEST_CASE(iterate)
++i;
}
}
TEST_MAIN(Trie)

View file

@ -4,8 +4,9 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/StdLibExtras.h>
#include <AK/TestSuite.h>
#include <AK/TypeList.h>
#define STATIC_EXPECT_EQ(lhs, rhs) \
@ -104,5 +105,3 @@ TEST_CASE(UnderlyingType)
STATIC_EXPECT_EQ(Type, u8);
}
TEST_MAIN(TypeTraits)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Array.h>
#include <AK/TypedTransfer.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/URL.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Utf8View.h>
@ -67,5 +67,3 @@ TEST_CASE(validate_invalid_ut8)
EXPECT(!utf8_4.validate(valid_bytes));
EXPECT(valid_bytes == 0);
}
TEST_MAIN(UTF8)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/NonnullOwnPtrVector.h>
#include <AK/OwnPtr.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/String.h>
#include <AK/WeakPtr.h>
@ -64,5 +64,3 @@ TEST_CASE(weakptr_move)
EXPECT_EQ(weak2.is_null(), true);
}
TEST_MAIN(WeakPtr)

View file

@ -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})

View file

@ -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 $<TARGET_OBJECTS:LagomCore> ${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

View file

@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include "../CSV.h"
#include "../XSV.h"
@ -72,5 +72,3 @@ We"ll,"Hello,", Friends
EXPECT_EQ(StringView { stream.bytes() }, expected_output);
}
TEST_MAIN(XSV)

View file

@ -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()

View file

@ -5,7 +5,7 @@
*/
#include <AK/StringView.h>
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <time.h>
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)

View file

@ -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()

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Array.h>
#include <AK/MemoryStream.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Array.h>
#include <AK/Random.h>
@ -95,5 +95,3 @@ TEST_CASE(gzip_round_trip)
EXPECT(uncompressed.has_value());
EXPECT(uncompressed.value() == original);
}
TEST_MAIN(Gzip)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Array.h>
#include <LibCompress/Zlib.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h> // import first, to prevent warning of VERIFY* redefinition
#include <LibTest/TestCase.h> // import first, to prevent warning of VERIFY* redefinition
#include <LibRegex/Regex.h>
#include <stdio.h>
@ -967,5 +967,3 @@ BENCHMARK_CASE(simple_notbol_noteol_benchmark_reference_stdcpp)
# endif
#endif
TEST_MAIN(Regex)

View file

@ -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()

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h> // import first, to prevent warning of VERIFY* redefinition
#include <LibTest/TestCase.h> // import first, to prevent warning of VERIFY* redefinition
#include <AK/StringBuilder.h>
#include <LibRegex/Regex.h>
@ -595,5 +595,3 @@ TEST_CASE(replace)
EXPECT_EQ(re.replace(test.subject, test.replacement), test.expected);
}
}
TEST_MAIN(Regex)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/StringBuilder.h>
#include <LibC/regex.h>
@ -1116,5 +1116,3 @@ TEST_CASE(simple_notbol_noteol)
regfree(&regex);
}
TEST_MAIN(Regex)

View file

@ -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()

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/HashMap.h>
#include <AK/Result.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/Optional.h>
#include <AK/Result.h>
@ -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)

View file

@ -1 +1,8 @@
serenity_install_sources("Userland/Libraries/LibTest")
set(SOURCES
TestSuite.cpp
)
serenity_lib(LibTest test)
target_link_libraries(LibTest LibC)

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Assertions.h>
#include <AK/CheckedFormatString.h>
namespace AK {
template<typename... Parameters>
void warnln(CheckedFormatString<Parameters...>&& 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<double>(expect_close_lhs) - static_cast<double>(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)

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibTest/Macros.h> // intentionally first -- we redefine VERIFY and friends in here
#include <AK/Function.h>
#include <AK/NonnullRefPtr.h>
#include <AK/RefCounted.h>
#include <AK/String.h>
namespace Test {
using TestFunction = Function<void()>;
class TestCase : public RefCounted<TestCase> {
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<TestCase>& 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)()

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/Format.h>
#include <LibTest/TestSuite.h>
#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;
}

View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/Macros.h> // intentionally first -- we redefine VERIFY and friends in here
#include <LibCore/ArgsParser.h>
#include <LibTest/TestSuite.h>
#include <stdlib.h>
#include <sys/time.h>
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<TestCase>& 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<TestCase> TestSuite::find_cases(const String& search, bool find_tests, bool find_benchmarks)
{
NonnullRefPtrVector<TestCase> 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<TestCase>& 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;
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibTest/Macros.h> // intentionally first -- we redefine VERIFY and friends in here
#include <AK/Format.h>
#include <AK/Function.h>
#include <AK/NonnullRefPtrVector.h>
#include <AK/String.h>
#include <LibTest/TestCase.h>
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<TestCase>&);
int main(const String& suite_name, int argc, char** argv);
NonnullRefPtrVector<TestCase> find_cases(const String& search, bool find_tests, bool find_benchmarks);
void add_case(const NonnullRefPtr<TestCase>& 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<TestCase> m_cases;
u64 m_testtime = 0;
u64 m_benchtime = 0;
String m_suite_name;
bool m_current_test_case_passed = true;
};
}

View file

@ -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})

View file

@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/ByteBuffer.h>
#include <AK/Random.h>
@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <AK/ByteBuffer.h>
#include <AK/Random.h>
@ -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)

View file

@ -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)

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/Painter.h>
@ -51,5 +51,3 @@ BENCHMARK_CASE(fill_with_gradient)
painter.fill_rect_with_gradient(bitmap->rect(), Color::Blue, Color::Red);
}
}
TEST_MAIN(Painter)

View file

@ -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()

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TestSuite.h>
#include <LibTest/TestCase.h>
#include <float.h>
#include <math.h>
@ -250,5 +250,3 @@ TEST_CASE(fmax_and_fmin)
EXPECT(fmin(0, NAN) == 0);
EXPECT(isnan(fmin(NAN, NAN)));
}
TEST_MAIN(Math)

View file

@ -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})