Added unit tests for Vector data type

This commit is contained in:
2025-11-05 11:52:21 +01:00
parent fafbd0bc51
commit e6a48e1c21
3 changed files with 311 additions and 3 deletions

View File

@@ -2,30 +2,39 @@ CC = gcc
CFLAGS = -Wall -Wextra -Werror -pedantic-errors -fstack-protector-strong \
-fsanitize=address -fsanitize=undefined -fstack-clash-protection \
-Wwrite-strings -std=c99
LDFLAGS = -fsanitize=address -fsanitize=undefined
SRC_DIR = src
OBJ_DIR = obj
TESTS_SRC = tests
TARGET = usage
TEST_TARGET = test_vector
LIB_OBJS = $(OBJ_DIR)/vector.o $(OBJ_DIR)/map.o
PROG_OBJS = $(OBJ_DIR)/usage.o
TESTS_OBJS = $(OBJ_DIR)/test_vector.o
.PHONY: all clean
all: $(TARGET)
all: $(TARGET) $(TEST_TARGET)
$(TARGET): $(PROG_OBJS) $(LIB_OBJS)
$(CC) $(CFLAGS) -o $@ $^
$(TEST_TARGET): $(TESTS_OBJS) $(OBJ_DIR)/vector.o
$(CC) $(CFLAGS) -o $@ $^
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CC) $(CFLAGS) -c -o $@ $<
$(OBJ_DIR)/%.o: %.c | $(OBJ_DIR)
$(CC) $(CFLAGS) -c -o $@ $<
$(OBJ_DIR)/%.o: $(TESTS_SRC)/%.c | $(OBJ_DIR)
$(CC) $(CFLAGS) -c -o $@ $<
$(OBJ_DIR):
mkdir -p $(OBJ_DIR)
clean:
rm -rf $(OBJ_DIR) $(TARGET)
rm -rf $(OBJ_DIR) $(TARGET) $(TEST_TARGET)

View File

