diff --git a/trie/src/trie.c b/trie/src/trie.c index 7276e58..176d5a0 100644 --- a/trie/src/trie.c +++ b/trie/src/trie.c @@ -26,9 +26,17 @@ TrieExitCode trie_init(Trie **trie_ptr, const char *file_path) { // Allocate & initialize trie Trie *trie = calloc(1, sizeof(Trie)); trie->root = tnode_init(); - trie->file_path = strdup(file_path); pthread_rwlock_init(&trie->lock, NULL); + *trie_ptr = trie; + + if (file_path == NULL) { + trie->file_path = NULL; + return Ok; + } + + trie->file_path = strdup(file_path); + // Populate trie with data from file FILE *fp = fopen(file_path, "r"); @@ -75,8 +83,6 @@ TrieExitCode trie_init(Trie **trie_ptr, const char *file_path) { fclose(fp); - *trie_ptr = trie; - return Ok; } @@ -265,28 +271,30 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) { } TrieExitCode trie_add(Trie *trie, const char *key, Entry *entry) { - // Easiest way to make sure we don't add duplicate entries - // We use an internal function that doesn't require a read lock, as we're - // already inside a write lock - if (trie_search_node(trie, key).child != NULL) { - return AlreadyPresent; + if (trie->file_path != NULL) { + // Easiest way to make sure we don't add duplicate entries + // We use an internal function that doesn't require a read lock, as we're + // already inside a write lock + if (trie_search_node(trie, key).child != NULL) { + return AlreadyPresent; + } + + FILE *fp = fopen(trie->file_path, "a"); + + if (fp == NULL) { + return FileError; + } + + fputs(key, fp); + fputs(" ", fp); + fputc(entry_type_to_char(entry->type), fp); + fputs(" ", fp); + fputs(entry->string, fp); + fputs("\n", fp); + + fclose(fp); } - FILE *fp = fopen(trie->file_path, "a"); - - if (fp == NULL) { - return FileError; - } - - fputs(key, fp); - fputs(" ", fp); - fputc(entry_type_to_char(entry->type), fp); - fputs(" ", fp); - fputs(entry->string, fp); - fputs("\n", fp); - - fclose(fp); - // This function *should* always return Ok. Otherwise, the function would've // exited because the string was found in the trie. return trie_add_no_lock(trie, key, entry); diff --git a/trie/test/fuzzy.h b/trie/test/fuzzy.h index b9621be..00dc386 100644 --- a/trie/test/fuzzy.h +++ b/trie/test/fuzzy.h @@ -5,6 +5,7 @@ #include #include #include +#include "trie.h" typedef struct fuzzyconfig { int seed; @@ -74,7 +75,7 @@ char** init_string_matrix(int count, int len) { * @param size_func function to get the size of the given trie * @return exit code describing failures, if any */ -int fuzzy_test_trie_seed(FuzzyConfig conf, void* (*init_func) (), void (*free_func) (void*), bool (*add_func) (void*, char*, void*), bool (*remove_func) (void*, char*), size_t (*size_func) (void*)) { +int fuzzy_test_trie_seed(FuzzyConfig conf) { srand(conf.seed); char** matrix = init_string_matrix(conf.word_count, conf.word_length); @@ -100,9 +101,11 @@ int fuzzy_test_trie_seed(FuzzyConfig conf, void* (*init_func) (), void (*free_fu // also correct size_t size = 0; - void* ct = init_func(); + Trie *ct; + trie_init(&ct, NULL); bool changed; + TrieExitCode status; // 0: success // 1: invalid add @@ -113,13 +116,13 @@ int fuzzy_test_trie_seed(FuzzyConfig conf, void* (*init_func) (), void (*free_fu // Add all strings to trie, checking for duplicates for (int i = 0; i < conf.word_count; i++) { - changed = add_func(ct, matrix[i], NULL); + status = trie_add(ct, matrix[i], NULL); // if changed is false, *contains_dedupped[i] should be true, as changed // can only be false if the string is already contained in the trie. if // changed is true, *contains_dedupped[i] should be false, as the string // cannot be in the trie yet. - if (changed == *contains_dedupped[i]) { + if (status == Ok && *contains_dedupped[i]) { exit_code = 1; goto END; } @@ -131,8 +134,8 @@ int fuzzy_test_trie_seed(FuzzyConfig conf, void* (*init_func) (), void (*free_fu } // Ensure size is correct - if (size_func(ct) != size) { - printf("%i %i\n", size_func(ct), size); + if (trie_size(ct) != size) { + printf("%i %i\n", trie_size(ct), size); exit_code = 3; goto END; } @@ -160,7 +163,7 @@ int fuzzy_test_trie_seed(FuzzyConfig conf, void* (*init_func) (), void (*free_fu /* } */ END: - free_func(ct); + trie_free(ct); // Even testing functions should properly free memory free(contains); diff --git a/trie/test/test_trie.c b/trie/test/test_trie.c index e9217d9..7a7e8d3 100644 --- a/trie/test/test_trie.c +++ b/trie/test/test_trie.c @@ -5,64 +5,106 @@ #define TEST_SIZE(ct, size) \ TEST_CHECK(trie_size(ct) == size); \ TEST_MSG("Size: %zu", trie_size(ct)) - \ + +# define TRIE_INIT() \ + Trie *ct; \ + trie_init(&ct, NULL); \ + TEST_CHECK(ct != NULL) + void test_init() { - Trie* ct = trie_init(); - TEST_CHECK(ct != NULL); - TEST_SIZE(ct, 0); - trie_free(ct); + TRIE_INIT(); + TEST_SIZE(ct, 0); + trie_free(ct); } void test_add_one() { - Trie* ct = trie_init(); - TEST_CHECK(ct != NULL); + TRIE_INIT(); - Entry *entry = entry_new(Redirect, ""); - const char* string = "this is a test"; + Entry *entry = entry_new(Redirect, ""); + const char* string = "this is a test"; - TEST_CHECK(trie_add(ct, string, entry)); - TEST_CHECK(trie_search(ct, string) == entry); - TEST_SIZE(ct, 1); - trie_free(ct); + TEST_CHECK(trie_add(ct, string, entry) == Ok); + Entry *entry2; + TEST_CHECK(trie_search(ct, &entry2, string) == Ok); + TEST_CHECK(entry == entry2); + TEST_SIZE(ct, 1); + trie_free(ct); +} + +void test_add_prefix() { + TRIE_INIT(); + + const char *s1 = "halloween-2022"; + const char *s2 = "halloween-202"; + + Entry *entry1 = entry_new(Redirect, ""); + Entry *entry2 = entry_new(Redirect, ""); + + TEST_CHECK(trie_add(ct, s1, entry1) == Ok); + TEST_CHECK(trie_add(ct, s2, entry2) == Ok); + + Entry *entry3; + + TEST_CHECK(trie_search(ct, &entry3, s1) == Ok); + TEST_CHECK(entry3 == entry1); + entry2 = NULL; + + TEST_CHECK(trie_search(ct, &entry3, s2) == Ok); + TEST_CHECK(entry3 == entry2); + + trie_free(ct); } void test_search_not_present() { - Trie* ct = trie_init(); - TEST_CHECK(ct != NULL); + TRIE_INIT(); - TEST_CHECK(trie_add(ct, "this string exists", NULL)); - TEST_CHECK(trie_search(ct, "this string does not exist") == NULL); - trie_free(ct); + TEST_CHECK(trie_add(ct, "this string exists", NULL) == Ok); + Entry *entry; + TEST_CHECK(trie_search(ct, &entry, "this string does not exist") == NotFound); + + trie_free(ct); } void test_add_more() { - Trie* ct = trie_init(); - TEST_CHECK(ct != NULL); + TRIE_INIT(); - const char* one = "one"; - const char* two = "two"; - const char* twenty = "twenty"; - const char* twentytwo = "twentytwo"; - Entry *entry = entry_new(Redirect, ""); + const char* one = "one"; + const char* two = "two"; + const char* twenty = "twenty"; + const char* twentytwo = "twentytwo"; - TEST_CHECK(trie_add(ct, one, entry)); - TEST_CHECK(trie_add(ct, two, entry)); - TEST_CHECK(trie_add(ct, twenty, entry)); - TEST_CHECK(trie_add(ct, twentytwo, entry)); + Entry *entry = entry_new(Redirect, ""); - TEST_SIZE(ct, 4); + TEST_CHECK(trie_add(ct, one, entry) == Ok); + TEST_CHECK(trie_add(ct, two, entry) == Ok); + TEST_CHECK(trie_add(ct, twenty, entry) == Ok); + TEST_CHECK(trie_add(ct, twentytwo, entry) == Ok); - TEST_CHECK(trie_search(ct, one) == entry); - TEST_CHECK(trie_search(ct, two) == entry); - TEST_CHECK(trie_search(ct, twenty) == entry); - TEST_CHECK(trie_search(ct, twentytwo) == entry); + TEST_SIZE(ct, 4); - TEST_CHECK(!trie_add(ct, one, NULL)); - TEST_CHECK(!trie_add(ct, two, NULL)); - TEST_CHECK(!trie_add(ct, twenty, NULL)); - TEST_CHECK(!trie_add(ct, twentytwo, NULL)); + Entry *entry2; + TEST_CHECK(trie_search(ct, &entry2, one) == Ok); + TEST_CHECK(entry2 == entry); + entry2 = NULL; - trie_free(ct); + TEST_CHECK(trie_search(ct, &entry2, two) == Ok); + TEST_CHECK(entry2 == entry); + entry2 = NULL; + + TEST_CHECK(trie_search(ct, &entry2, twenty) == Ok); + TEST_CHECK(entry2 == entry); + entry2 = NULL; + + TEST_CHECK(trie_search(ct, &entry2, twentytwo) == Ok); + TEST_CHECK(entry2 == entry); + entry2 = NULL; + + TEST_CHECK(trie_add(ct, one, NULL) == AlreadyPresent); + TEST_CHECK(trie_add(ct, two, NULL) == AlreadyPresent); + TEST_CHECK(trie_add(ct, twenty, NULL) == AlreadyPresent); + TEST_CHECK(trie_add(ct, twentytwo, NULL) == AlreadyPresent); + + trie_free(ct); } /* void test_remove_one() { */ @@ -127,9 +169,7 @@ void test_fuzzy_set() { int res; for (int i = 0; i < count; i++) { -res = fuzzy_test_trie_seed(configs[i], trie_init, - trie_free, trie_add_no_lock, - NULL, trie_size); +res = fuzzy_test_trie_seed(configs[i]); TEST_CHECK_(res == 0, "Failed config, seed = %i, len = %i, count = %i, code=%i", configs[i].seed, configs[i].word_length, configs[i].word_count, res); } diff --git a/trie/test/test_trie_fuzzy.c b/trie/test/test_trie_fuzzy.c index 29b20d3..33a2e24 100644 --- a/trie/test/test_trie_fuzzy.c +++ b/trie/test/test_trie_fuzzy.c @@ -19,9 +19,7 @@ void test_fuzzy() { config.word_length = len; config.word_count = count; -res = fuzzy_test_trie_seed(config, trie_init, - trie_free, trie_add_no_lock, - NULL, trie_size); +res = fuzzy_test_trie_seed(config); TEST_CHECK_(res == 0, "Failed config, seed = %i, len = %i, count = %i, code = %i", config.seed, config.word_length, config.word_count, res); }