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.
 
 
 
 
 
 

407 lines
14 KiB

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include "../lib/ll_queue.h"
#include "../lib/u_async.h"
// Тестовые данные
struct test_data {
int value;
char name[32];
};
// Простой контекст uasync для тестов
struct test_context {
struct UASYNC* ua;
int callback_count;
};
// Коллбэк для тестов
void test_callback(struct ll_queue* q, struct ll_entry* entry, void* arg) {
struct test_context* ctx = (struct test_context*)arg;
ctx->callback_count++;
printf("Callback called for entry %p\n", entry);
}
// Базовый тест двусвязного списка
void test_doubly_linked_basics() {
printf("=== Тест базовых операций двусвязного списка ===\n");
struct UASYNC* ua = uasync_create();
struct ll_queue* q = queue_new(ua, NULL);
assert(q != NULL);
assert(queue_entry_count(q) == 0);
// Создать и добавить несколько элементов
for (int i = 0; i < 5; i++) {
struct ll_entry* entry = queue_entry_new(sizeof(struct test_data));
assert(entry != NULL);
struct test_data* data = (struct test_data*)ll_entry_data(entry);
data->value = i;
snprintf(data->name, sizeof(data->name), "item_%d", i);
assert(queue_entry_put(q, entry) == 0);
}
assert(queue_entry_count(q) == 5);
// Проверить, что prev/next указатели корректны
struct ll_entry* curr = q->head;
int count = 0;
while (curr) {
struct test_data* data = (struct test_data*)ll_entry_data(curr);
printf(" Forward: %s (value=%d)\n", data->name, data->value);
// Проверить двусвязность
if (curr->prev) {
struct test_data* prev_data = (struct test_data*)ll_entry_data(curr->prev);
printf(" prev: %s\n", prev_data->name);
}
if (curr->next) {
struct test_data* next_data = (struct test_data*)ll_entry_data(curr->next);
printf(" next: %s\n", next_data->name);
}
curr = curr->next;
count++;
}
assert(count == 5);
// Проверить обратный проход
curr = q->tail;
count = 0;
while (curr) {
struct test_data* data = (struct test_data*)ll_entry_data(curr);
printf(" Backward: %s (value=%d)\n", data->name, data->value);
curr = curr->prev;
count++;
}
assert(count == 5);
queue_free(q);
uasync_destroy(ua);
printf("✓ Базовые операции двусвязного списка работают\n\n");
}
// Тест навигации по позициям
void test_position_navigation() {
printf("=== Тест навигации по позициям ===\n");
struct UASYNC* ua = uasync_create();
struct ll_queue* q = queue_new(ua, NULL);
// Добавить тестовые данные
for (int i = 0; i < 5; i++) {
struct ll_entry* entry = queue_entry_new(sizeof(struct test_data));
struct test_data* data = (struct test_data*)ll_entry_data(entry);
data->value = i;
snprintf(data->name, sizeof(data->name), "item_%d", i);
queue_entry_put(q, entry);
}
struct ll_queue_pos* pos = queue_pos_new(q);
assert(pos != NULL);
// Тест reset
queue_pos_reset(pos);
assert(queue_pos_index(pos) == -1);
assert(queue_pos_current(pos) == NULL);
// Тест next
int count = 0;
while (queue_pos_next(pos)) {
struct ll_entry* entry = queue_pos_current(pos);
struct test_data* data = (struct test_data*)ll_entry_data(entry);
printf(" Position %d: %s (value=%d)\n", queue_pos_index(pos), data->name, data->value);
assert(queue_pos_index(pos) == count);
assert(data->value == count);
count++;
}
assert(count == 5);
// Тест prev
int prev_count = 0;
while (queue_pos_prev(pos)) {
struct ll_entry* entry = queue_pos_current(pos);
if (entry) { // Проверить, что entry не NULL
struct test_data* data = (struct test_data*)ll_entry_data(entry);
printf(" Back Position %d: %s (value=%d)\n", queue_pos_index(pos), data->name, data->value);
} else {
printf(" Back Position %d: NULL (before head)\n", queue_pos_index(pos));
}
prev_count++;
}
assert(prev_count == 5);
// Тест seek
assert(queue_pos_seek(pos, 2) == 1);
assert(queue_pos_index(pos) == 2);
struct ll_entry* entry = queue_pos_current(pos);
struct test_data* data = (struct test_data*)ll_entry_data(entry);
assert(data->value == 2);
printf(" Seek to 2: %s (value=%d)\n", data->name, data->value);
queue_pos_free(pos);
queue_free(q);
uasync_destroy(ua);
printf("✓ Навигация по позициям работает\n\n");
}
// Тест вставки и удаления
void test_insert_remove_operations() {
printf("=== Тест вставки и удаления ===\n");
struct UASYNC* ua = uasync_create();
struct ll_queue* q = queue_new(ua, NULL);
// Создать начальную очередь: [0, 1, 2, 3, 4]
for (int i = 0; i < 5; i++) {
struct ll_entry* entry = queue_entry_new(sizeof(struct test_data));
struct test_data* data = (struct test_data*)ll_entry_data(entry);
data->value = i;
snprintf(data->name, sizeof(data->name), "item_%d", i);
queue_entry_put(q, entry);
}
struct ll_queue_pos* pos = queue_pos_new(q);
// Тест вставки перед элементом 2
queue_pos_seek(pos, 2);
struct ll_entry* new_entry = queue_entry_new(sizeof(struct test_data));
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");
assert(queue_pos_insert(pos, new_entry, 0) == 0); // Вставить перед
assert(queue_entry_count(q) == 6);
// Проверить вставку
queue_pos_seek(pos, 2);
struct ll_entry* check_entry = queue_pos_current(pos);
struct test_data* check_data = (struct test_data*)ll_entry_data(check_entry);
assert(check_data->value == 99);
printf(" Inserted before position 2: %s\n", check_data->name);
// Тест вставки после элемента 2 (теперь это вставленный элемент)
new_entry = queue_entry_new(sizeof(struct test_data));
new_data = (struct test_data*)ll_entry_data(new_entry);
new_data->value = 88;
snprintf(new_data->name, sizeof(new_data->name), "inserted_after_2");
assert(queue_pos_insert(pos, new_entry, 1) == 0); // Вставить после
assert(queue_entry_count(q) == 7);
// Проверить вставку
queue_pos_next(pos);
check_entry = queue_pos_current(pos);
check_data = (struct test_data*)ll_entry_data(check_entry);
assert(check_data->value == 88);
printf(" Inserted after position 2: %s\n", check_data->name);
// Тест удаления
queue_pos_seek(pos, 3); // Вернемся к вставленному элементу
struct ll_entry* removed_entry = queue_pos_remove(pos);
assert(removed_entry != NULL);
struct test_data* removed_data = (struct test_data*)ll_entry_data(removed_entry);
assert(removed_data->value == 88);
printf(" Removed element: %s\n", removed_data->name);
assert(queue_entry_count(q) == 6);
queue_entry_free(removed_entry);
// Тест удаления по указателю
// Найдем элемент с value = 99 и удалим его
struct ll_entry* curr = q->head;
while (curr) {
struct test_data* data = (struct test_data*)ll_entry_data(curr);
if (data->value == 99) {
assert(queue_entry_remove(q, curr) == 0);
queue_entry_free(curr);
break;
}
curr = curr->next;
}
assert(queue_entry_count(q) == 5);
printf(" Removed element by pointer: item_99\n");
queue_pos_free(pos);
queue_free(q);
uasync_destroy(ua);
printf("✓ Вставка и удаление работают\n\n");
}
// Стресс-тест
void test_stress() {
printf("=== Стресс-тест ===\n");
struct UASYNC* ua = uasync_create();
struct ll_queue* q = queue_new(ua, NULL);
const int iterations = 1000;
const int max_queue_size = 50;
srand(time(NULL));
for (int i = 0; i < iterations; i++) {
int operation = rand() % 4;
switch (operation) {
case 0: { // Добавить в конец
struct ll_entry* entry = queue_entry_new(sizeof(int));
int* value = (int*)ll_entry_data(entry);
*value = rand();
queue_entry_put(q, entry);
break;
}
case 1: { // Добавить в начало
struct ll_entry* entry = queue_entry_new(sizeof(int));
int* value = (int*)ll_entry_data(entry);
*value = rand();
queue_entry_put_first(q, entry);
break;
}
case 2: { // Удалить из начала
struct ll_entry* entry = queue_entry_get(q);
if (entry) {
queue_entry_free(entry);
}
break;
}
case 3: { // Произвольная операция с позицией
if (queue_entry_count(q) > 0) {
struct ll_queue_pos* pos = queue_pos_new(q);
int index = rand() % queue_entry_count(q);
if (queue_pos_seek(pos, index)) {
// Случайная операция: вставка или удаление
if (rand() % 2) {
struct ll_entry* entry = queue_entry_new(sizeof(int));
int* value = (int*)ll_entry_data(entry);
*value = rand();
queue_pos_insert(pos, entry, rand() % 2);
} else {
struct ll_entry* removed = queue_pos_remove(pos);
if (removed) {
queue_entry_free(removed);
}
}
}
queue_pos_free(pos);
}
break;
}
}
// Проверить размер очереди
if (queue_entry_count(q) > max_queue_size) {
// Удалить лишние элементы
while (queue_entry_count(q) > max_queue_size / 2) {
struct ll_entry* entry = queue_entry_get(q);
if (entry) {
queue_entry_free(entry);
}
}
}
// Периодическая проверка целостности
if (i % 100 == 0) {
int count = 0;
struct ll_entry* curr = q->head;
while (curr) {
count++;
// Проверить двусвязность
if (curr->prev) {
assert(curr->prev->next == curr);
}
if (curr->next) {
assert(curr->next->prev == curr);
}
curr = curr->next;
}
assert(count == queue_entry_count(q));
}
}
printf(" Прошло %d случайных операций\n", iterations);
printf(" Финальный размер очереди: %d\n", queue_entry_count(q));
queue_free(q);
uasync_destroy(ua);
printf("✓ Стресс-тест пройден\n\n");
}
// Тест совместимости существующего API
void test_api_compatibility() {
printf("=== Тест совместимости API ===\n");
struct UASYNC* ua = uasync_create();
struct ll_queue* q = queue_new(ua, NULL);
// Тест старого API
struct ll_entry* entries[5];
for (int i = 0; i < 5; i++) {
entries[i] = queue_entry_new(sizeof(struct test_data));
struct test_data* data = (struct test_data*)ll_entry_data(entries[i]);
data->value = i;
snprintf(data->name, sizeof(data->name), "compat_%d", i);
}
// Добавить в конец
for (int i = 0; i < 5; i++) {
assert(queue_entry_put(q, entries[i]) == 0);
}
assert(queue_entry_count(q) == 5);
// Извлечь из начала
for (int i = 0; i < 5; i++) {
struct ll_entry* entry = queue_entry_get(q);
assert(entry == entries[i]); // Проверить порядок FIFO
struct test_data* data = (struct test_data*)ll_entry_data(entry);
printf(" Extracted: %s (value=%d)\n", data->name, data->value);
assert(data->value == i);
queue_entry_free(entry);
}
assert(queue_entry_count(q) == 0);
// Тест put_first
for (int i = 0; i < 3; i++) {
struct ll_entry* entry = queue_entry_new(sizeof(int));
int* value = (int*)ll_entry_data(entry);
*value = i;
queue_entry_put_first(q, entry);
}
// Извлечь в обратном порядке (LIFO)
for (int i = 0; i < 3; i++) {
struct ll_entry* entry = queue_entry_get(q);
int* value = (int*)ll_entry_data(entry);
printf(" LIFO extracted: %d (expected %d)\n", *value, 2-i);
assert(*value == 2-i);
queue_entry_free(entry);
}
queue_free(q);
uasync_destroy(ua);
printf("✓ Совместимость API сохранена\n\n");
}
int main() {
printf("=== Запуск тестов doubly-linked ll_queue ===\n\n");
test_doubly_linked_basics();
test_position_navigation();
test_insert_remove_operations();
test_stress();
test_api_compatibility();
printf("=== Все тесты пройдены успешно! ===\n");
return 0;
}