Files
FastSync/tests/test_queue.c
T
2026-06-10 16:58:35 +02:00

207 lines
4.2 KiB
C

#include "test_queue.h"
#include "queue.h"
#include "test_utils.h"
#include <stdlib.h>
#include <threads.h>
#include <stdbool.h>
#include <stdio.h>
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);
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));
int *v1 = (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
int *v2 = (int *)queue_dequeue(q);
EXPECT_NOT_NULL(v2);
EXPECT_EQ_INT(*v2, 2);
int *v3 = (int *)queue_dequeue(q);
EXPECT_NOT_NULL(v3);
EXPECT_EQ_INT(*v3, 3);
int *v4 = (int *)queue_dequeue(q);
EXPECT_NOT_NULL(v4);
EXPECT_EQ_INT(*v4, 4);
int *v5 = (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();
}