@@ -20,6 +20,13 @@ static vector_result_t vector_resize(vector_t *vector);
vector_result_t vector_new(size_t size, size_t data_size) {
vector_result_t result = {0};
if (size == 0) {
result.status = VECTOR_ERR_ALLOCATE;
SET_MSG(result, "Invalid vector size");
return result;
}
// Allocate a new vector
vector_t *vector = malloc(sizeof(vector_t));
if (vector == NULL) {

292
tests/test_vector.c Normal file
View File

@@ -0,0 +1,292 @@
/*
* Unit tests for Vector
*/
#define TEST(NAME) do { \
printf("Running test_%s...", #NAME); \
test_##NAME(); \
printf(" PASSED\n"); \
} while(0)
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "../src/vector.h"
// Create a new vector
void test_vector_new() {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
assert(res.value.vector != NULL);
assert(vector_size(res.value.vector) == 0);
assert(vector_capacity(res.value.vector) == 5);
vector_destroy(res.value.vector);
}
// Create a vector with zero capacity
void test_vector_new_zcap() {
vector_result_t res = vector_new(0, sizeof(int));
assert(res.status == VECTOR_ERR_ALLOCATE);
}
// Push elements to vector
void test_vector_push() {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
int x = 42, y = 84;
vector_result_t x_res = vector_push(v, &x);
assert(x_res.status == VECTOR_OK);
assert(vector_size(v) == 1);
vector_result_t y_res = vector_push(v, &y);
assert(y_res.status == VECTOR_OK);
assert(vector_size(v) == 1);
vector_destroy(v);
}
// Trigger vector reallocation
void test_vector_push_realloc() {
vector_result_t res = vector_new(2, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
for (int i = 0; i < 5; i++) {
vector_result_t push_res = vector_push(v, &i);
assert(push_res.status == VECTOR_OK);
}
assert(vector_size(v) == 5);
assert(vector_capacity(v) >= 5);
vector_destroy(v);
}
// Get vector elements
void test_vector_get() {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
int val = 123;
vector_push(v, &val);
vector_result_t get_res = vector_get(v, 0);
assert(get_res.status == VECTOR_OK);
assert(*(int*)get_res.value.element == 123);
vector_destroy(v);
}
// Test out of bounds
void test_vector_get_ofb() {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
int val = 123;
vector_push(v, &val);
vector_result_t get_res = vector_get(v, 10);
assert(get_res.status != VECTOR_OK);
vector_destroy(v);
}
// Set vector element
void test_vector_set() {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
int x = 123, y = 999;
vector_push(v, &x);
vector_result_t set_res = vector_set(v, 0, &y);
assert(set_res.status == VECTOR_OK);
vector_result_t get_res = vector_get(v, 0);
assert(*(int*)get_res.value.element == 999);
vector_destroy(v);
}
// Set vector elemement out of bounds
void test_vector_set_ofb() {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
int x = 10, y = 999;
vector_push(v, &x);
vector_result_t set_res = vector_set(v, 10, &y);
assert(set_res.status != VECTOR_OK);
vector_destroy(v);
}
// Pop element from vector
void test_vector_pop() {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
int x = 10, y = 20;
vector_push(v, &x);
vector_push(v, &y);
assert(vector_size(v) == 2);
vector_result_t pop_res = vector_pop(v);
assert(pop_res.status == VECTOR_OK);
assert(*(int*)pop_res.value.element == 20);
assert(vector_size(v) == 1);
vector_destroy(v);
}
// Test pop element from empty vector
void test_vector_pop_empty() {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
vector_result_t pop_res = vector_pop(v);
assert(pop_res.status != VECTOR_OK);
vector_destroy(v);
}
// Clear vector
void test_vector_clear() {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
for (int i = 0; i < 5; i++) {
vector_push(v, &i);
}
assert(vector_size(v) == 5);
vector_result_t clear_res = vector_clear(v);
assert(clear_res.status == VECTOR_OK);
assert(vector_size(v) == 0);
// Capacity should be unchanged, this is by design!
assert(vector_capacity(v) == 5);
vector_destroy(v);
}
// Multiple operations in sequence (push, set, pop and clear)
void test_vector_sequence() {
vector_result_t res = vector_new(2, sizeof(int));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
// push
for (int i = 0; i < 5; i++) {
vector_push(v, &i);
}
// Set
int new_val = 0xBABE;
vector_set(v, 2, &new_val);
vector_result_t get_res = vector_get(v, 2);
assert(*(int*)get_res.value.element == 0xBABE);
// Pop
vector_pop(v);
assert(vector_size(v) == 4);
// Clear
vector_clear(v);
assert(vector_size(v) == 0);
vector_destroy(v);
}
// Vector with chars
void test_vector_char() {
vector_result_t res = vector_new(5, sizeof(char));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
char x = 'A', y = 'B', z = 'C';
vector_push(v, &x);
vector_push(v, &y);
vector_push(v, &z);
vector_result_t get_res = vector_get(v, 1);
assert(*(char *)get_res.value.element == 'B');
vector_destroy(v);
}
// Test vector with product data type
typedef struct {
int x;
int y;
} Point;
void test_vector_struct() {
vector_result_t res = vector_new(5, sizeof(Point));
assert(res.status == VECTOR_OK);
vector_t *v = res.value.vector;
Point p1 = {10, 20};
Point p2 = {30, 40};
vector_push(v, &p1);
vector_push(v, &p2);
vector_result_t get_res = vector_get(v, 0);
Point *retr = (Point*)get_res.value.element;
assert(retr->x == 10);
assert(retr->y == 20);
vector_destroy(v);
}
int main(void) {
printf("=== Running Vector unit tests ===\n\n");
TEST(vector_new);
TEST(vector_new_zcap);
TEST(vector_push_realloc);
TEST(vector_get);
TEST(vector_get_ofb);
TEST(vector_set);
TEST(vector_set_ofb);
TEST(vector_pop);
TEST(vector_pop_empty);
TEST(vector_clear);
TEST(vector_sequence);
TEST(vector_char);
TEST(vector_struct);
printf("\n=== All tests passed! ===\n");
return 0;
}