#include "test_queue.h" #include "queue.h" #include "test_utils.h" #include #include #include #include static void test_queue_basic() { Queue* q = queue_create(10, NULL); EXPECT_NOT_NULL(q); EXPECT_TRUE(queue_is_empty(q)); EXPECT_FALSE(queue_is_full(q)); int* vals[5]; for (int i = 0; i < 5; i++) { vals[i] = malloc(sizeof(int)); *vals[i] = (i + 1) * 10; queue_enqueue(q, vals[i]); } EXPECT_FALSE(queue_is_empty(q)); EXPECT_FALSE(queue_is_full(q)); EXPECT_EQ_INT(q->size, 5); int* v1 = (int*)queue_dequeue(q); EXPECT_NOT_NULL(v1); EXPECT_EQ_INT(*v1, 10); free(v1); int* v2 = (int*)queue_dequeue(q); EXPECT_NOT_NULL(v2); EXPECT_EQ_INT(*v2, 20); free(v2); EXPECT_EQ_INT(q->size, 3); int* vals2[3]; for (int i = 0; i < 3; i++) { vals2[i] = malloc(sizeof(int)); *vals2[i] = (i + 6) * 10; queue_enqueue(q, vals2[i]); } EXPECT_EQ_INT(q->size, 6); const int expected_vals[] = {30, 40, 50, 60, 70, 80}; for (int i = 0; i < 6; i++) { int* v = (int*)queue_dequeue(q); EXPECT_NOT_NULL(v); EXPECT_EQ_INT(*v, expected_vals[i]); free(v); } EXPECT_TRUE(queue_is_empty(q)); queue_destroy(q); } static void test_queue_resize() { Queue* q = queue_create(3, NULL); EXPECT_NOT_NULL(q); EXPECT_EQ_INT(q->capacity, 3); int a = 1, b = 2, c = 3, d = 4, e = 5; queue_enqueue(q, &a); queue_enqueue(q, &b); queue_enqueue(q, &c); EXPECT_TRUE(queue_is_full(q)); const int* v1 = (const int*)queue_dequeue(q); EXPECT_NOT_NULL(v1); EXPECT_EQ_INT(*v1, 1); // Now front = 1, rear = 0, size = 2 (wrapped state) queue_enqueue(q, &d); EXPECT_TRUE(queue_is_full(q)); // This enqueue triggers capacity doubling queue_enqueue(q, &e); EXPECT_FALSE(queue_is_full(q)); EXPECT_EQ_INT(q->capacity, 6); EXPECT_EQ_INT(q->size, 4); // Dequeue all and check order: B, C, D, E const int* v2 = (const int*)queue_dequeue(q); EXPECT_NOT_NULL(v2); EXPECT_EQ_INT(*v2, 2); const int* v3 = (const int*)queue_dequeue(q); EXPECT_NOT_NULL(v3); EXPECT_EQ_INT(*v3, 3); const int* v4 = (const int*)queue_dequeue(q); EXPECT_NOT_NULL(v4); EXPECT_EQ_INT(*v4, 4); const int* v5 = (const int*)queue_dequeue(q); EXPECT_NOT_NULL(v5); EXPECT_EQ_INT(*v5, 5); EXPECT_TRUE(queue_is_empty(q)); queue_destroy(q); } static int destroyer_calls = 0; static void my_destroyer(void* item) { destroyer_calls++; free(item); } static void test_queue_destroyer() { destroyer_calls = 0; Queue* q = queue_create(5, my_destroyer); EXPECT_NOT_NULL(q); for (int i = 0; i < 3; i++) { int* val = malloc(sizeof(int)); *val = i; queue_enqueue(q, val); } int* v = (int*)queue_dequeue(q); EXPECT_NOT_NULL(v); EXPECT_EQ_INT(*v, 0); free(v); queue_destroy(q); EXPECT_EQ_INT(destroyer_calls, 2); } typedef struct { Queue* q; mtx_t* mutex; cnd_t* cnd_empty; cnd_t* cnd_full; bool done; int sum; } ThreadContext; static int consumer_func(void* arg) { ThreadContext* ctx = (ThreadContext*)arg; while (true) { int* val = (int*)queue_dequeue_multithreaded(ctx->q, ctx->mutex, ctx->cnd_empty, ctx->cnd_full, &ctx->done); if (val == NULL) { break; } ctx->sum += *val; free(val); } return 0; } static void test_queue_multithreaded() { Queue* q = queue_create(2, NULL); mtx_t mutex; cnd_t cnd_empty; cnd_t cnd_full; mtx_init(&mutex, mtx_plain); cnd_init(&cnd_empty); cnd_init(&cnd_full); ThreadContext ctx = {.q = q, .mutex = &mutex, .cnd_empty = &cnd_empty, .cnd_full = &cnd_full, .done = false, .sum = 0}; thrd_t consumer; int res = thrd_create(&consumer, consumer_func, &ctx); EXPECT_EQ_INT(res, thrd_success); for (int i = 1; i <= 100; i++) { int* val = malloc(sizeof(int)); *val = i; queue_enqueue_multithreaded(q, val, &mutex, &cnd_empty, &cnd_full); } mtx_lock(&mutex); ctx.done = true; cnd_signal(&cnd_empty); mtx_unlock(&mutex); int join_res; thrd_join(consumer, &join_res); EXPECT_EQ_INT(ctx.sum, 5050); EXPECT_TRUE(queue_is_empty(q)); queue_destroy(q); mtx_destroy(&mutex); cnd_destroy(&cnd_empty); cnd_destroy(&cnd_full); } void test_queue() { test_queue_basic(); test_queue_resize(); test_queue_destroyer(); test_queue_multithreaded(); }