Skip to content

Instantly share code, notes, and snippets.

@SteffenBauer
Created August 31, 2020 15:44
Show Gist options
  • Save SteffenBauer/92cfa5cf03acb5d479346c7c0a13a02d to your computer and use it in GitHub Desktop.
Save SteffenBauer/92cfa5cf03acb5d479346c7c0a13a02d to your computer and use it in GitHub Desktop.
Basic key/value in C, including simple unit test system
/* A key/value dict system in C */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define TEST TRUE /* Do the unit tests */
typedef struct dict_t_struct {
char *key;
char *value;
struct dict_t_struct *next;
} dict_t;
static dict_t *config = NULL;
int configLen() {
int count = 0;
dict_t *ptr;
for (ptr = config; ptr != NULL; ptr = ptr->next)
count++;
return count;
}
void configAddItem(char *key, char *value) {
dict_t *ptr;
dict_t *new;
#ifdef DEBUG
printf("Adding key '%s' value '%s'\n", key, value);
#endif
for (ptr = config; ptr != NULL; ptr = ptr->next) {
if (strcmp(ptr->key, key) == 0) {
ptr->value = realloc(ptr->value, strlen(value)+1);
strcpy(ptr->value, value);
return;
}
}
new = malloc(sizeof(struct dict_t_struct));
new->key = malloc(strlen(key)+1);
new->value = malloc(strlen(value)+1);
strcpy(new->key, key);
strcpy(new->value, value);
new->next = config;
config = new;
return;
}
void configPrint() {
dict_t *ptr;
int count = 1;
if (config == NULL) printf("config is empty\n");
else printf("config entries:\n");
for (ptr = config; ptr != NULL; ptr = ptr->next) {
printf("-- Entry %d Key '%s' -> Value '%s' / Next '%s'\n", count++, ptr->key, ptr->value, ptr->next == NULL ? "NO":"YES");
}
}
void configDel() {
dict_t *ptr;
while (config != NULL) {
ptr = config;
config = config->next;
#ifdef DEBUG
printf("Cleanup entry key '%s' value '%s'\n", ptr->key, ptr->value);
#endif
free(ptr->key);
free(ptr->value);
free(ptr);
}
}
char *configGetItem(char *key) {
dict_t *ptr;
for (ptr = config; ptr != NULL; ptr = ptr->next) {
if (strcmp(ptr->key, key) == 0) {
return ptr->value;
}
}
return NULL;
}
void configDelItem(char *key) {
dict_t *ptr, *prev;
ptr = config;
prev = NULL;
while(ptr != NULL) {
if(strcmp(ptr->key, key) == 0) {
if (prev == NULL && ptr->next != NULL)
config = ptr->next;
else if (prev != NULL && ptr->next != NULL)
prev->next = ptr->next;
else if (prev == NULL && ptr->next == NULL)
config = NULL;
else
prev->next = NULL;
#ifdef DEBUG
printf("Remove key '%s' value '%s'\n", ptr->key, ptr->value);
#endif
free(ptr->key);
free(ptr->value);
free(ptr);
return;
}
prev = ptr;
ptr = ptr->next;
}
printf("Del: Key '%s' not in config\n", key);
}
#ifdef TEST
void test_setup() {
config = NULL;
}
void test_teardown() {
configDel();
}
void test_empty_len() {
assert(configLen() == 0);
}
void test_add_foo() {
configAddItem("foo", "bar");
assert(strcmp(configGetItem("foo"), "bar") == 0);
assert(configGetItem("bar") == NULL);
assert(configLen() == 1);
}
void test_add_foo_bar() {
configAddItem("foo", "bar");
configAddItem("bar", "foo");
assert(strcmp(configGetItem("foo"), "bar") == 0);
assert(strcmp(configGetItem("bar"), "foo") == 0);
assert(configLen() == 2);
}
void test_remove_top() {
configAddItem("foo", "bar");
configAddItem("bar", "foo");
configAddItem("barbar", "foo2");
assert(configLen() == 3);
configDelItem("barbar");
assert(configLen() == 2);
assert(strcmp(configGetItem("foo"), "bar") == 0);
assert(strcmp(configGetItem("bar"), "foo") == 0);
assert(configGetItem("barbar") == NULL);
}
void test_remove_mid() {
configAddItem("foo", "bar");
configAddItem("bar", "foo");
configAddItem("barbar", "foo2");
assert(configLen() == 3);
configDelItem("bar");
assert(configLen() == 2);
assert(strcmp(configGetItem("foo"), "bar") == 0);
assert(configGetItem("bar") == NULL);
assert(strcmp(configGetItem("barbar"), "foo2") == 0);
}
void test_remove_last() {
configAddItem("foo", "bar");
configAddItem("bar", "foo");
configAddItem("barbar", "foo2");
assert(configLen() == 3);
configDelItem("foo");
assert(configLen() == 2);
assert(configGetItem("foo") == NULL);
assert(strcmp(configGetItem("bar"), "foo") == 0);
assert(strcmp(configGetItem("barbar"), "foo2") == 0);
}
struct test_def {
void (*test)();
char *testname;
};
struct test_def tests[] = {
{test_empty_len, "Test empty dict length "},
{test_add_foo, "Test add one entry "},
{test_add_foo_bar, "Test add two entries "},
{test_remove_top, "Test remove from top of dict"},
{test_remove_mid, "Test remove from mid of dict"},
{test_remove_last, "Test remove last entry "},
{NULL, ""}
};
int main(int argc, char **argv) {
int test_count = 0;
while(tests[test_count].test != NULL) {
test_setup();
printf("Do test '%s' - ", tests[test_count].testname);
tests[test_count].test();
printf("[OK]\n");
test_teardown();
test_count++;
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment