From 47b21bfc0cca48bcc9e41418afa5cdefae2f221f Mon Sep 17 00:00:00 2001 From: ikpil Date: Mon, 19 May 2025 00:07:36 +0900 Subject: [PATCH] Add unit test framework for ENet library Set up testing infrastructure to validate core ENet functionality. --- CMakeLists.txt | 7 +++ test/units/enet_unit.h | 102 ++++++++++++++++++++++++++++++++++++++++ test/units/test_main.c | 18 +++++++ test/units/test_times.c | 99 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 226 insertions(+) create mode 100644 test/units/enet_unit.h create mode 100644 test/units/test_main.c create mode 100644 test/units/test_times.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c49fe76..7b3d679 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,13 @@ if(ENET_TEST) target_link_libraries(enet_test_extra_peers PRIVATE enet_test_interface) target_compile_definitions(enet_test_extra_peers PRIVATE ENET_USE_MORE_PEERS) + # Test unit + add_executable(enet_test_unit test/units/test_main.c) + target_link_libraries(enet_test_unit PRIVATE enet_test_interface) + target_include_directories(enet_test_unit INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/test/units/include + ) endif() # ----------------------------- diff --git a/test/units/enet_unit.h b/test/units/enet_unit.h new file mode 100644 index 0000000..2bad73d --- /dev/null +++ b/test/units/enet_unit.h @@ -0,0 +1,102 @@ +#ifndef ENET_UNIT_H +#define ENET_UNIT_H + +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +typedef struct _ENetTestEntry ENetTestEntry; + +typedef void (*ENetUnitTestFunc)(ENetTestEntry *entry); + +typedef struct _ENetTestEntry { + const char *name; + ENetUnitTestFunc func; + int failed; +} ENetTestEntry; + +#define MAX_TESTS 8096 + +static ENetTestEntry enet_test_entries[MAX_TESTS]; +static int enet_test_count = 0; + +#ifdef _WIN32 +#define ASSERT_SLEEP(ms) Sleep(ms) +#else +#define ASSERT_SLEEP(ms) usleep(ms * 1000); +#endif + +#define GET_MACRO(_1, _2, _3, NAME, ...) NAME +#define ASSERT_THAT(...) GET_MACRO(__VA_ARGS__, ASSERT_THAT_IMPL3, ASSERT_THAT_IMPL2)(__VA_ARGS__) + +#define REGISTER_TEST(f) \ + do { \ + if (enet_test_count < MAX_TESTS) { \ + enet_test_entries[enet_test_count].name = #f; \ + enet_test_entries[enet_test_count].func = f; \ + enet_test_count++; \ + } else { \ + fprintf(stderr, "Too many unit tests!\n"); \ + } \ + } while (0) + +#define TEST(func) \ + static void test_##func(ENetTestEntry * entry); \ + __attribute__((constructor)) static void register_##func(void) { \ + REGISTER_TEST(test_##func); \ + } \ + static void test_##func(ENetTestEntry * entry) + +#define ASSERT_THAT_IMPL3(a, b, m) do { \ + if ((a) != (b)) { \ + entry->failed += 1; \ + fprintf(stderr, "%s\n", m); \ + fprintf(stderr, "ASSERT_THAT(%s, %s)\n", #a, #b); \ + fprintf(stderr, " Expected: %s\n", #b); \ + fprintf(stderr, " But was: %s\n", #a); \ + fprintf(stderr, "at %s:%d\n", __FILE__, __LINE__); \ + return; \ + } \ +} while (0) + +#define ASSERT_THAT_IMPL2(a, b) do { \ + if ((a) != (b)) { \ + entry->failed += 1; \ + fprintf(stderr, "ASSERT_THAT(%s, %s)\n", #a, #b); \ + fprintf(stderr, " Expected: %s\n", #b); \ + fprintf(stderr, " But was: %s\n", #a); \ + fprintf(stderr, "at %s:%d\n", __FILE__, __LINE__); \ + return; \ + } \ +} while (0) + +static int run_all_tests(void) { + int failed = 0; + for (int i = 0; i < enet_test_count; ++i) { + ENetTestEntry *entry = &enet_test_entries[i]; + + fprintf(stdout, "[ RUNNING ] %s\n", entry->name); + fflush(stdout); + + entry->func(entry); + fflush(stderr); + + if (0 < entry->failed) { + fprintf(stderr, "[ FAILED ] %s\n", entry->name); + fflush(stderr); + } else { + fprintf(stdout, "[ PASSED ] %s\n", entry->name); + fflush(stdout); + } + + failed += entry->failed; + } + + return failed; +} + +#endif diff --git a/test/units/test_main.c b/test/units/test_main.c new file mode 100644 index 0000000..3220ca2 --- /dev/null +++ b/test/units/test_main.c @@ -0,0 +1,18 @@ +#include + +#include "enet.h" +#include "enet_unit.h" +#include "test_times.c" + +int main() { + if (enet_initialize() != 0) { + printf("An error occurred while initializing ENet.\n"); + return 1; + } + + int failed = run_all_tests(); + + enet_deinitialize(); + + return failed; +} diff --git a/test/units/test_times.c b/test/units/test_times.c new file mode 100644 index 0000000..19f5b29 --- /dev/null +++ b/test/units/test_times.c @@ -0,0 +1,99 @@ +#include "enet.h" +#include "enet_unit.h" + +TEST(ENET_TIME_LESS) { + enet_uint32 a = 1000; + enet_uint32 b = 2000; + // Normal cases + ASSERT_THAT(ENET_TIME_LESS(a, b), true, "ENET_TIME_LESS should return true for a < b"); + ASSERT_THAT(ENET_TIME_LESS(a, a), false, "ENET_TIME_LESS should return false for a == b"); + ASSERT_THAT(ENET_TIME_LESS(b, a), false, "ENET_TIME_LESS should return false for a > b"); + + // Cases involving ENET_TIME_OVERFLOW constant + ASSERT_THAT(ENET_TIME_LESS(a, ENET_TIME_OVERFLOW), true, + "ENET_TIME_LESS with a < ENET_TIME_OVERFLOW and b == ENET_TIME_OVERFLOW should be true"); + ASSERT_THAT(ENET_TIME_LESS(ENET_TIME_OVERFLOW, a), false, + "ENET_TIME_LESS with a == ENET_TIME_OVERFLOW and b < ENET_TIME_OVERFLOW should be false"); + ASSERT_THAT(ENET_TIME_LESS(ENET_TIME_OVERFLOW, ENET_TIME_OVERFLOW), false, + "ENET_TIME_LESS with a == ENET_TIME_OVERFLOW and b == ENET_TIME_OVERFLOW should be false"); +} + +TEST(ENET_TIME_GREATER) { + enet_uint32 a = 1000; + enet_uint32 b = 2000; + // Normal cases + ASSERT_THAT(ENET_TIME_GREATER(b, a), true, "ENET_TIME_GREATER should return true for a > b"); + ASSERT_THAT(ENET_TIME_GREATER(a, a), false, "ENET_TIME_GREATER should return false for a == b"); + ASSERT_THAT(ENET_TIME_GREATER(a, b), false, "ENET_TIME_GREATER should return false for a < b"); + + // Cases involving ENET_TIME_OVERFLOW constant + ASSERT_THAT(ENET_TIME_GREATER(a, ENET_TIME_OVERFLOW), false, + "ENET_TIME_GREATER with a < ENET_TIME_OVERFLOW and b == ENET_TIME_OVERFLOW should be false"); + ASSERT_THAT(ENET_TIME_GREATER(ENET_TIME_OVERFLOW, a), true, + "ENET_TIME_GREATER with a == ENET_TIME_OVERFLOW and b < ENET_TIME_OVERFLOW should be true"); + // ENET_TIME_GREATER is !ENET_TIME_LESS_EQUAL + ASSERT_THAT(ENET_TIME_GREATER(ENET_TIME_OVERFLOW, ENET_TIME_OVERFLOW), false, + "ENET_TIME_GREATER with a == ENET_TIME_OVERFLOW and b == ENET_TIME_OVERFLOW should be false"); +} + +TEST(ENET_TIME_LESS_EQUAL) { + enet_uint32 a = 1000; + enet_uint32 b = 2000; + // Normal cases + ASSERT_THAT(ENET_TIME_LESS_EQUAL(a, b), true, "ENET_TIME_LESS_EQUAL should return true for a <= b"); + ASSERT_THAT(ENET_TIME_LESS_EQUAL(a, a), true, + "ENET_TIME_LESS_EQUAL should return true for a <= b (equal)"); + ASSERT_THAT(ENET_TIME_LESS_EQUAL(b, a), false, + "ENET_TIME_LESS_EQUAL should return false for a <= b (greater)"); + + // Cases involving ENET_TIME_OVERFLOW constant + ASSERT_THAT(ENET_TIME_LESS_EQUAL(a, ENET_TIME_OVERFLOW), true, + "ENET_TIME_LESS_EQUAL with a < ENET_TIME_OVERFLOW and b == ENET_TIME_OVERFLOW should be true"); + ASSERT_THAT(ENET_TIME_LESS_EQUAL(ENET_TIME_OVERFLOW, a), false, + "ENET_TIME_LESS_EQUAL with a == ENET_TIME_OVERFLOW and b < ENET_TIME_OVERFLOW should be false"); + ASSERT_THAT(ENET_TIME_LESS_EQUAL(ENET_TIME_OVERFLOW, ENET_TIME_OVERFLOW), true, + "ENET_TIME_LESS_EQUAL with a == ENET_TIME_OVERFLOW and b == ENET_TIME_OVERFLOW should be true"); +} + +TEST(ENET_TIME_GREATER_EQUAL) { + enet_uint32 a = 1000; + enet_uint32 b = 2000; + // Normal cases + ASSERT_THAT(ENET_TIME_GREATER_EQUAL(b, a), true, "ENET_TIME_GREATER_EQUAL should return true for a >= b"); + ASSERT_THAT(ENET_TIME_GREATER_EQUAL(a, a), true, "ENET_TIME_GREATER_EQUAL should return true for a >= b (equal)"); + ASSERT_THAT(ENET_TIME_GREATER_EQUAL(a, b), false, "ENET_TIME_GREATER_EQUAL should return false for a >= b (less)"); + + // Cases involving ENET_TIME_OVERFLOW constant (based on ENET_TIME_GREATER logic) + ASSERT_THAT(ENET_TIME_GREATER_EQUAL(a, ENET_TIME_OVERFLOW), false, + "ENET_TIME_GREATER_EQUAL with a < ENET_TIME_OVERFLOW and b == ENET_TIME_OVERFLOW should be false"); + ASSERT_THAT(ENET_TIME_GREATER_EQUAL(ENET_TIME_OVERFLOW, a), true, + "ENET_TIME_GREATER_EQUAL with a == ENET_TIME_OVERFLOW and b < ENET_TIME_OVERFLOW should be true"); + ASSERT_THAT(ENET_TIME_GREATER_EQUAL(ENET_TIME_OVERFLOW, ENET_TIME_OVERFLOW), true, + "ENET_TIME_GREATER_EQUAL with a == ENET_TIME_OVERFLOW and b == ENET_TIME_OVERFLOW should be true"); +} + +TEST(ENET_TIME_DIFFERENCE) { + // Normal cases + enet_uint32 a = 2000; + enet_uint32 b = 1000; + ASSERT_THAT(ENET_TIME_DIFFERENCE(a, b), 1000, + "ENET_TIME_DIFFERENCE should return the absolute difference for a > b"); + ASSERT_THAT(ENET_TIME_DIFFERENCE(b, a), 1000, + "ENET_TIME_DIFFERENCE should return the absolute difference for a < b"); + ASSERT_THAT(ENET_TIME_DIFFERENCE(a, a), 0u, "ENET_TIME_DIFFERENCE should return 0 for a == b"); + + // Case involving ENET_TIME_OVERFLOW constant as per user's example + enet_uint32 c = 1000; + enet_uint32 d = ENET_TIME_OVERFLOW; + ASSERT_THAT(ENET_TIME_DIFFERENCE(c, d), d - c, + "ENET_TIME_DIFFERENCE should return the difference involving ENET_TIME_OVERFLOW"); +} + +TEST(enet_time_get) { + enet_uint32 firstTime = enet_time_get(); + ASSERT_SLEEP(100); + enet_uint32 secondTime = enet_time_get(); + + ASSERT_THAT(secondTime >= firstTime, true, "enet_time_get should return increasing time"); + ASSERT_THAT(secondTime - firstTime > 90, true, "Time difference should be at least ~100ms"); +}