Compare commits

..

4 Commits

Author SHA1 Message Date
789fbf7d4c test: Added push_back tests
All working
2026-04-16 10:42:01 -06:00
1e7e6f7b8d test: Added tests made for state consistency
Also changed a few things like usin asser_null and assert_non_null
--didn't knew they existed in cmocka, or at least forgot-- for better
clarity and readability.
2026-04-16 08:42:01 -06:00
7662af09f8 test: Added test for init and destroy
Also changed a few things like destroy tanking a double pointer so that
is more secure and making sure before hand that capacity is not that
ridiculous of a size, still, shit can get pass but generally is fine
2026-04-15 17:17:54 -06:00
1d7f9676ec addition: resize and reserve, not tested 2026-04-15 10:01:27 -06:00
3 changed files with 392 additions and 34 deletions

View File

@@ -16,13 +16,15 @@ typedef enum {
ARRLIST_OK = 0,
ARRLIST_OUT_OF_BOUNDS,
ARRLIST_BAD_ALLOC,
ARRLIST_ALLOC_OVERFLOW,
ARRLIST_EMPTY,
ARRLIST_NULL_ARG,
ARRLIST_INVALID_ELEM_SIZE,
ARRLIST_INVALID_CAPACITY,
} ArrayListErr;
ArrayList *arraylist_init(size_t capacity, size_t elem_size);
ArrayListErr arraylist_destroy(ArrayList *arr);
ArrayListErr arraylist_destroy(ArrayList **arr);
ArrayListErr arraylist_clear(ArrayList *arr);
size_t arraylist_size(const ArrayList *arr);

View File

