From b3e3e4d45d2136b6ed447e1bbaf4428d9eee8695 Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Wed, 1 Sep 2021 04:40:46 -0600 Subject: [PATCH] Tests: Convert remaining LibC tests to LibTest Convert them to using outln instead of printf at the same time. --- Tests/LibC/CMakeLists.txt | 42 ++++----- .../LibC/{memmem-tests.cpp => TestMemmem.cpp} | 15 +-- ...ort-sorts-and-copies.cpp => TestQsort.cpp} | 18 ++-- Tests/LibC/TestRealpath.cpp | 85 +++++++++++++++++ Tests/LibC/{scanf.cpp => TestScanf.cpp} | 8 +- ...rintf-correctness.cpp => TestSnprintf.cpp} | 0 ...trlcpy-correctness.cpp => TestStrlcpy.cpp} | 17 ---- ...racy-strtod.cpp => TestStrtodAccuracy.cpp} | 34 +++---- Tests/LibC/overlong_realpath.cpp | 94 ------------------- 9 files changed, 135 insertions(+), 178 deletions(-) rename Tests/LibC/{memmem-tests.cpp => TestMemmem.cpp} (82%) rename Tests/LibC/{qsort-sorts-and-copies.cpp => TestQsort.cpp} (82%) create mode 100644 Tests/LibC/TestRealpath.cpp rename Tests/LibC/{scanf.cpp => TestScanf.cpp} (98%) rename Tests/LibC/{snprintf-correctness.cpp => TestSnprintf.cpp} (100%) rename Tests/LibC/{strlcpy-correctness.cpp => TestStrlcpy.cpp} (89%) rename Tests/LibC/{accuracy-strtod.cpp => TestStrtodAccuracy.cpp} (97%) delete mode 100644 Tests/LibC/overlong_realpath.cpp diff --git a/Tests/LibC/CMakeLists.txt b/Tests/LibC/CMakeLists.txt index 6922f765055..daec9dae636 100644 --- a/Tests/LibC/CMakeLists.txt +++ b/Tests/LibC/CMakeLists.txt @@ -1,28 +1,24 @@ set(TEST_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/snprintf-correctness.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/strlcpy-correctness.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCTime.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCMkTemp.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCExec.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCDirEnt.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCInodeWatcher.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCSetjmp.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCString.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestStackSmash.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestIo.cpp + TestIo.cpp + TestLibCExec.cpp + TestLibCDirEnt.cpp + TestLibCInodeWatcher.cpp + TestLibCMkTemp.cpp + TestLibCSetjmp.cpp + TestLibCString.cpp + TestLibCTime.cpp + TestMemmem.cpp + TestQsort.cpp + TestRealpath.cpp + TestScanf.cpp + TestSnprintf.cpp + TestStackSmash.cpp + TestStrlcpy.cpp + TestStrtodAccuracy.cpp ) -file(GLOB CMD_SOURCES CONFIGURE_DEPENDS "*.cpp") -list(REMOVE_ITEM CMD_SOURCES ${TEST_SOURCES}) +set_source_files_properties(TestStrtodAccuracy.cpp PROPERTIES COMPILE_FLAGS "-fno-builtin-strtod") -# 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) - install(TARGETS ${CMD_NAME} RUNTIME DESTINATION usr/Tests/LibC) -endforeach() - -foreach(source ${TEST_SOURCES}) - serenity_test(${source} LibC) +foreach(source IN LISTS TEST_SOURCES) + serenity_test("${source}" LibC) endforeach() diff --git a/Tests/LibC/memmem-tests.cpp b/Tests/LibC/TestMemmem.cpp similarity index 82% rename from Tests/LibC/memmem-tests.cpp rename to Tests/LibC/TestMemmem.cpp index 3a59fb6126e..f266b53dad4 100644 --- a/Tests/LibC/memmem-tests.cpp +++ b/Tests/LibC/TestMemmem.cpp @@ -4,12 +4,10 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include -#include -#include -#include #include -#include struct TestCase { const u8* haystack; @@ -32,20 +30,15 @@ const static TestCase g_test_cases[] = { { (const u8[64]) { 0, 1, 1, 2 }, 64u, (const u8[33]) { 1, 1 }, 2u, 1 }, }; -int main() +TEST_CASE(memmem_search) { - bool failed = false; size_t i = 0; for (const auto& test_case : g_test_cases) { auto expected = test_case.matching_offset >= 0 ? test_case.haystack + test_case.matching_offset : nullptr; auto result = memmem(test_case.haystack, test_case.haystack_length, test_case.needle, test_case.needle_length); if (result != expected) { - failed = true; - fprintf(stderr, "Test %zu FAILED! expected %p, got %p\n", i, expected, result); + FAIL(String::formatted("Test {} FAILED! expected {:p}, got {:p}", i, expected, result)); } ++i; } - - printf(failed ? "FAIL\n" : "PASS\n"); - return failed ? 1 : 0; } diff --git a/Tests/LibC/qsort-sorts-and-copies.cpp b/Tests/LibC/TestQsort.cpp similarity index 82% rename from Tests/LibC/qsort-sorts-and-copies.cpp rename to Tests/LibC/TestQsort.cpp index 95b4579cbb6..204d0e6f75d 100644 --- a/Tests/LibC/qsort-sorts-and-copies.cpp +++ b/Tests/LibC/TestQsort.cpp @@ -4,10 +4,12 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include +#include #include #include -#include #include const size_t NUM_RUNS = 100; @@ -39,13 +41,13 @@ static int calc_payload_for_pos(size_t pos) static void shuffle_vec(Vector& test_objects) { for (size_t i = 0; i < test_objects.size() * 3; ++i) { - auto i1 = rand() % test_objects.size(); - auto i2 = rand() % test_objects.size(); + auto i1 = get_random_uniform(test_objects.size()); + auto i2 = get_random_uniform(test_objects.size()); swap(test_objects[i1], test_objects[i2]); } } -int main() +TEST_CASE(quick_sort) { // Generate vector of SortableObjects in sorted order, with payloads determined by their sorted positions Vector test_objects; @@ -61,8 +63,7 @@ int main() const auto& key1 = test_objects[i].m_key; const auto& key2 = test_objects[i + 1].m_key; if (key1 > key2) { - printf("\x1b[01;35mTests failed: saw key %d before key %d\n", key1, key2); - return 1; + FAIL(String::formatted("saw key {} before key {}\n", key1, key2)); } } // Check that the object's payloads have not been corrupted @@ -70,11 +71,8 @@ int main() const auto expected = calc_payload_for_pos(i); const auto payload = test_objects[i].m_payload; if (payload != expected) { - printf("\x1b[01;35mTests failed: expected payload %d for pos %u, got payload %d\n", expected, i, payload); - return 1; + FAIL(String::formatted("Expected payload {} for pos {}, got payload {}", expected, i, payload)); } } } - printf("PASS\n"); - return 0; } diff --git a/Tests/LibC/TestRealpath.cpp b/Tests/LibC/TestRealpath.cpp new file mode 100644 index 00000000000..1ca9ac5540b --- /dev/null +++ b/Tests/LibC/TestRealpath.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Ben Wiederhake + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static constexpr char TMPDIR_PATTERN[] = "/tmp/overlong_realpath_XXXXXX"; +static constexpr char PATH_LOREM_250[] = "This-is-an-annoyingly-long-name-that-should-take-up-exactly-two-hundred-and-fifty-characters-and-is-surprisingly-difficult-to-fill-with-reasonably-meaningful-text-which-is-necessary-because-that-makes-it-easier-for-my-eyes-to-spot-any-corruption-fast"; + +static constexpr size_t ITERATION_DEPTH = 17; + +static void check_result(const char* what, const String& expected, const char* actual) +{ + if (expected != actual) + FAIL(String::formatted("Expected {} to be \"{}\" ({} characters)", what, actual, actual ? strlen(actual) : 0)); +} + +TEST_CASE(overlong_realpath) +{ + // We want to construct a path that is over PATH_MAX characters long. + // This cannot be done in a single step. + + // First, switch to a known environment: + char tmp_dir[] = "/tmp/overlong_realpath_XXXXXX"; + + errno = 0; + auto* new_dir = mkdtemp(tmp_dir); + VERIFY(new_dir != nullptr); + VERIFY(errno == 0); + + errno = 0; + auto ret = chdir(tmp_dir); + VERIFY(ret >= 0); + VERIFY(errno == 0); + + // Then, create a long path. + StringBuilder expected; + expected.append(tmp_dir); + + // But first, demonstrate the functionality at a reasonable depth: + auto expected_str = expected.build(); + check_result("getwd", expected_str, getwd(static_cast(calloc(1, PATH_MAX)))); + check_result("getcwd", expected_str, getcwd(nullptr, 0)); + check_result("realpath", expected_str, realpath(".", nullptr)); + + for (size_t i = 0; i < ITERATION_DEPTH; ++i) { + ret = mkdir(PATH_LOREM_250, S_IRWXU); + if (ret < 0) { + perror("mkdir iter"); + FAIL(String::formatted("Unable to mkdir the overlong path fragment in iteration {}", i)); + return; + } + expected.append('/'); + expected.append(PATH_LOREM_250); + ret = chdir(PATH_LOREM_250); + if (ret < 0) { + perror("chdir iter"); + FAIL(String::formatted("Unable to chdir to the overlong path fragment in iteration {}", i)); + return; + } + } + outln("cwd should now be ridiculously large"); + + // Evaluate + expected_str = expected.build(); + + check_result("getwd", {}, getwd(static_cast(calloc(1, PATH_MAX)))); + check_result("getcwd", expected_str, getcwd(nullptr, 0)); + check_result("realpath", expected_str, realpath(".", nullptr)); + + VERIFY(strlen(PATH_LOREM_250) == 250); + VERIFY(strlen(TMPDIR_PATTERN) + ITERATION_DEPTH * (1 + strlen(PATH_LOREM_250)) == expected_str.length()); + VERIFY(expected_str.length() > PATH_MAX); +} diff --git a/Tests/LibC/scanf.cpp b/Tests/LibC/TestScanf.cpp similarity index 98% rename from Tests/LibC/scanf.cpp rename to Tests/LibC/TestScanf.cpp index 35047d49ca1..cd6d9f27d6a 100644 --- a/Tests/LibC/scanf.cpp +++ b/Tests/LibC/TestScanf.cpp @@ -4,6 +4,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include #include #include @@ -233,13 +235,11 @@ static void do_one_test(const TestSuite& test) else printf(" overall FAIL\n"); - g_any_failed = g_any_failed || !overall; + VERIFY(overall); } -int main() +TEST_CASE(scanf) { for (auto& test : test_suites) do_one_test(test); - - return g_any_failed ? 1 : 0; } diff --git a/Tests/LibC/snprintf-correctness.cpp b/Tests/LibC/TestSnprintf.cpp similarity index 100% rename from Tests/LibC/snprintf-correctness.cpp rename to Tests/LibC/TestSnprintf.cpp diff --git a/Tests/LibC/strlcpy-correctness.cpp b/Tests/LibC/TestStrlcpy.cpp similarity index 89% rename from Tests/LibC/strlcpy-correctness.cpp rename to Tests/LibC/TestStrlcpy.cpp index 9ce801751ff..cf4c0a99885 100644 --- a/Tests/LibC/strlcpy-correctness.cpp +++ b/Tests/LibC/TestStrlcpy.cpp @@ -107,23 +107,6 @@ static bool test_single(const Testcase& testcase) // Drop the NUL terminator added by the C++ compiler. #define LITERAL(x) x, (sizeof(x) - 1) -//static Testcase TESTCASES[] = { -// // Golden path: - -// // Hitting the border: - -// // Too long: -// { LITERAL("Hello World!\0"), LITERAL("Hello Friend!"), LITERAL("Hello Friend\0") }, -// { LITERAL("Hello World!\0"), LITERAL("This source is just *way* too long!"), LITERAL("This source \0") }, -// { LITERAL("x"), LITERAL("This source is just *way* too long!"), LITERAL("\0") }, -// // Other special cases: -// { LITERAL(""), LITERAL(""), LITERAL("") }, -// { LITERAL(""), LITERAL("Empty test"), LITERAL("") }, -// { LITERAL("x"), LITERAL(""), LITERAL("\0") }, -// { LITERAL("xx"), LITERAL(""), LITERAL("\0x") }, -// { LITERAL("xxx"), LITERAL(""), LITERAL("\0xx") }, -//}; - TEST_CASE(golden_path) { EXPECT(test_single({ LITERAL("Hello World!\0\0\0"), LITERAL("Hello Friend!"), LITERAL("Hello Friend!\0\0") })); diff --git a/Tests/LibC/accuracy-strtod.cpp b/Tests/LibC/TestStrtodAccuracy.cpp similarity index 97% rename from Tests/LibC/accuracy-strtod.cpp rename to Tests/LibC/TestStrtodAccuracy.cpp index af833c23235..5f57769299a 100644 --- a/Tests/LibC/accuracy-strtod.cpp +++ b/Tests/LibC/TestStrtodAccuracy.cpp @@ -4,13 +4,12 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include -#include +#include + +#include +#include #include #include -#include -#include static constexpr char TEXT_ERROR[] = "\x1b[01;35m"; static constexpr char TEXT_WRONG[] = "\x1b[01;31m"; @@ -291,7 +290,7 @@ static bool is_strtod_close(strtod_fn_t strtod_fn, const char* test_string, cons bool error_cns = !actual_consume_possible; bool wrong_cns = !error_cns && (actual_consume != expect_consume); - printf(" %s%s%s(%s%2u%s)", + out(" {}{}{}({}{:2}{})", ofby1_hex ? TEXT_OFBY1 : wrong_hex ? TEXT_WRONG : "", actual_hex, @@ -315,8 +314,8 @@ static long long hex_to_ll(const char* hex) } else if ('a' <= ch && ch <= 'f') { digit = ch - 'a' + 10; } else { - printf("\n!!! Encountered char %02x at %d.\n", ch, i); - assert(false); + FAIL(String::formatted("\n!!! Encountered char {:02x} at {}", ch, i)); + return result; } result <<= 4; result += digit; @@ -324,10 +323,10 @@ static long long hex_to_ll(const char* hex) return result; } -int main() +TEST_CASE(strtod_accuracy) { - printf("Running %zu testcases...\n", NUM_TESTCASES); - printf("%3s(%-5s): %16s(%2s) %16s(%2s) %16s(%2s) %16s(%2s) – %s\n", "num", "name", "correct", "cs", "builtin", "cs", "old_strtod", "cs", "new_strtod", "cs", "teststring"); + outln("Running {} testcases...", NUM_TESTCASES); + outln("{:3}({:-5}): {:16}({:2}) {:16}({:2}) - {}", "num", "name", "correct", "cs", "strtod", "cs", "teststring"); int successes = 0; int fails = 0; @@ -336,13 +335,12 @@ int main() if (tc.should_consume == -1) { tc.should_consume = strlen(tc.test_string); } - printf("%3zu(%-5s):", i, tc.test_name); - printf(" %s(%2d)", tc.hex, tc.should_consume); + out("{:3}({:-5}): {}({:2})", i, tc.test_name, tc.hex, tc.should_consume); long long expect_ll = hex_to_ll(tc.hex); bool success = false; success = is_strtod_close(strtod, tc.test_string, tc.hex, tc.should_consume, expect_ll); - printf(" from %s\n", tc.test_string); + outln(" from {}", tc.test_string); if (success) { successes += 1; @@ -350,12 +348,10 @@ int main() fails += 1; } } - printf("Out of %zu tests, saw %d successes and %d fails.\n", NUM_TESTCASES, successes, fails); + outln("Out of {} tests, saw {} successes and {} fails.", NUM_TESTCASES, successes, fails); if (fails != 0) { - printf("FAIL\n"); - return 1; + FAIL(String::formatted("{} strtod tests failed", fails)); } - printf("PASS (with leniency up to %lld ULP from the exact solution.\n", LENIENCY); - return 0; + outln("PASS (with leniency up to {} ULP from the exact solution)", LENIENCY); } diff --git a/Tests/LibC/overlong_realpath.cpp b/Tests/LibC/overlong_realpath.cpp deleted file mode 100644 index df307d9a8d6..00000000000 --- a/Tests/LibC/overlong_realpath.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2021, Ben Wiederhake - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -// FIXME -static constexpr char TEXT_FAIL[] = "\x1b[01;31m"; -static constexpr char TEXT_PASS[] = "\x1b[01;32m"; -static constexpr char TEXT_RESET[] = "\x1b[0m"; - -static constexpr char TMPDIR_PATTERN[] = "/tmp/overlong_realpath_XXXXXX"; -static constexpr char PATH_LOREM_250[] = "This-is-an-annoyingly-long-name-that-should-take-up-exactly-two-hundred-and-fifty-characters-and-is-surprisingly-difficult-to-fill-with-reasonably-meaningful-text-which-is-necessary-because-that-makes-it-easier-for-my-eyes-to-spot-any-corruption-fast"; - -static constexpr size_t ITERATION_DEPTH = 17; - -static bool check_result(const char* what, const String& expected, const char* actual) -{ - bool good = expected == actual; - printf("%s%s%s: %s = \"%s\" (%zu characters)\n", good ? TEXT_PASS : TEXT_FAIL, good ? "GOOD" : "FAIL", TEXT_RESET, what, actual, actual ? strlen(actual) : 0); - return good; -} - -int main() -{ - // We want to construct a path that is over PATH_MAX characters long. - // This cannot be done in a single step. - - // First, switch to a known environment: - char* tmp_dir = strdup("/tmp/overlong_realpath_XXXXXX"); - if (!mkdtemp(tmp_dir)) { - perror("mkdtmp"); - return 1; - } - if (chdir(tmp_dir) < 0) { - perror("chdir tmpdir"); - return 1; - } - - // Then, create a long path. - StringBuilder expected; - expected.append(tmp_dir); - - // But first, demonstrate the functionality at a reasonable depth: - bool all_good = true; - auto expected_str = expected.build(); - all_good &= check_result("getwd", expected_str, getwd(static_cast(calloc(1, PATH_MAX)))); - all_good &= check_result("getcwd", expected_str, getcwd(nullptr, 0)); - all_good &= check_result("realpath", expected_str, realpath(".", nullptr)); - - for (size_t i = 0; i < ITERATION_DEPTH; ++i) { - if (mkdir(PATH_LOREM_250, 0700) < 0) { - perror("mkdir iter"); - printf("%sFAILED%s in iteration %zu.\n", TEXT_FAIL, TEXT_RESET, i); - return 1; - } - expected.append('/'); - expected.append(PATH_LOREM_250); - if (chdir(PATH_LOREM_250) < 0) { - perror("chdir iter"); - printf("%sFAILED%s in iteration %zu.\n", TEXT_FAIL, TEXT_RESET, i); - return 1; - } - } - printf("cwd should now be ridiculously large.\n"); - - // Evaluate - expected_str = expected.build(); - - all_good &= check_result("getwd", {}, getwd(static_cast(calloc(1, PATH_MAX)))); - all_good &= check_result("getcwd", expected_str, getcwd(nullptr, 0)); - all_good &= check_result("realpath", expected_str, realpath(".", nullptr)); - - VERIFY(strlen(PATH_LOREM_250) == 250); - VERIFY(strlen(TMPDIR_PATTERN) + ITERATION_DEPTH * (1 + strlen(PATH_LOREM_250)) == expected_str.length()); - VERIFY(expected_str.length() > PATH_MAX); - - if (all_good) { - printf("Overall: %sPASS%s\n", TEXT_PASS, TEXT_RESET); - return 0; - } else { - printf("Overall: %sFAIL%s\n", TEXT_FAIL, TEXT_RESET); - return 2; - } -}