// Copy the original test file but add debugging #include #include #include #include #include "../lib/platform_compat.h" #include #include "u_async.h" #include "timeout_heap.h" /* Test statistics */ static struct { int tests_run; int tests_passed; int tests_failed; /* Timer statistics */ int timer_callbacks; int timer_cancellations; int immediate_timeouts; /* Socket statistics */ int socket_events; int socket_errors; /* Error statistics */ int memory_allocation_errors; int invalid_parameter_errors; int race_condition_errors; } test_stats = {0}; /* Test result tracking */ #define TEST_START(name) do { \ printf("TEST: %s... \n", name); \ printf(" immediate_timeouts before: %d\n", test_stats.immediate_timeouts); \ test_stats.tests_run++; \ } while(0) #define TEST_PASS() do { \ printf(" immediate_timeouts after: %d\n", test_stats.immediate_timeouts); \ printf("PASS\n"); \ test_stats.tests_passed++; \ } while(0) #define TEST_FAIL(msg) do { \ printf(" immediate_timeouts after: %d\n", test_stats.immediate_timeouts); \ printf("FAIL: %s\n", msg); \ test_stats.tests_failed++; \ } while(0) #define ASSERT_EQ(a, b, msg) do { \ if ((a) != (b)) { \ TEST_FAIL(msg); \ printf(" Expected: %ld, Got: %ld\n", (long)(b), (long)(a)); \ return; \ } \ } while(0) #define ASSERT_NOT_NULL(ptr, msg) do { \ if ((ptr) == NULL) { \ TEST_FAIL(msg); \ return; \ } \ } while(0) /* Test context for callbacks */ typedef struct { int callback_count; int expected_count; int callback_arg; int timeout_ms; uasync_t* ua; void* timer_id; } test_context_t; /* Timer callback for testing */ static void test_timer_callback(void* arg) { test_context_t* ctx = (test_context_t*)arg; ctx->callback_count++; test_stats.timer_callbacks++; if (ctx->timeout_ms == 0) { test_stats.immediate_timeouts++; printf(" IMMEDIATE TIMEOUT: immediate_timeouts now = %d\n", test_stats.immediate_timeouts); } } /* Test 1: Basic timer functionality */ static void test_basic_timers(void) { TEST_START("Basic timer functionality"); uasync_t* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync instance"); test_context_t ctx = {0}; ctx.expected_count = 3; ctx.timeout_ms = 10; // Non-zero to avoid immediate timeout counting /* Set multiple timers with different timeouts */ void* timer1 = uasync_set_timeout(ua, 10, &ctx, test_timer_callback); /* 1ms */ void* timer2 = uasync_set_timeout(ua, 20, &ctx, test_timer_callback); /* 2ms */ void* timer3 = uasync_set_timeout(ua, 30, &ctx, test_timer_callback); /* 3ms */ ASSERT_NOT_NULL(timer1, "Failed to set timer 1"); ASSERT_NOT_NULL(timer2, "Failed to set timer 2"); ASSERT_NOT_NULL(timer3, "Failed to set timer 3"); /* Poll and verify timers fire in order */ int poll_count = 0; while (ctx.callback_count < ctx.expected_count && poll_count < 100) { uasync_poll(ua, 10); /* 1ms poll */ poll_count++; } ASSERT_EQ(ctx.callback_count, ctx.expected_count, "Not all timers fired"); /* Cleanup */ uasync_destroy(ua, 0); TEST_PASS(); } /* Test 2: Timer cancellation race conditions */ static void test_timer_cancellation_races(void) { TEST_START("Timer cancellation race conditions"); uasync_t* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync instance"); test_context_t ctx = {0}; ctx.expected_count = 2; ctx.timeout_ms = 5; // Non-zero to avoid immediate timeout counting /* Create timers that will be cancelled at different stages */ void* timer1 = uasync_set_timeout(ua, 5, &ctx, test_timer_callback); /* 0.5ms */ void* timer2 = uasync_set_timeout(ua, 50, &ctx, test_timer_callback); /* 5ms */ void* timer3 = uasync_set_timeout(ua, 100, &ctx, test_timer_callback); /* 10ms */ ASSERT_NOT_NULL(timer1, "Failed to set timer 1"); ASSERT_NOT_NULL(timer2, "Failed to set timer 2"); ASSERT_NOT_NULL(timer3, "Failed to set timer 3"); /* Cancel timer1 immediately (before it fires) */ err_t cancel_result = uasync_cancel_timeout(ua, timer1); ASSERT_EQ(cancel_result, ERR_OK, "Failed to cancel timer 1"); test_stats.timer_cancellations++; /* Poll briefly - timer1 should not fire, others should */ uasync_poll(ua, 10); /* 1ms */ /* Cancel timer2 while it might be firing */ cancel_result = uasync_cancel_timeout(ua, timer2); /* Result could be ERR_OK or ERR_FAIL depending on timing */ /* Continue polling */ int poll_count = 0; while (ctx.callback_count < 2 && poll_count < 50) { uasync_poll(ua, 10); poll_count++; } /* Verify we got expected callbacks (timer3 + possibly timer2) */ if (ctx.callback_count < 1 || ctx.callback_count > 2) { TEST_FAIL("Wrong number of timers fired"); return; } /* Cleanup remaining timer */ if (timer3) { uasync_cancel_timeout(ua, timer3); timer3 = NULL; } uasync_destroy(ua, 0); TEST_PASS(); } /* Test 3: Immediate timeout handling */ static void test_immediate_timeouts(void) { TEST_START("Immediate timeout handling"); uasync_t* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync instance"); test_context_t ctx = {0}; ctx.expected_count = 5; ctx.timeout_ms = 0; // This should trigger immediate timeout counting /* Set multiple immediate timeouts (0ms) */ for (int i = 0; i < 5; i++) { void* timer = uasync_set_timeout(ua, 0, &ctx, test_timer_callback); ASSERT_NOT_NULL(timer, "Failed to set immediate timer"); } /* Immediate timeouts should fire during next poll */ ASSERT_EQ(ctx.callback_count, 0, "Callbacks fired too early"); printf(" About to call uasync_poll, immediate_timeouts = %d\n", test_stats.immediate_timeouts); uasync_poll(ua, 1); /* Minimal poll */ printf(" After uasync_poll, immediate_timeouts = %d\n", test_stats.immediate_timeouts); ASSERT_EQ(ctx.callback_count, ctx.expected_count, "Immediate timeouts didn't fire correctly"); ASSERT_EQ(test_stats.immediate_timeouts, 5, "Immediate timeout counter incorrect"); uasync_destroy(ua, 0); TEST_PASS(); } int main(void) { printf("=== lib Comprehensive Unit Tests ===\n"); printf("Testing race conditions, memory management, and error handling\n\n"); printf("Initial immediate_timeouts: %d\n", test_stats.immediate_timeouts); /* Run all tests */ test_basic_timers(); printf("After basic_timers: immediate_timeouts = %d\n", test_stats.immediate_timeouts); test_timer_cancellation_races(); printf("After timer_cancellation_races: immediate_timeouts = %d\n", test_stats.immediate_timeouts); test_immediate_timeouts(); printf("After immediate_timeouts: immediate_timeouts = %d\n", test_stats.immediate_timeouts); /* Print final statistics */ printf("\n=== Final Statistics ===\n"); printf("Timer callbacks: %d\n", test_stats.timer_callbacks); printf("Immediate timeouts: %d\n", test_stats.immediate_timeouts); return (test_stats.tests_failed > 0) ? 1 : 0; }