@@ -26,6 +26,10 @@ ArrayList *arraylist_init(size_t capacity, size_t elem_size) {
return NULL;
}
if (capacity > SIZE_MAX / elem_size) {
return NULL;
}
ArrayList *arr = malloc(sizeof(ArrayList));
if (arr == NULL) {
return NULL;
@@ -42,17 +46,16 @@ ArrayList *arraylist_init(size_t capacity, size_t elem_size) {
return arr;
}
ArrayListErr arraylist_destroy(ArrayList *arr) {
if (arr == NULL) {
ArrayListErr arraylist_destroy(ArrayList **arr) {
if (arr == NULL || *arr == NULL) {
return ARRLIST_NULL_ARG;
}
arr->capacity = 0;
arr->elem_size = 0;
arr->len = 0;
free(arr->buffer);
arr->buffer = NULL;
free(arr);
// No problem on using free on NULL :)
free((*arr)->buffer);
free(*arr);
*arr = NULL;
return ARRLIST_OK;
}
@@ -86,7 +89,7 @@ bool arraylist_is_empty(const ArrayList *arr) {
if (arr == NULL) {
return true;
}
return arr->capacity == 0;
return arr->len == 0;
}
static ArrayListErr arraylist_grow(ArrayList *arr) {
@@ -94,10 +97,16 @@ static ArrayListErr arraylist_grow(ArrayList *arr) {
// and only used by funtions that already verified
// arr is not null, same with shrink.
size_t new_capacity = arr->capacity * 2;
if (new_capacity > SIZE_MAX / arr->elem_size) {
return ARRLIST_ALLOC_OVERFLOW;
}
void *tmp = realloc(arr->buffer, new_capacity * arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->capacity = new_capacity;
arr->buffer = tmp;
return ARRLIST_OK;
@@ -105,10 +114,16 @@ static ArrayListErr arraylist_grow(ArrayList *arr) {
static ArrayListErr arraylist_shrink(ArrayList *arr) {
size_t new_capacity = arr->capacity / 2;
if (new_capacity > SIZE_MAX / arr->elem_size) {
return ARRLIST_ALLOC_OVERFLOW;
}
void *tmp = realloc(arr->buffer, new_capacity *arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->capacity = new_capacity;
arr->buffer = tmp;
return ARRLIST_OK;
@@ -127,7 +142,7 @@ ArrayListErr arraylist_push_back(ArrayList *arr, void *data) {
}
}
memcpy(arr->buffer, data, arr->elem_size);
memcpy(arr->buffer + (arr->len * arr->elem_size), data, arr->elem_size);
arr->len++;
return ARRLIST_OK;
}
@@ -146,14 +161,17 @@ ArrayListErr arraylist_push_front(ArrayList *arr, void *data) {
}
// No problem if array is full because it grows if it's full
for (size_t i = arr->len - 1; i >= 0; i--) {
memcpy(
arr->buffer + ((i + 1) * arr->elem_size),
arr->buffer + (i * arr->elem_size),
arr->elem_size);
}
memmove(
arr->buffer,
arr->buffer + arr->elem_size,
(arr->len - 1) * arr->elem_size
);
memcpy(
arr->buffer,
data,
arr->elem_size);
memcpy(arr->buffer, data, arr->elem_size);
arr->len++;
return ARRLIST_OK;
@@ -164,7 +182,7 @@ ArrayListErr arraylist_insert(ArrayList *arr, size_t index, void *data) {
return ARRLIST_NULL_ARG;
}
if (index >= arr->len) {
if (index > arr->len) {
return ARRLIST_OUT_OF_BOUNDS;
}
@@ -175,14 +193,15 @@ ArrayListErr arraylist_insert(ArrayList *arr, size_t index, void *data) {
}
}
for (size_t i = arr->len - 1; i >= index; i--) {
memcpy(
arr->buffer + ((i + 1) * arr->elem_size),
arr->buffer + (i * arr->elem_size),
arr->elem_size);
}
memmove(
arr->buffer + ((index + 1) * arr->elem_size),
arr->buffer + (index * arr->elem_size),
(arr->len - index) * arr->elem_size);
memcpy(arr->buffer + (index * arr->elem_size),
data,
arr->elem_size);
memcpy(arr->buffer + (index * arr->elem_size), data, arr->elem_size);
arr->len++;
return ARRLIST_OK;
@@ -240,12 +259,10 @@ ArrayListErr arraylist_pop_front(ArrayList *arr, void *out) {
);
}
for (size_t i = 0; i < arr->len; i++) {
memcpy(
arr->buffer + (i * arr->elem_size),
arr->buffer + ((i + 1) * arr->elem_size),
arr->elem_size);
}
memmove(
arr->buffer + arr->elem_size,
arr->buffer,
(arr->len - 1) * arr->elem_size);
arr->len--;
@@ -319,3 +336,52 @@ ArrayListErr arraylist_set(ArrayList *arr, size_t index, void *data) {
return ARRLIST_OK;
}
ArrayListErr arraylist_resize(ArrayList *arr, size_t new_capacity) {
if (arr == NULL) {
return ARRLIST_NULL_ARG;
}
if (new_capacity < 1) {
return ARRLIST_INVALID_CAPACITY;
}
if (new_capacity > SIZE_MAX / arr->elem_size) {
return ARRLIST_ALLOC_OVERFLOW;
}
uint8_t *tmp = realloc(arr->buffer, new_capacity * arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->buffer = tmp;
arr->capacity = new_capacity;
return ARRLIST_OK;
}
ArrayListErr arraylist_reserve(ArrayList *arr, size_t size_to_reserve) {
if (arr == NULL) {
return ARRLIST_NULL_ARG;
}
if (size_to_reserve < 1) {
return ARRLIST_INVALID_CAPACITY;
}
if (arr->capacity + size_to_reserve > SIZE_MAX / arr->elem_size) {
return ARRLIST_ALLOC_OVERFLOW;
}
uint8_t *tmp = realloc(
arr->buffer,
(arr->capacity + size_to_reserve) * arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->buffer = tmp;
arr->capacity += size_to_reserve;
return ARRLIST_OK;
}

View File

@@ -1,5 +1,295 @@
#include <stdlib.h>
#include <stdalign.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <cmocka.h>
#include <string.h>
#include "arraylist.h"
// INIT
static void test_init_valid_parameters(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_non_null(arr);
arraylist_destroy(&arr);
}
static void test_init_zero_capacity(void **state) {
(void) state;
ArrayList *arr = arraylist_init(0, sizeof(int));
assert_null(arr);
arraylist_destroy(&arr);
}
static void test_init_zero_elem_size(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, 0);
assert_null(arr);
arraylist_destroy(&arr);
}
static void test_init_large_capacity(void **state) {
(void) state;
ArrayList *arr = arraylist_init(SIZE_MAX, sizeof(int));
assert_null(arr);
arraylist_destroy(&arr);
}
// DESTROY
static void test_destroy_valid_array(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_non_null(arr);
arraylist_destroy(&arr);
assert_null(arr);
}
static void test_destroy_null_array(void **state) {
(void) state;
ArrayList *arr = NULL;
ArrayListErr err = arraylist_destroy(&arr);
assert_null(arr);
assert_uint_equal(err, ARRLIST_NULL_ARG);
}
static void test_destroy_double(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_non_null(arr);
ArrayListErr err = arraylist_destroy(&arr);
assert_uint_equal(err, ARRLIST_OK);
assert_null(arr);
err = arraylist_destroy(&arr);
assert_uint_equal(err, ARRLIST_NULL_ARG);
assert_null(arr);
}
// State
static void test_capacity_after_init(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_non_null(arr);
assert_uint_equal(arraylist_capacity(arr), 64);
arraylist_destroy(&arr);
}
static void test_is_empty_after_init(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_non_null(arr);
assert_true(arraylist_is_empty(arr));
arraylist_destroy(&arr);
}
static void test_is_empty_after_push(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_non_null(arr);
int n = 8;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_false(arraylist_is_empty(arr));
arraylist_destroy(&arr);
}
static void test_size_after_many_push(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_non_null(arr);
int n = 8;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 1);
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 2);
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 3);
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 4);
arraylist_destroy(&arr);
}
static void test_capacity_growth_on_push(void **state) {
(void) state;
ArrayList *arr = arraylist_init(2, sizeof(int));
assert_non_null(arr);
int n = 8;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_capacity(arr), 2);
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_capacity(arr), 2);
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_capacity(arr), 4);
arraylist_destroy(&arr);
}
static void test_capacity_shrink_on_pop(void **state) {
(void) state;
ArrayList *arr = arraylist_init(8, sizeof(int));
assert_non_null(arr);
int n = 8;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_pop_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_capacity(arr), 4);
arraylist_destroy(&arr);
}
// push_back
static void test_push_back_single_element(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_non_null(arr);
int n = 8;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 1);
int b;
assert_uint_equal(arraylist_get(arr, 0, &b), ARRLIST_OK);
assert_int_equal(b, 8);
arraylist_destroy(&arr);
}
static void test_push_back_multiple_elements(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_non_null(arr);
int n = 8;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 1);
n = 9;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 2);
n = 10;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 3);
n = 11;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 4);
n = 12;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_OK);
assert_uint_equal(arraylist_size(arr), 5);
int b;
assert_uint_equal(arraylist_get(arr, 0, &b), ARRLIST_OK);
assert_int_equal(b, 8);
assert_uint_equal(arraylist_get(arr, 1, &b), ARRLIST_OK);
assert_int_equal(b, 9);
assert_uint_equal(arraylist_get(arr, 2, &b), ARRLIST_OK);
assert_int_equal(b, 10);
assert_uint_equal(arraylist_get(arr, 3, &b), ARRLIST_OK);
assert_int_equal(b, 11);
assert_uint_equal(arraylist_get(arr, 4, &b), ARRLIST_OK);
assert_int_equal(b, 12);
arraylist_destroy(&arr);
}
static void test_push_back_null_array(void **state) {
(void) state;
ArrayList *arr = NULL;
int n = 8;
assert_uint_equal(arraylist_push_back(arr, &n), ARRLIST_NULL_ARG);
}
static void test_push_back_null_data(void **state) {
(void) state;
ArrayList *arr = arraylist_init(64, sizeof(int));
assert_uint_equal(arraylist_push_back(arr, NULL), ARRLIST_NULL_ARG);
arraylist_destroy(&arr);
}
int main(void) {
return EXIT_SUCCESS;
const struct CMUnitTest init[] = {
cmocka_unit_test(test_init_valid_parameters),
cmocka_unit_test(test_init_zero_capacity),
cmocka_unit_test(test_init_zero_elem_size),
cmocka_unit_test(test_init_large_capacity),
};
const struct CMUnitTest destroy[] = {
cmocka_unit_test(test_destroy_valid_array),
cmocka_unit_test(test_destroy_null_array),
cmocka_unit_test(test_destroy_double),
};
const struct CMUnitTest state[] = {
cmocka_unit_test(test_capacity_after_init),
cmocka_unit_test(test_is_empty_after_init),
cmocka_unit_test(test_is_empty_after_push),
cmocka_unit_test(test_size_after_many_push),
cmocka_unit_test(test_capacity_growth_on_push),
cmocka_unit_test(test_capacity_shrink_on_pop),
};
const struct CMUnitTest push_back[] = {
cmocka_unit_test(test_push_back_single_element),
cmocka_unit_test(test_push_back_multiple_elements),
cmocka_unit_test(test_push_back_null_array),
cmocka_unit_test(test_push_back_null_data),
};
int rc = 0;
rc += cmocka_run_group_tests(init, NULL, NULL);
rc += cmocka_run_group_tests(destroy, NULL, NULL);
rc += cmocka_run_group_tests(state, NULL, NULL);
rc += cmocka_run_group_tests(push_back, NULL, NULL);
return rc;
}