Added unit tests for Map data type and fixed other issues
This commit is contained in:
15
Makefile
15
Makefile
@@ -8,26 +8,29 @@ OBJ_DIR = obj
|
|||||||
TESTS_SRC = tests
|
TESTS_SRC = tests
|
||||||
|
|
||||||
TARGET = usage
|
TARGET = usage
|
||||||
TEST_TARGET = test_vector
|
TEST_V_TARGET = test_vector
|
||||||
|
TEST_M_TARGET = test_map
|
||||||
|
|
||||||
LIB_OBJS = $(OBJ_DIR)/vector.o $(OBJ_DIR)/map.o
|
LIB_OBJS = $(OBJ_DIR)/vector.o $(OBJ_DIR)/map.o
|
||||||
PROG_OBJS = $(OBJ_DIR)/usage.o
|
PROG_OBJS = $(OBJ_DIR)/usage.o
|
||||||
TESTS_OBJS = $(OBJ_DIR)/test_vector.o
|
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all: $(TARGET) $(TEST_TARGET)
|
all: $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET)
|
||||||
|
|
||||||
$(TARGET): $(PROG_OBJS) $(LIB_OBJS)
|
$(TARGET): $(PROG_OBJS) $(LIB_OBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
$(TEST_TARGET): $(TESTS_OBJS) $(OBJ_DIR)/vector.o
|
$(TEST_V_TARGET): $(OBJ_DIR)/test_vector.o $(OBJ_DIR)/vector.o
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
$(TEST_M_TARGET): $(OBJ_DIR)/test_map.o $(OBJ_DIR)/map.o
|
||||||
$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
|
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(OBJ_DIR)/%.o: %.c | $(OBJ_DIR)
|
$(OBJ_DIR)/usage.o: usage.c | $(OBJ_DIR)
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(OBJ_DIR)/%.o: $(TESTS_SRC)/%.c | $(OBJ_DIR)
|
$(OBJ_DIR)/%.o: $(TESTS_SRC)/%.c | $(OBJ_DIR)
|
||||||
@@ -37,4 +40,4 @@ $(OBJ_DIR):
|
|||||||
mkdir -p $(OBJ_DIR)
|
mkdir -p $(OBJ_DIR)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(OBJ_DIR) $(TARGET) $(TEST_TARGET)
|
rm -rf $(OBJ_DIR) $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET)
|
||||||
|
|||||||
340
tests/test_map.c
Normal file
340
tests/test_map.c
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
/*
|
||||||
|
* Unit tests for Map data type
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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/map.h"
|
||||||
|
|
||||||
|
// Create a new map
|
||||||
|
void test_map_new() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
assert(res.value.map != NULL);
|
||||||
|
assert(map_size(res.value.map) == 0);
|
||||||
|
assert(map_capacity(res.value.map) > 0);
|
||||||
|
|
||||||
|
map_destroy(res.value.map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add elements to map
|
||||||
|
void test_map_add() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
int x = 42, y = 84;
|
||||||
|
|
||||||
|
map_result_t x_res = map_add(map, "key1", &x);
|
||||||
|
assert(x_res.status == MAP_OK);
|
||||||
|
assert(map_size(map) == 1);
|
||||||
|
|
||||||
|
map_result_t y_res = map_add(map, "key2", &y);
|
||||||
|
assert(y_res.status == MAP_OK);
|
||||||
|
assert(map_size(map) == 2);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add multiple elements to the map
|
||||||
|
void test_map_add_multiple() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
const int x = 0xB00B5;
|
||||||
|
const char *y = "Hello";
|
||||||
|
|
||||||
|
map_result_t add_res = map_add(map, "x", (void*)&x);
|
||||||
|
assert(add_res.status == MAP_OK);
|
||||||
|
|
||||||
|
add_res = map_add(map, "y", (void*)y);
|
||||||
|
assert(add_res.status == MAP_OK);
|
||||||
|
|
||||||
|
assert(map_size(map) == 2);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get map element
|
||||||
|
void test_map_get() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
int val = 123;
|
||||||
|
map_add(map, "test", &val);
|
||||||
|
|
||||||
|
map_result_t get_res = map_get(map, "test");
|
||||||
|
assert(get_res.status == MAP_OK);
|
||||||
|
assert(*(int*)get_res.value.element == 123);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get non-existing key from map
|
||||||
|
void test_map_get_invalid() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
map_result_t get_res = map_get(map, "boom");
|
||||||
|
assert(get_res.status == MAP_ERR_NOT_FOUND);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map with heterogeneous types
|
||||||
|
void test_map_mixed() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
const int x = 0xB00B5;
|
||||||
|
const char *y = "Hello";
|
||||||
|
|
||||||
|
map_add(map, "x", (void*)&x);
|
||||||
|
map_add(map, "y", (void*)y);
|
||||||
|
|
||||||
|
map_result_t get_res = map_get(map, "x");
|
||||||
|
assert(get_res.status == MAP_OK);
|
||||||
|
|
||||||
|
const int *val_x = (const int*)get_res.value.element;
|
||||||
|
assert(*val_x == 0xB00B5);
|
||||||
|
|
||||||
|
get_res = map_get(map, "y");
|
||||||
|
assert(get_res.status == MAP_OK);
|
||||||
|
|
||||||
|
const char *val_y = (const char*)get_res.value.element;
|
||||||
|
assert(!strcmp(val_y, "Hello"));
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update existing map key
|
||||||
|
void test_map_update() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
const int x = 100, y = 200;
|
||||||
|
|
||||||
|
map_add(map, "key", (void*)&x);
|
||||||
|
|
||||||
|
map_result_t set_res = map_add(map, "key", (void*)&y);
|
||||||
|
assert(set_res.status == MAP_OK);
|
||||||
|
|
||||||
|
map_result_t get_res = map_get(map, "key");
|
||||||
|
const int *val = (const int*)get_res.value.element;
|
||||||
|
|
||||||
|
assert(*val == 200);
|
||||||
|
assert(map_size(map) == 1);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove an element from map
|
||||||
|
void test_map_remove() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
const int x = 10, y = 20;
|
||||||
|
|
||||||
|
map_add(map, "x", (void*)&x);
|
||||||
|
map_add(map, "y", (void*)&y);
|
||||||
|
|
||||||
|
assert(map_size(map) == 2);
|
||||||
|
|
||||||
|
map_result_t rm_res = map_remove(map, "x");
|
||||||
|
assert(rm_res.status == MAP_OK);
|
||||||
|
assert(map_size(map) == 1);
|
||||||
|
|
||||||
|
// Check whether the 'x' and 'y' keysx is still there
|
||||||
|
map_result_t get_res = map_get(map, "x");
|
||||||
|
assert(get_res.status != MAP_OK);
|
||||||
|
|
||||||
|
get_res = map_get(map, "y");
|
||||||
|
assert(get_res.status == MAP_OK);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove non-existing key from map
|
||||||
|
void test_map_remove_invalid() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
map_result_t rm_res = map_remove(map, "boom");
|
||||||
|
assert(rm_res.status != MAP_OK);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the map
|
||||||
|
void test_map_clear() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
int x = 10, y = 20, z = 30;
|
||||||
|
|
||||||
|
map_add(map, "x", (void*)&x);
|
||||||
|
map_add(map, "y", (void*)&y);
|
||||||
|
map_add(map, "z", (void*)&z);
|
||||||
|
|
||||||
|
assert(map_size(map) == 3);
|
||||||
|
|
||||||
|
map_result_t clear_res = map_clear(map);
|
||||||
|
assert(clear_res.status == MAP_OK);
|
||||||
|
assert(map_size(map) == 0);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear empty map
|
||||||
|
void test_map_clear_empty() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
map_result_t clear_res = map_clear(map);
|
||||||
|
assert(clear_res.status == MAP_OK);
|
||||||
|
assert(map_size(map) == 0);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple operations in sequence (add, update, delete and clear)
|
||||||
|
void test_map_sequence() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
const int x = 0xB00B5;
|
||||||
|
const char *y = "Hello";
|
||||||
|
|
||||||
|
// Add
|
||||||
|
map_add(map, "x", (void*)&x);
|
||||||
|
map_add(map, "y", (void*)&y);
|
||||||
|
|
||||||
|
assert(map_size(map) == 2);
|
||||||
|
|
||||||
|
// Update
|
||||||
|
const int new_x = 0xC0FFEE;
|
||||||
|
map_add(map, "x", (void*)&new_x);
|
||||||
|
|
||||||
|
map_result_t get_res = map_get(map, "x");
|
||||||
|
assert(*(const int*)get_res.value.element == 0xC0FFEE);
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
map_remove(map, "y");
|
||||||
|
assert(map_size(map) == 1);
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
map_clear(map);
|
||||||
|
assert(map_size(map) == 0);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test map with product data types
|
||||||
|
typedef struct {
|
||||||
|
char name[256];
|
||||||
|
char surname[256];
|
||||||
|
short age;
|
||||||
|
} Person;
|
||||||
|
|
||||||
|
void test_map_struct() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
Person bob = { "Bob", "Miller", 23 };
|
||||||
|
Person alice = { "Alice", "Davis", 21 };
|
||||||
|
|
||||||
|
map_add(map, "af94rt", &bob);
|
||||||
|
map_add(map, "b910o5", &alice);
|
||||||
|
|
||||||
|
map_result_t get_res = map_get(map, "af94rt");
|
||||||
|
assert(get_res.status == MAP_OK);
|
||||||
|
|
||||||
|
Person *retr = (Person*)get_res.value.element;
|
||||||
|
assert(!strcmp(retr->name, "Bob"));
|
||||||
|
assert(!strcmp(retr->surname, "Miller"));
|
||||||
|
assert(retr->age == 23);
|
||||||
|
|
||||||
|
get_res = map_get(map, "b910o5");
|
||||||
|
assert(get_res.status == MAP_OK);
|
||||||
|
|
||||||
|
retr = (Person*)get_res.value.element;
|
||||||
|
assert(!strcmp(retr->name, "Alice"));
|
||||||
|
assert(!strcmp(retr->surname, "Davis"));
|
||||||
|
assert(retr->age == 21);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test map capacity tracking
|
||||||
|
void test_map_cap() {
|
||||||
|
map_result_t res = map_new();
|
||||||
|
|
||||||
|
assert(res.status == MAP_OK);
|
||||||
|
map_t *map = res.value.map;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
char key[16];
|
||||||
|
snprintf(key, sizeof(key), "key%d", i);
|
||||||
|
map_add(map, key, &i);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(map_size(map) == 10);
|
||||||
|
assert(map_capacity(map) >= 10);
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("=== Running Map unit tests ===\n\n");
|
||||||
|
|
||||||
|
TEST(map_new);
|
||||||
|
TEST(map_add);
|
||||||
|
TEST(map_add_multiple);
|
||||||
|
TEST(map_get);
|
||||||
|
TEST(map_get_invalid);
|
||||||
|
TEST(map_mixed);
|
||||||
|
TEST(map_update);
|
||||||
|
TEST(map_remove);
|
||||||
|
TEST(map_remove_invalid);
|
||||||
|
TEST(map_clear);
|
||||||
|
TEST(map_clear_empty);
|
||||||
|
TEST(map_sequence);
|
||||||
|
TEST(map_struct);
|
||||||
|
TEST(map_cap);
|
||||||
|
|
||||||
|
printf("\n=== All tests passed! ===\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Unit tests for Vector
|
* Unit tests for Vector data type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define TEST(NAME) do { \
|
#define TEST(NAME) do { \
|
||||||
@@ -48,7 +48,7 @@ void test_vector_push() {
|
|||||||
|
|
||||||
vector_result_t y_res = vector_push(v, &y);
|
vector_result_t y_res = vector_push(v, &y);
|
||||||
assert(y_res.status == VECTOR_OK);
|
assert(y_res.status == VECTOR_OK);
|
||||||
assert(vector_size(v) == 1);
|
assert(vector_size(v) == 2);
|
||||||
|
|
||||||
vector_destroy(v);
|
vector_destroy(v);
|
||||||
}
|
}
|
||||||
@@ -274,6 +274,7 @@ int main(void) {
|
|||||||
|
|
||||||
TEST(vector_new);
|
TEST(vector_new);
|
||||||
TEST(vector_new_zcap);
|
TEST(vector_new_zcap);
|
||||||
|
TEST(vector_push);
|
||||||
TEST(vector_push_realloc);
|
TEST(vector_push_realloc);
|
||||||
TEST(vector_get);
|
TEST(vector_get);
|
||||||
TEST(vector_get_ofb);
|
TEST(vector_get_ofb);
|
||||||
|
|||||||
20
usage.c
20
usage.c
@@ -1,4 +1,20 @@
|
|||||||
#define SEP(SIZE) { for (size_t i = 0; i < SIZE; i++) { printf("="); }; puts("\n"); }
|
/*
|
||||||
|
* Sample usage of the Datum library.
|
||||||
|
*
|
||||||
|
* This program is a complete example on how to use Datum
|
||||||
|
* with *verbose* error checking. For a more minimal usage, you may want to ignore
|
||||||
|
* return messages/codes and get straight to the actual result. See the early
|
||||||
|
* part of the README.md file for such example (use it at your own risk).
|
||||||
|
*
|
||||||
|
* Developed by Marco Cetica (c) 2025, <email@marcocetica.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define SEP(SIZE) do { \
|
||||||
|
for (size_t i = 0; i < SIZE; i++) { \
|
||||||
|
printf("="); \
|
||||||
|
}; \
|
||||||
|
puts("\n"); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@@ -14,7 +30,7 @@ int main(void) {
|
|||||||
st = vector_usage();
|
st = vector_usage();
|
||||||
if (st) { return st; }
|
if (st) { return st; }
|
||||||
|
|
||||||
SEP(50)
|
SEP(50);
|
||||||
|
|
||||||
st = map_usage();
|
st = map_usage();
|
||||||
if (st) { return st; }
|
if (st) { return st; }
|
||||||
|
|||||||
Reference in New Issue
Block a user