You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

752 lines
28 KiB

/**
* Unified comprehensive test suite for ll_queue module
* Combines: basic operations, position navigation, doubly-linked list, stress testing
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>
#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;
}
}