/** * Unified comprehensive test suite for ll_queue module * Combines: basic operations, position navigation, doubly-linked list, stress testing */ #include #include #include #include #include #include #include #include "../lib/ll_queue.h" #include "../lib/u_async.h" #include "../lib/debug_config.h" /* Test statistics */ static struct { int tests_run; int tests_passed; int tests_failed; /* Performance metrics */ double total_time_ms; int operations_count; /* Error tracking */ int memory_errors; int invalid_parameter_errors; } test_stats = {0}; /* Test result tracking */ #define TEST_START(name) do { \ printf("TEST: %s... ", name); \ test_stats.tests_run++; \ } while(0) #define TEST_PASS() do { \ printf("PASS\n"); \ test_stats.tests_passed++; \ } while(0) #define TEST_FAIL(msg) do { \ printf("FAIL: %s\n", msg); \ test_stats.tests_failed++; \ } while(0) #define ASSERT_TRUE(cond, msg) do { \ if (!(cond)) { \ TEST_FAIL(msg); \ return; \ } \ } while(0) #define ASSERT_FALSE(cond, msg) ASSERT_TRUE(!(cond), msg) #define ASSERT_NULL(ptr, msg) ASSERT_TRUE((ptr) == NULL, msg) #define ASSERT_NOT_NULL(ptr, msg) ASSERT_TRUE((ptr) != NULL, msg) #define ASSERT_EQ(a, b, msg) ASSERT_TRUE((a) == (b), msg) #define ASSERT_NEQ(a, b, msg) ASSERT_TRUE((a) != (b), msg) /* Test data structure */ struct test_data { int value; char name[32]; int checksum; }; /* Utility functions */ static double get_time_ms() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0; } static struct test_data* create_test_data(int value) { struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); if (!entry) return NULL; struct test_data* data = (struct test_data*)ll_entry_data(entry); data->value = value; snprintf(data->name, sizeof(data->name), "item_%d", value); data->checksum = value * 7 + 3; // Simple checksum return data; } static int verify_test_data(struct test_data* data) { if (!data) return 0; return data->checksum == (data->value * 7 + 3); } /* Test: Basic doubly-linked list operations */ static void test_doubly_linked_basics() { TEST_START("doubly_linked_basics"); struct UASYNC* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync"); struct ll_queue* q = queue_new(ua, NULL); ASSERT_NOT_NULL(q, "Failed to create queue"); ASSERT_EQ(queue_entry_count(q), 0, "Queue should be empty"); // Create and add test elements for (int i = 0; i < 5; i++) { struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); ASSERT_NOT_NULL(entry, "Failed to create entry"); struct test_data* data = (struct test_data*)ll_entry_data(entry); data->value = i; snprintf(data->name, sizeof(data->name), "item_%d", i); data->checksum = i * 7 + 3; ASSERT_EQ(queue_entry_put(q, entry), 0, "Failed to add entry to queue"); } ASSERT_EQ(queue_entry_count(q), 5, "Wrong queue count"); // Verify forward traversal with doubly-linked integrity struct ll_entry* curr = q->head; int forward_count = 0; while (curr) { struct test_data* data = (struct test_data*)ll_entry_data(curr); ASSERT_TRUE(verify_test_data(data), "Data corruption in forward traversal"); ASSERT_EQ(data->value, forward_count, "Wrong value in forward traversal"); // Verify doubly-linked integrity if (curr->prev) { ASSERT_NOT_NULL(curr->prev->next, "Broken prev link"); ASSERT_EQ(curr->prev->next, curr, "Invalid prev->next link"); } if (curr->next) { ASSERT_NOT_NULL(curr->next->prev, "Broken next link"); ASSERT_EQ(curr->next->prev, curr, "Invalid next->prev link"); } curr = curr->next; forward_count++; } ASSERT_EQ(forward_count, 5, "Wrong forward count"); // Verify backward traversal curr = q->tail; int backward_count = 4; while (curr) { struct test_data* data = (struct test_data*)ll_entry_data(curr); ASSERT_TRUE(verify_test_data(data), "Data corruption in backward traversal"); ASSERT_EQ(data->value, backward_count, "Wrong value in backward traversal"); curr = curr->prev; backward_count--; } ASSERT_EQ(backward_count, -1, "Wrong backward count"); queue_free(q); uasync_destroy(ua); TEST_PASS(); } /* Test: Position navigation system */ static void test_position_navigation() { TEST_START("position_navigation"); struct UASYNC* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync"); struct ll_queue* q = queue_new(ua, NULL); ASSERT_NOT_NULL(q, "Failed to create queue"); // Add test elements for (int i = 0; i < 5; i++) { struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); ASSERT_NOT_NULL(entry, "Failed to create entry"); struct test_data* data = (struct test_data*)ll_entry_data(entry); data->value = i; snprintf(data->name, sizeof(data->name), "item_%d", i); data->checksum = i * 7 + 3; ASSERT_EQ(queue_entry_put(q, entry), 0, "Failed to add entry"); } struct ll_queue_pos* pos = queue_pos_new(q); ASSERT_NOT_NULL(pos, "Failed to create position"); // Test initial state ASSERT_EQ(queue_pos_index(pos), -1, "Wrong initial index"); ASSERT_NULL(queue_pos_current(pos), "Current should be NULL initially"); // Test forward navigation int count = 0; while (queue_pos_next(pos)) { struct ll_entry* entry = queue_pos_current(pos); ASSERT_NOT_NULL(entry, "Current entry should not be NULL"); ASSERT_EQ(queue_pos_index(pos), count, "Wrong index in forward navigation"); struct test_data* data = (struct test_data*)ll_entry_data(entry); ASSERT_TRUE(verify_test_data(data), "Data corruption in position navigation"); ASSERT_EQ(data->value, count, "Wrong value in forward navigation"); count++; } ASSERT_EQ(count, 5, "Wrong forward navigation count"); // Test backward navigation int prev_count = 0; while (queue_pos_prev(pos)) { struct ll_entry* entry = queue_pos_current(pos); // Note: entry can be NULL when at position -1 (before head) if (entry) { struct test_data* data = (struct test_data*)ll_entry_data(entry); ASSERT_TRUE(verify_test_data(data), "Data corruption in backward navigation"); } prev_count++; } ASSERT_EQ(prev_count, 5, "Wrong backward navigation count"); // Test seek functionality ASSERT_EQ(queue_pos_seek(pos, 2), 1, "Seek to index 2 failed"); ASSERT_EQ(queue_pos_index(pos), 2, "Wrong index after seek"); struct ll_entry* entry = queue_pos_current(pos); ASSERT_NOT_NULL(entry, "Current entry should not be NULL after seek"); struct test_data* data = (struct test_data*)ll_entry_data(entry); ASSERT_TRUE(verify_test_data(data), "Data corruption after seek"); ASSERT_EQ(data->value, 2, "Wrong value after seek"); // Test invalid seek ASSERT_EQ(queue_pos_seek(pos, -2), 0, "Invalid seek should fail"); ASSERT_EQ(queue_pos_seek(pos, 10), 0, "Out of bounds seek should fail"); queue_pos_free(pos); queue_free(q); uasync_destroy(ua); TEST_PASS(); } /* Test: Position-based insert and remove operations */ static void test_position_insert_remove() { TEST_START("position_insert_remove"); struct UASYNC* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync"); struct ll_queue* q = queue_new(ua, NULL); ASSERT_NOT_NULL(q, "Failed to create queue"); // Create initial queue: [0, 1, 2, 3, 4] for (int i = 0; i < 5; i++) { struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); ASSERT_NOT_NULL(entry, "Failed to create entry"); struct test_data* data = (struct test_data*)ll_entry_data(entry); data->value = i; snprintf(data->name, sizeof(data->name), "item_%d", i); data->checksum = i * 7 + 3; ASSERT_EQ(queue_entry_put(q, entry), 0, "Failed to add entry"); } struct ll_queue_pos* pos = queue_pos_new(q); ASSERT_NOT_NULL(pos, "Failed to create position"); // Test insertion before position 2 ASSERT_EQ(queue_pos_seek(pos, 2), 1, "Failed to seek to position 2"); struct ll_entry* new_entry = queue_entry_new(sizeof(struct test_data)); ASSERT_NOT_NULL(new_entry, "Failed to create new entry"); struct test_data* new_data = (struct test_data*)ll_entry_data(new_entry); new_data->value = 99; snprintf(new_data->name, sizeof(new_data->name), "inserted_before_2"); new_data->checksum = 99 * 7 + 3; ASSERT_EQ(queue_pos_insert(pos, new_entry, 0), 0, "Failed to insert before position"); ASSERT_EQ(queue_entry_count(q), 6, "Wrong count after insertion"); // Verify insertion (refresh position first due to version change) queue_pos_refresh(pos); // Обновить позицию после изменения очереди ASSERT_EQ(queue_pos_seek(pos, 2), 1, "Failed to seek after insertion"); struct ll_entry* check_entry = queue_pos_current(pos); ASSERT_NOT_NULL(check_entry, "Current entry should not be NULL after insertion"); struct test_data* check_data = (struct test_data*)ll_entry_data(check_entry); ASSERT_TRUE(verify_test_data(check_data), "Data corruption after insertion"); ASSERT_EQ(check_data->value, 99, "Wrong value after insertion"); // Test insertion after position (refresh position first, then create new entry) queue_pos_refresh(pos); // Обновить позицию после предыдущей вставки struct ll_entry* new_entry2 = queue_entry_new(sizeof(struct test_data)); ASSERT_NOT_NULL(new_entry2, "Failed to create second new entry"); struct test_data* new_data2 = (struct test_data*)ll_entry_data(new_entry2); new_data2->value = 88; snprintf(new_data2->name, sizeof(new_data2->name), "inserted_after_2"); new_data2->checksum = 88 * 7 + 3; ASSERT_EQ(queue_pos_insert(pos, new_entry2, 1), 0, "Failed to insert after position"); ASSERT_EQ(queue_entry_count(q), 7, "Wrong count after second insertion"); // Test removal (refresh position first) queue_pos_refresh(pos); // Обновить позицию после вставки struct ll_entry* removed_entry = queue_pos_remove(pos); ASSERT_NOT_NULL(removed_entry, "Failed to remove entry"); ASSERT_EQ(queue_entry_count(q), 6, "Wrong count after removal"); struct test_data* removed_data = (struct test_data*)ll_entry_data(removed_entry); ASSERT_TRUE(verify_test_data(removed_data), "Data corruption in removed entry"); ASSERT_EQ(removed_data->value, 99, "Wrong value in removed entry"); queue_entry_free(removed_entry); // Test removal by pointer (find element with value 88 - the other inserted element) struct ll_entry* curr = q->head; int found = 0; while (curr) { struct test_data* data = (struct test_data*)ll_entry_data(curr); if (data->value == 88) { // Target the element that was inserted after position 2 ASSERT_EQ(queue_entry_remove(q, curr), 0, "Failed to remove by pointer"); queue_entry_free(curr); found = 1; break; } curr = curr->next; } ASSERT_TRUE(found, "Element with value 88 not found in queue after operations"); ASSERT_EQ(queue_entry_count(q), 5, "Wrong count after pointer removal"); queue_pos_free(pos); queue_free(q); uasync_destroy(ua); TEST_PASS(); } /* Test: Stress testing with random operations */ static void test_stress_random_operations() { TEST_START("stress_random_operations"); double start_time = get_time_ms(); struct UASYNC* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync"); struct ll_queue* q = queue_new(ua, NULL); ASSERT_NOT_NULL(q, "Failed to create queue"); const int iterations = 1000; const int max_queue_size = 50; srand(time(NULL)); for (int i = 0; i < iterations; i++) { int operation = rand() % 5; // 5 types of operations switch (operation) { case 0: { // Add to tail struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); if (entry) { struct test_data* data = (struct test_data*)ll_entry_data(entry); data->value = rand() % 1000; data->checksum = data->value * 7 + 3; queue_entry_put(q, entry); test_stats.operations_count++; } break; } case 1: { // Add to head struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); if (entry) { struct test_data* data = (struct test_data*)ll_entry_data(entry); data->value = rand() % 1000; data->checksum = data->value * 7 + 3; queue_entry_put_first(q, entry); test_stats.operations_count++; } break; } case 2: { // Remove from head struct ll_entry* entry = queue_entry_get(q); if (entry) { struct test_data* data = (struct test_data*)ll_entry_data(entry); if (!verify_test_data(data)) { test_stats.memory_errors++; } queue_entry_free(entry); test_stats.operations_count++; } break; } case 3: { // Position-based operations if (queue_entry_count(q) > 0) { struct ll_queue_pos* pos = queue_pos_new(q); if (pos) { int index = rand() % queue_entry_count(q); if (queue_pos_seek(pos, index)) { if (rand() % 2) { // Insert operation struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); if (entry) { struct test_data* data = (struct test_data*)ll_entry_data(entry); data->value = rand() % 1000; data->checksum = data->value * 7 + 3; queue_pos_insert(pos, entry, rand() % 2); test_stats.operations_count++; } } else { // Remove operation struct ll_entry* removed = queue_pos_remove(pos); if (removed) { struct test_data* data = (struct test_data*)ll_entry_data(removed); if (!verify_test_data(data)) { test_stats.memory_errors++; } queue_entry_free(removed); test_stats.operations_count++; } } } queue_pos_free(pos); } } break; } case 4: { // Random remove by pointer if (queue_entry_count(q) > 0) { // Find random element to remove int target_index = rand() % queue_entry_count(q); struct ll_entry* curr = q->head; for (int j = 0; j < target_index && curr; j++) { curr = curr->next; } if (curr) { struct test_data* data = (struct test_data*)ll_entry_data(curr); if (verify_test_data(data)) { queue_entry_remove(q, curr); queue_entry_free(curr); test_stats.operations_count++; } } } break; } } // Keep queue size reasonable while (queue_entry_count(q) > max_queue_size) { struct ll_entry* entry = queue_entry_get(q); if (entry) { struct test_data* data = (struct test_data*)ll_entry_data(entry); if (!verify_test_data(data)) { test_stats.memory_errors++; } queue_entry_free(entry); } } // Periodic integrity check if (i % 100 == 0) { int count = 0; struct ll_entry* curr = q->head; while (curr) { count++; // Verify doubly-linked integrity if (curr->prev) { if (curr->prev->next != curr) { test_stats.memory_errors++; } } if (curr->next) { if (curr->next->prev != curr) { test_stats.memory_errors++; } } curr = curr->next; } if (count != queue_entry_count(q)) { test_stats.memory_errors++; } } } double end_time = get_time_ms(); test_stats.total_time_ms += (end_time - start_time); ASSERT_EQ(test_stats.memory_errors, 0, "Memory corruption detected during stress test"); ASSERT_TRUE(test_stats.operations_count > iterations / 2, "Too few operations performed"); queue_free(q); uasync_destroy(ua); TEST_PASS(); } /* Test: API compatibility with existing code */ static void test_api_compatibility() { TEST_START("api_compatibility"); struct UASYNC* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync"); struct ll_queue* q = queue_new(ua, NULL); ASSERT_NOT_NULL(q, "Failed to create queue"); // Test FIFO operations (existing API) struct ll_entry* entries[5]; for (int i = 0; i < 5; i++) { entries[i] = queue_entry_new(sizeof(struct test_data)); ASSERT_NOT_NULL(entries[i], "Failed to create entry"); struct test_data* data = (struct test_data*)ll_entry_data(entries[i]); data->value = i; snprintf(data->name, sizeof(data->name), "fifo_%d", i); data->checksum = i * 7 + 3; } // Add to tail (FIFO) for (int i = 0; i < 5; i++) { ASSERT_EQ(queue_entry_put(q, entries[i]), 0, "Failed to add entry (FIFO)"); } ASSERT_EQ(queue_entry_count(q), 5, "Wrong count after FIFO adds"); // Extract from head (FIFO) for (int i = 0; i < 5; i++) { struct ll_entry* entry = queue_entry_get(q); ASSERT_NOT_NULL(entry, "Failed to get entry (FIFO)"); ASSERT_EQ(entry, entries[i], "Wrong order in FIFO extraction"); struct test_data* data = (struct test_data*)ll_entry_data(entry); ASSERT_TRUE(verify_test_data(data), "Data corruption in FIFO"); ASSERT_EQ(data->value, i, "Wrong value in FIFO extraction"); queue_entry_free(entry); } ASSERT_EQ(queue_entry_count(q), 0, "Queue should be empty after FIFO extraction"); // Test LIFO operations (existing API) for (int i = 0; i < 3; i++) { struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); ASSERT_NOT_NULL(entry, "Failed to create entry"); struct test_data* data = (struct test_data*)ll_entry_data(entry); data->value = i; data->checksum = i * 7 + 3; ASSERT_EQ(queue_entry_put_first(q, entry), 0, "Failed to add entry (LIFO)"); } ASSERT_EQ(queue_entry_count(q), 3, "Wrong count after LIFO adds"); // Extract from head (LIFO - should be reverse order) for (int i = 0; i < 3; i++) { struct ll_entry* entry = queue_entry_get(q); ASSERT_NOT_NULL(entry, "Failed to get entry (LIFO)"); struct test_data* data = (struct test_data*)ll_entry_data(entry); ASSERT_TRUE(verify_test_data(data), "Data corruption in LIFO"); ASSERT_EQ(data->value, 2 - i, "Wrong order in LIFO extraction"); queue_entry_free(entry); } ASSERT_EQ(queue_entry_count(q), 0, "Queue should be empty after LIFO extraction"); queue_free(q); uasync_destroy(ua); TEST_PASS(); } /* Test: Performance benchmarks */ static void test_performance_benchmarks() { TEST_START("performance_benchmarks"); struct UASYNC* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync"); struct ll_queue* q = queue_new(ua, NULL); ASSERT_NOT_NULL(q, "Failed to create queue"); const int benchmark_size = 10000; double start_time, end_time; // Benchmark: Sequential add operations start_time = get_time_ms(); for (int i = 0; i < benchmark_size; i++) { struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); if (entry) { struct test_data* data = (struct test_data*)ll_entry_data(entry); data->value = i; data->checksum = i * 7 + 3; queue_entry_put(q, entry); } } end_time = get_time_ms(); printf("\n Sequential add (%d ops): %.2f ms (%.2f ops/sec)", benchmark_size, end_time - start_time, benchmark_size * 1000.0 / (end_time - start_time)); // Benchmark: Sequential remove operations start_time = get_time_ms(); for (int i = 0; i < benchmark_size; i++) { struct ll_entry* entry = queue_entry_get(q); if (entry) { struct test_data* data = (struct test_data*)ll_entry_data(entry); if (!verify_test_data(data)) { test_stats.memory_errors++; } queue_entry_free(entry); } } end_time = get_time_ms(); printf("\n Sequential remove (%d ops): %.2f ms (%.2f ops/sec)", benchmark_size, end_time - start_time, benchmark_size * 1000.0 / (end_time - start_time)); // Benchmark: Position navigation // Rebuild queue for navigation benchmark for (int i = 0; i < benchmark_size / 10; i++) { struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); if (entry) { queue_entry_put(q, entry); } } struct ll_queue_pos* pos = queue_pos_new(q); ASSERT_NOT_NULL(pos, "Failed to create position for benchmark"); start_time = get_time_ms(); int navigation_ops = 0; for (int i = 0; i < benchmark_size / 10; i++) { // Forward and backward navigation while (queue_pos_next(pos)) navigation_ops++; while (queue_pos_prev(pos)) navigation_ops++; // Random seek operations int target = rand() % queue_entry_count(q); queue_pos_seek(pos, target); navigation_ops++; } end_time = get_time_ms(); printf("\n Position navigation (%d ops): %.2f ms (%.2f ops/sec)", navigation_ops, end_time - start_time, navigation_ops * 1000.0 / (end_time - start_time)); queue_pos_free(pos); queue_free(q); uasync_destroy(ua); TEST_PASS(); } /* Test: Edge cases and error conditions */ static void test_edge_cases() { TEST_START("edge_cases"); struct UASYNC* ua = uasync_create(); ASSERT_NOT_NULL(ua, "Failed to create uasync"); // Test NULL parameter handling ASSERT_NULL(queue_pos_new(NULL), "Should return NULL for NULL queue"); ASSERT_NULL(queue_entry_get(NULL), "Should return NULL for NULL queue"); ASSERT_EQ(queue_entry_put(NULL, NULL), -1, "Should fail on NULL parameters"); struct ll_queue* q = queue_new(ua, NULL); ASSERT_NOT_NULL(q, "Failed to create queue"); struct ll_queue_pos* pos = queue_pos_new(q); ASSERT_NOT_NULL(pos, "Failed to create position"); // Test operations on empty queue ASSERT_NULL(queue_entry_get(q), "Should return NULL from empty queue"); ASSERT_NULL(queue_pos_current(pos), "Should return NULL for empty queue"); ASSERT_EQ(queue_pos_seek(pos, 0), 0, "Seek should fail on empty queue"); // Test navigation on empty queue ASSERT_EQ(queue_pos_next(pos), 0, "Next should fail on empty queue"); ASSERT_EQ(queue_pos_prev(pos), 0, "Prev should fail on empty queue"); // Test single element queue struct ll_entry* entry = queue_entry_new(sizeof(struct test_data)); ASSERT_NOT_NULL(entry, "Failed to create entry"); ASSERT_EQ(queue_entry_put(q, entry), 0, "Failed to add single entry"); ASSERT_EQ(queue_entry_count(q), 1, "Wrong count for single entry"); // Test navigation with single element ASSERT_EQ(queue_pos_seek(pos, 0), 1, "Should seek to single element"); ASSERT_NOT_NULL(queue_pos_current(pos), "Should have current element"); ASSERT_EQ(queue_pos_next(pos), 0, "Next should fail at end"); ASSERT_EQ(queue_pos_seek(pos, 1), 0, "Should fail to seek beyond single element"); // Test removal of single element struct ll_entry* removed = queue_pos_remove(pos); ASSERT_NOT_NULL(removed, "Should remove single element"); ASSERT_EQ(queue_entry_count(q), 0, "Queue should be empty after removal"); queue_entry_free(removed); // Test size limit enforcement queue_set_size_limit(q, 2); struct ll_entry* e1 = queue_entry_new(sizeof(struct test_data)); struct ll_entry* e2 = queue_entry_new(sizeof(struct test_data)); struct ll_entry* e3 = queue_entry_new(sizeof(struct test_data)); ASSERT_NOT_NULL(e1, "Failed to create entry 1"); ASSERT_NOT_NULL(e2, "Failed to create entry 2"); ASSERT_NOT_NULL(e3, "Failed to create entry 3"); ASSERT_EQ(queue_entry_put(q, e1), 0, "Should add first entry"); ASSERT_EQ(queue_entry_put(q, e2), 0, "Should add second entry"); ASSERT_EQ(queue_entry_put(q, e3), -1, "Should reject third entry (size limit)"); ASSERT_EQ(queue_entry_count(q), 2, "Wrong count with size limit"); queue_entry_free(e3); // Free the rejected entry queue_pos_free(pos); queue_free(q); uasync_destroy(ua); TEST_PASS(); } /* Main test runner */ int main() { printf("=== Unified Comprehensive ll_queue Test Suite ===\n"); printf("Starting tests at %s\n", __TIME__); double suite_start_time = get_time_ms(); // Run all tests test_doubly_linked_basics(); test_position_navigation(); test_position_insert_remove(); test_stress_random_operations(); test_api_compatibility(); test_performance_benchmarks(); test_edge_cases(); double suite_end_time = get_time_ms(); double total_suite_time = suite_end_time - suite_start_time; printf("\n=== Test Suite Summary ===\n"); printf("Tests run: %d\n", test_stats.tests_run); printf("Tests passed: %d\n", test_stats.tests_passed); printf("Tests failed: %d\n", test_stats.tests_failed); printf("Memory errors: %d\n", test_stats.memory_errors); printf("Total operations: %d\n", test_stats.operations_count); printf("Total time: %.2f ms\n", total_suite_time); printf("Average ops/sec: %.2f\n", test_stats.operations_count * 1000.0 / total_suite_time); if (test_stats.tests_failed == 0 && test_stats.memory_errors == 0) { printf("\n✅ ALL TESTS PASSED - ll_queue module is working correctly!\n"); return 0; } else { printf("\n❌ TEST FAILURES DETECTED - Check output above for details\n"); return 1; } }