#include #include #include #include #include #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; }