test: update tests to use new API
parent
50ebf86589
commit
a153c4e22d
|
@ -26,9 +26,17 @@ TrieExitCode trie_init(Trie **trie_ptr, const char *file_path) {
|
||||||
// Allocate & initialize trie
|
// Allocate & initialize trie
|
||||||
Trie *trie = calloc(1, sizeof(Trie));
|
Trie *trie = calloc(1, sizeof(Trie));
|
||||||
trie->root = tnode_init();
|
trie->root = tnode_init();
|
||||||
trie->file_path = strdup(file_path);
|
|
||||||
pthread_rwlock_init(&trie->lock, NULL);
|
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
|
// Populate trie with data from file
|
||||||
FILE *fp = fopen(file_path, "r");
|
FILE *fp = fopen(file_path, "r");
|
||||||
|
|
||||||
|
@ -75,8 +83,6 @@ TrieExitCode trie_init(Trie **trie_ptr, const char *file_path) {
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
*trie_ptr = trie;
|
|
||||||
|
|
||||||
return Ok;
|
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) {
|
TrieExitCode trie_add(Trie *trie, const char *key, Entry *entry) {
|
||||||
// Easiest way to make sure we don't add duplicate entries
|
if (trie->file_path != NULL) {
|
||||||
// We use an internal function that doesn't require a read lock, as we're
|
// Easiest way to make sure we don't add duplicate entries
|
||||||
// already inside a write lock
|
// We use an internal function that doesn't require a read lock, as we're
|
||||||
if (trie_search_node(trie, key).child != NULL) {
|
// already inside a write lock
|
||||||
return AlreadyPresent;
|
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
|
// This function *should* always return Ok. Otherwise, the function would've
|
||||||
// exited because the string was found in the trie.
|
// exited because the string was found in the trie.
|
||||||
return trie_add_no_lock(trie, key, entry);
|
return trie_add_no_lock(trie, key, entry);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "trie.h"
|
||||||
|
|
||||||
typedef struct fuzzyconfig {
|
typedef struct fuzzyconfig {
|
||||||
int seed;
|
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
|
* @param size_func function to get the size of the given trie
|
||||||
* @return exit code describing failures, if any
|
* @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);
|
srand(conf.seed);
|
||||||
|
|
||||||
char** matrix = init_string_matrix(conf.word_count, conf.word_length);
|
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
|
// also correct
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
||||||
void* ct = init_func();
|
Trie *ct;
|
||||||
|
trie_init(&ct, NULL);
|
||||||
|
|
||||||
bool changed;
|
bool changed;
|
||||||
|
TrieExitCode status;
|
||||||
|
|
||||||
// 0: success
|
// 0: success
|
||||||
// 1: invalid add
|
// 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
|
// Add all strings to trie, checking for duplicates
|
||||||
for (int i = 0; i < conf.word_count; i++) {
|
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
|
// 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
|
// 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
|
// changed is true, *contains_dedupped[i] should be false, as the string
|
||||||
// cannot be in the trie yet.
|
// cannot be in the trie yet.
|
||||||
if (changed == *contains_dedupped[i]) {
|
if (status == Ok && *contains_dedupped[i]) {
|
||||||
exit_code = 1;
|
exit_code = 1;
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
@ -131,8 +134,8 @@ int fuzzy_test_trie_seed(FuzzyConfig conf, void* (*init_func) (), void (*free_fu
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure size is correct
|
// Ensure size is correct
|
||||||
if (size_func(ct) != size) {
|
if (trie_size(ct) != size) {
|
||||||
printf("%i %i\n", size_func(ct), size);
|
printf("%i %i\n", trie_size(ct), size);
|
||||||
exit_code = 3;
|
exit_code = 3;
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +163,7 @@ int fuzzy_test_trie_seed(FuzzyConfig conf, void* (*init_func) (), void (*free_fu
|
||||||
/* } */
|
/* } */
|
||||||
|
|
||||||
END:
|
END:
|
||||||
free_func(ct);
|
trie_free(ct);
|
||||||
|
|
||||||
// Even testing functions should properly free memory
|
// Even testing functions should properly free memory
|
||||||
free(contains);
|
free(contains);
|
||||||
|
|
|
@ -5,64 +5,106 @@
|
||||||
#define TEST_SIZE(ct, size) \
|
#define TEST_SIZE(ct, size) \
|
||||||
TEST_CHECK(trie_size(ct) == size); \
|
TEST_CHECK(trie_size(ct) == size); \
|
||||||
TEST_MSG("Size: %zu", trie_size(ct))
|
TEST_MSG("Size: %zu", trie_size(ct))
|
||||||
\
|
|
||||||
|
# define TRIE_INIT() \
|
||||||
|
Trie *ct; \
|
||||||
|
trie_init(&ct, NULL); \
|
||||||
|
TEST_CHECK(ct != NULL)
|
||||||
|
|
||||||
void test_init() {
|
void test_init() {
|
||||||
Trie* ct = trie_init();
|
TRIE_INIT();
|
||||||
TEST_CHECK(ct != NULL);
|
TEST_SIZE(ct, 0);
|
||||||
TEST_SIZE(ct, 0);
|
trie_free(ct);
|
||||||
trie_free(ct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_add_one() {
|
void test_add_one() {
|
||||||
Trie* ct = trie_init();
|
TRIE_INIT();
|
||||||
TEST_CHECK(ct != NULL);
|
|
||||||
|
|
||||||
Entry *entry = entry_new(Redirect, "");
|
Entry *entry = entry_new(Redirect, "");
|
||||||
const char* string = "this is a test";
|
const char* string = "this is a test";
|
||||||
|
|
||||||
TEST_CHECK(trie_add(ct, string, entry));
|
TEST_CHECK(trie_add(ct, string, entry) == Ok);
|
||||||
TEST_CHECK(trie_search(ct, string) == entry);
|
Entry *entry2;
|
||||||
TEST_SIZE(ct, 1);
|
TEST_CHECK(trie_search(ct, &entry2, string) == Ok);
|
||||||
trie_free(ct);
|
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() {
|
void test_search_not_present() {
|
||||||
Trie* ct = trie_init();
|
TRIE_INIT();
|
||||||
TEST_CHECK(ct != NULL);
|
|
||||||
|
|
||||||
TEST_CHECK(trie_add(ct, "this string exists", NULL));
|
TEST_CHECK(trie_add(ct, "this string exists", NULL) == Ok);
|
||||||
TEST_CHECK(trie_search(ct, "this string does not exist") == NULL);
|
Entry *entry;
|
||||||
trie_free(ct);
|
TEST_CHECK(trie_search(ct, &entry, "this string does not exist") == NotFound);
|
||||||
|
|
||||||
|
trie_free(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_add_more() {
|
void test_add_more() {
|
||||||
Trie* ct = trie_init();
|
TRIE_INIT();
|
||||||
TEST_CHECK(ct != NULL);
|
|
||||||
|
|
||||||
const char* one = "one";
|
const char* one = "one";
|
||||||
const char* two = "two";
|
const char* two = "two";
|
||||||
const char* twenty = "twenty";
|
const char* twenty = "twenty";
|
||||||
const char* twentytwo = "twentytwo";
|
const char* twentytwo = "twentytwo";
|
||||||
Entry *entry = entry_new(Redirect, "");
|
|
||||||
|
|
||||||
TEST_CHECK(trie_add(ct, one, entry));
|
Entry *entry = entry_new(Redirect, "");
|
||||||
TEST_CHECK(trie_add(ct, two, entry));
|
|
||||||
TEST_CHECK(trie_add(ct, twenty, entry));
|
|
||||||
TEST_CHECK(trie_add(ct, twentytwo, entry));
|
|
||||||
|
|
||||||
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_SIZE(ct, 4);
|
||||||
TEST_CHECK(trie_search(ct, two) == entry);
|
|
||||||
TEST_CHECK(trie_search(ct, twenty) == entry);
|
|
||||||
TEST_CHECK(trie_search(ct, twentytwo) == entry);
|
|
||||||
|
|
||||||
TEST_CHECK(!trie_add(ct, one, NULL));
|
Entry *entry2;
|
||||||
TEST_CHECK(!trie_add(ct, two, NULL));
|
TEST_CHECK(trie_search(ct, &entry2, one) == Ok);
|
||||||
TEST_CHECK(!trie_add(ct, twenty, NULL));
|
TEST_CHECK(entry2 == entry);
|
||||||
TEST_CHECK(!trie_add(ct, twentytwo, NULL));
|
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() { */
|
/* void test_remove_one() { */
|
||||||
|
@ -127,9 +169,7 @@ void test_fuzzy_set() {
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
res = fuzzy_test_trie_seed(configs[i], trie_init,
|
res = fuzzy_test_trie_seed(configs[i]);
|
||||||
trie_free, trie_add_no_lock,
|
|
||||||
NULL, trie_size);
|
|
||||||
TEST_CHECK_(res == 0,
|
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);
|
"Failed config, seed = %i, len = %i, count = %i, code=%i", configs[i].seed, configs[i].word_length, configs[i].word_count, res);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,7 @@ void test_fuzzy() {
|
||||||
config.word_length = len;
|
config.word_length = len;
|
||||||
config.word_count = count;
|
config.word_count = count;
|
||||||
|
|
||||||
res = fuzzy_test_trie_seed(config, trie_init,
|
res = fuzzy_test_trie_seed(config);
|
||||||
trie_free, trie_add_no_lock,
|
|
||||||
NULL, trie_size);
|
|
||||||
TEST_CHECK_(res == 0,
|
TEST_CHECK_(res == 0,
|
||||||
"Failed config, seed = %i, len = %i, count = %i, code = %i", config.seed, config.word_length, config.word_count, res);
|
"Failed config, seed = %i, len = %i, count = %i, code = %i", config.seed, config.word_length, config.word_count, res);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue