439 lines
11 KiB
C
439 lines
11 KiB
C
#include "dynamic_array.h"
|
||
#include "types.h"
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
// Подсчёт тестов
|
||
|
||
static int tests_passed = 0;
|
||
static int tests_failed = 0;
|
||
|
||
#define TEST(name) static bool name(void)
|
||
#define RUN(name) do { \
|
||
printf(" %-50s", #name); \
|
||
if (name()) { \
|
||
tests_passed++; \
|
||
printf(" [OK]\n"); \
|
||
} \
|
||
} while (0)
|
||
|
||
#define ASSERT(cond) do { \
|
||
if (!(cond)) { \
|
||
printf(" [FAIL] %s:%d: %s\n", __FILE__, __LINE__, #cond); \
|
||
tests_failed++; \
|
||
return false; \
|
||
} \
|
||
} while (0)
|
||
|
||
// --------------- ТЕСТЫ ---------------
|
||
// Создание и базовые операции
|
||
|
||
TEST(test_create_destroy) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
ASSERT(arr != NULL);
|
||
ASSERT(da_size(arr) == 0);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_push_back_double) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
const double vals[] = {1.1, 2.2, 3.3};
|
||
|
||
for (size_t i = 0; i < 3; i++) {
|
||
da_push_back(arr, &vals[i]);
|
||
}
|
||
ASSERT(da_size(arr) == 3);
|
||
ASSERT(*(double *)da_get(arr, 0) == 1.1);
|
||
ASSERT(*(double *)da_get(arr, 1) == 2.2);
|
||
ASSERT(*(double *)da_get(arr, 2) == 3.3);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_push_back_complex) {
|
||
DynamicArray *arr = da_create(get_complex_type(), 0);
|
||
const Complex vals[] = {
|
||
{1.1, 1}, {2.2, 2}, {3.3, 3}
|
||
};
|
||
|
||
for (size_t i = 0; i < 3; i++) {
|
||
da_push_back(arr, &vals[i]);
|
||
}
|
||
Complex *c_get;
|
||
ASSERT(da_size(arr) == 3);
|
||
|
||
c_get = (Complex *) da_get(arr, 0);
|
||
ASSERT(c_get->re == 1.1 && c_get->im == 1);
|
||
c_get = (Complex *) da_get(arr, 1);
|
||
ASSERT(c_get->re == 2.2 && c_get->im == 2);
|
||
c_get = (Complex *) da_get(arr, 2);
|
||
ASSERT(c_get->re == 3.3 && c_get->im == 3);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_set_get) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
const double v1 = 42, v2 = 99;
|
||
da_push_back(arr, &v1);
|
||
ASSERT(*(double *)da_get(arr, 0) == 42);
|
||
da_set(arr, 0, &v2);
|
||
ASSERT(*(double *)da_get(arr, 0) == 99);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_insert) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
const double a = 1, b = 2, c = 3, ins = 99;
|
||
da_push_back(arr, &a);
|
||
da_push_back(arr, &b);
|
||
da_push_back(arr, &c);
|
||
da_insert(arr, 1, &ins);
|
||
ASSERT(da_size(arr) == 4);
|
||
ASSERT(*(double *)da_get(arr, 0) == 1);
|
||
ASSERT(*(double *)da_get(arr, 1) == 99);
|
||
ASSERT(*(double *)da_get(arr, 2) == 2);
|
||
ASSERT(*(double *)da_get(arr, 3) == 3);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_remove) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
const double vals[] = {10, 20, 30};
|
||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||
da_remove(arr, 1);
|
||
ASSERT(da_size(arr) == 2);
|
||
ASSERT(*(double *)da_get(arr, 0) == 10);
|
||
ASSERT(*(double *)da_get(arr, 1) == 30);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
// Граничные случаи
|
||
|
||
TEST(test_get_out_of_bounds) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
ASSERT(da_get(arr, 0) == NULL);
|
||
const double v = 1;
|
||
da_push_back(arr, &v);
|
||
ASSERT(da_get(arr, 1) == NULL);
|
||
ASSERT(da_get(arr, 100) == NULL);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_remove_out_of_bounds) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
ASSERT(da_remove(arr, 0) == false);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_empty_array_operations) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
da_sort(arr); // Не должен ломаться
|
||
ASSERT(da_size(arr) == 0);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_create_null_type) {
|
||
DynamicArray *arr = da_create(NULL, 0);
|
||
ASSERT(arr == NULL);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_capacity_growth) {
|
||
DynamicArray *arr = da_create(get_int_type(), 2);
|
||
for (int i = 0; i < 100; i++)
|
||
ASSERT(da_push_back(arr, &i));
|
||
ASSERT(da_size(arr) >= 100);
|
||
for (int i = 0; i < 100; i++)
|
||
ASSERT(*(int *)da_get(arr, i) == i);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
// Сортировка
|
||
|
||
TEST(test_sort_double) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
const double vals[] = {3.14, 1.0, 2.71, 0.5};
|
||
for (int i = 0; i < 4; i++) da_push_back(arr, &vals[i]);
|
||
da_sort(arr);
|
||
for (size_t i = 1; i < da_size(arr); i++)
|
||
ASSERT(*(double *)da_get(arr, i - 1) <= *(double *)da_get(arr, i));
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_sort_complex) {
|
||
DynamicArray *arr = da_create(get_complex_type(), 0);
|
||
const Complex vals[] = {
|
||
{3, 4}, {1, 0}, {0, 2}
|
||
}; // |5|, |1|, |2|
|
||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||
da_sort(arr);
|
||
|
||
// Порядок по модулю: (1,0), (0,2), (3,4)
|
||
const Complex *c0 = da_get(arr, 0);
|
||
const Complex *c1 = da_get(arr, 1);
|
||
const Complex *c2 = da_get(arr, 2);
|
||
ASSERT(c0->re == 1.0 && c0->im == 0.0);
|
||
ASSERT(c1->re == 0.0 && c1->im == 2.0);
|
||
ASSERT(c2->re == 3.0 && c2->im == 4.0);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
// map
|
||
|
||
static void double_value(void *dest, const void *src) {
|
||
*(double *)dest = *(const double *)src * 2;
|
||
}
|
||
|
||
TEST(test_map_double) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
const double vals[] = {1.0, 2.0, 3.0};
|
||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||
DynamicArray *mapped = da_map(arr, double_value);
|
||
ASSERT(mapped != NULL);
|
||
ASSERT(da_size(mapped) == 3);
|
||
ASSERT(*(double *)da_get(mapped, 0) == 2.0);
|
||
ASSERT(*(double *)da_get(mapped, 1) == 4.0);
|
||
ASSERT(*(double *)da_get(mapped, 2) == 6.0);
|
||
da_destroy(arr);
|
||
da_destroy(mapped);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_map_empty) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
DynamicArray *mapped = da_map(arr, double_value);
|
||
ASSERT(mapped != NULL);
|
||
ASSERT(da_size(mapped) == 0);
|
||
da_destroy(arr);
|
||
da_destroy(mapped);
|
||
|
||
return true;
|
||
}
|
||
// where
|
||
|
||
static bool is_positive(const void *elem) {
|
||
return *(const double *)elem > 0;
|
||
}
|
||
|
||
static bool is_real(const void *elem) {
|
||
const Complex *c_elem = (Complex *)elem;
|
||
return c_elem->im == 0;
|
||
}
|
||
|
||
TEST(test_where_double) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
const double vals[] = {-1.0, 2.5, -3.0, 4.0};
|
||
for (int i = 0; i < 4; i++)
|
||
da_push_back(arr, &vals[i]);
|
||
DynamicArray *filtered = da_where(arr, is_positive);
|
||
ASSERT(da_size(filtered) == 2);
|
||
ASSERT(*(double *)da_get(filtered, 0) == 2.5);
|
||
ASSERT(*(double *)da_get(filtered, 1) == 4.0);
|
||
da_destroy(arr);
|
||
da_destroy(filtered);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_where_complex) {
|
||
DynamicArray *arr = da_create(get_complex_type(), 0);
|
||
const Complex vals[] = {
|
||
{1.0, 2.0}, {4.0, 0.0}, {-1.0, 1.0}
|
||
};
|
||
for (int i = 0; i < 3; i++)
|
||
da_push_back(arr, &vals[i]);
|
||
DynamicArray *filtered = da_where(arr, is_real);
|
||
ASSERT(da_size(filtered) == 1);
|
||
const Complex *num = da_get(filtered, 0);
|
||
ASSERT(num->re == 4.0 && num->im == 0.0);
|
||
da_destroy(arr);
|
||
da_destroy(filtered);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_where_none_match) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
const double vals[] = {-1.0, -3.0, -5.0};
|
||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||
DynamicArray *filtered = da_where(arr, is_positive);
|
||
ASSERT(da_size(filtered) == 0);
|
||
da_destroy(arr);
|
||
da_destroy(filtered);
|
||
|
||
return true;
|
||
}
|
||
// reduce
|
||
|
||
static void sum_reduce_double(void *acc, const void *elem) {
|
||
*(double *)acc += *(const double *)elem;
|
||
}
|
||
|
||
static void sum_reduce_complex(void *acc, const void *elem) {
|
||
Complex *c_acc = (Complex *)acc;
|
||
const Complex *c_elem = (const Complex *)elem;
|
||
|
||
c_acc->re += c_elem->re;
|
||
c_acc->im += c_elem->im;
|
||
}
|
||
|
||
TEST(test_reduce_sum_double) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
const double vals[] = {1.0, 2.0, 3.0, 4.0, 5.0};
|
||
for (int i = 0; i < 5; i++) da_push_back(arr, &vals[i]);
|
||
|
||
double initial = 0.0, result = 0.0;
|
||
da_reduce(arr, sum_reduce_double, &initial, &result);
|
||
ASSERT(result == 15.0);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_reduce_sum_complex) {
|
||
DynamicArray *arr = da_create(get_complex_type(), 0);
|
||
const Complex vals[] = {
|
||
{1.0, 0.0}, {2.0, 1.0}, {3.0, 2.0}
|
||
};
|
||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||
|
||
Complex initial = {0.0, 0.0}, result = {0.0, 0.0};
|
||
da_reduce(arr, sum_reduce_complex, &initial, &result);
|
||
|
||
ASSERT(result.re == 6.0 && result.im == 3.0);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_reduce_empty) {
|
||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||
double initial = 42.0, result = 0.0;
|
||
da_reduce(arr, sum_reduce_double, &initial, &result);
|
||
ASSERT(result == 42);
|
||
da_destroy(arr);
|
||
|
||
return true;
|
||
}
|
||
// Конкатенация
|
||
|
||
TEST(test_concat_double) {
|
||
DynamicArray *a = da_create(get_double_type(), 0);
|
||
DynamicArray *b = da_create(get_double_type(), 0);
|
||
const double v1 = 1.0, v2 = 2.0, v3 = 3.0, v4 = 4.0;
|
||
da_push_back(a, &v1);
|
||
da_push_back(a, &v2);
|
||
da_push_back(b, &v3);
|
||
da_push_back(b, &v4);
|
||
|
||
DynamicArray *c = da_concat(a, b);
|
||
|
||
ASSERT(c != NULL);
|
||
ASSERT(da_size(c) == 4);
|
||
ASSERT(*(double *)da_get(c, 0) == 1.0);
|
||
ASSERT(*(double *)da_get(c, 1) == 2.0);
|
||
ASSERT(*(double *)da_get(c, 2) == 3.0);
|
||
ASSERT(*(double *)da_get(c, 3) == 4.0);
|
||
|
||
da_destroy(a);
|
||
da_destroy(b);
|
||
da_destroy(c);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_concat_type_mismatch) {
|
||
DynamicArray *a = da_create(get_double_type(), 0);
|
||
DynamicArray *b = da_create(get_complex_type(), 0);
|
||
DynamicArray *c = da_concat(a, b);
|
||
ASSERT(c == NULL); // Несовпадение типов
|
||
da_destroy(a);
|
||
da_destroy(b);
|
||
|
||
return true;
|
||
}
|
||
|
||
TEST(test_concat_with_empty) {
|
||
DynamicArray *a = da_create(get_double_type(), 0);
|
||
DynamicArray *b = da_create(get_double_type(), 0);
|
||
const double v = 42.0;
|
||
da_push_back(a, &v);
|
||
DynamicArray *c = da_concat(a, b);
|
||
ASSERT(da_size(c) == 1);
|
||
ASSERT(*(double *)da_get(c, 0) == 42.0);
|
||
da_destroy(a);
|
||
da_destroy(b);
|
||
da_destroy(c);
|
||
|
||
return true;
|
||
}
|
||
|
||
int main() {
|
||
printf(" === Модульные тесты ===\n");
|
||
|
||
printf("--- Создание и базовые операции ---\n");
|
||
RUN(test_create_destroy);
|
||
RUN(test_push_back_double);
|
||
RUN(test_push_back_complex);
|
||
RUN(test_set_get);
|
||
RUN(test_insert);
|
||
RUN(test_remove);
|
||
|
||
printf("--- Граничные случаи ---\n");
|
||
RUN(test_get_out_of_bounds);
|
||
RUN(test_remove_out_of_bounds);
|
||
RUN(test_empty_array_operations);
|
||
RUN(test_create_null_type);
|
||
RUN(test_capacity_growth);
|
||
|
||
printf("--- Сортировка ---\n");
|
||
RUN(test_sort_double);
|
||
RUN(test_sort_complex);
|
||
|
||
printf("--- map ---\n");
|
||
RUN(test_map_double);
|
||
RUN(test_map_empty);
|
||
|
||
printf("--- where ---\n");
|
||
RUN(test_where_double);
|
||
RUN(test_where_complex);
|
||
RUN(test_where_none_match);
|
||
|
||
printf("--- reduce ---\n");
|
||
RUN(test_reduce_sum_double);
|
||
RUN(test_reduce_sum_complex);
|
||
RUN(test_reduce_empty);
|
||
|
||
printf("--- Конкатенация ---\n");
|
||
RUN(test_concat_double);
|
||
RUN(test_concat_type_mismatch);
|
||
RUN(test_concat_with_empty);
|
||
|
||
printf("\n======================\n");
|
||
printf("Итого: %d пройдено, %d провалено\n", tests_passed, tests_failed);
|
||
|
||
return tests_failed > 0 ? 1 : 0;
|
||
}
|