diff options
| -rw-r--r-- | include/moslib/ds/hashmap.h | 31 | ||||
| -rw-r--r-- | include/moslib/tester.h | 21 | ||||
| -rw-r--r-- | src/ds/hashmap.c | 82 | ||||
| -rw-r--r-- | tests/ds/array_tests.c | 12 | ||||
| -rw-r--r-- | tests/ds/hashmap_tests.c | 46 | ||||
| -rw-r--r-- | tests/safe_tests.c | 26 | ||||
| -rw-r--r-- | tests/string_tests.c | 20 |
7 files changed, 167 insertions, 71 deletions
diff --git a/include/moslib/ds/hashmap.h b/include/moslib/ds/hashmap.h index 3c50287..4136ac2 100644 --- a/include/moslib/ds/hashmap.h +++ b/include/moslib/ds/hashmap.h @@ -83,6 +83,14 @@ // // ---------------------------------------------------------------------------------------------------- // +// To delete an an entry from a hashmap use: +// +// int deleted = hm_del(hm, key); +// +// It will return 1 if entry of such key existed and was deleted, 0 otherwise. +// +// ---------------------------------------------------------------------------------------------------- +// // You can loop over the hashmap using these functions: // // struct Entry *first = hm_first(hm); @@ -130,6 +138,7 @@ #define hm_put_e mos_hm_put_e #define hm_get mos_hm_get #define hm_get_e mos_hm_get_e +#define hm_del mos_hm_del #define hm_first mos_hm_first #define hm_next mos_hm_next #define hm_size mos_hm_size @@ -221,6 +230,19 @@ typedef struct { // pointer to the entry or NULL if no entry with such key exists #define mos_hm_get_e(hm, k) (mos_hm_ini, (hm)->key = k, mos_hm_get_e_fn(hm, mos_hm_fn_args)) +// Delete an entry with specific key from the hashmap +// +// Arguments: +// hm +// hashmap to delete from +// +// k +// key of the entry to delete +// +// Returns: +// 1 if an entry of given key was deleted, 0 otherwise +#define mos_hm_del(hm, k) (mos_hm_ini, (hm)->key = k, mos_hm_del_fn(hm, mos_hm_fn_args)) + // Get a pointer to the first entry in the hashmap // // Arguments: @@ -250,7 +272,7 @@ typedef struct { // Arguments: // hm // hashmap to get the count of entries from -extern size_t mos_hm_size(void *hm); +extern size_t mos_hm_size(const void *hm); // Free the hashmap // @@ -268,8 +290,9 @@ extern void mos_hm_init(void *p_hm, size_t entry_size); extern void *mos_hm_new_fn(MosHmInitArgs args); extern void mos_hm_put_fn(void *p_hm, void *key, size_t entry_size, size_t key_size, uint8_t load_factor); extern size_t mos_hm_get_fn(void *hm, void *key, size_t entry_size, size_t key_size); -extern void *mos_hm_get_e_fn(void *hm, void *key, size_t entry_size, size_t key_size); -extern void *mos_hm_first_fn(void *hm, size_t entry_size); -extern void *mos_hm_next_fn(void *hm, void *curr, size_t entry_size); +extern void *mos_hm_get_e_fn(const void *hm, const void *key, size_t entry_size, size_t key_size); +extern int mos_hm_del_fn(const void *hm, const void *key, size_t entry_size, size_t key_size); +extern void *mos_hm_first_fn(const void *hm, size_t entry_size); +extern void *mos_hm_next_fn(const void *hm, const void *curr, size_t entry_size); #endif // MOSLIB_DS_HASHMAP_H diff --git a/include/moslib/tester.h b/include/moslib/tester.h index a522b9d..f8cc8b1 100644 --- a/include/moslib/tester.h +++ b/include/moslib/tester.h @@ -23,10 +23,9 @@ // ---------------------------------------------------------------------------------------------------- // // Create tests. -// Tests are of type TestFn (Test (*)()). // They should use test_assert functions to check correctness. // Example: -// Test test_fn() { +// TEST(test_fn) { // int result1 = 1 + 2; // int result2 = 3 + 5; // @@ -38,11 +37,11 @@ // You need to create a helper test and pass it into test_assert_exit in main test. // Pass the helper test and expected exit code to it. // Example: -// Test helper_test() { +// TEST_HELPER(helper_test) { // int param1, param2; // int result = exit_failure_function(¶m1, ¶m2); // } -// Test main_test() { +// TEST(main_test) { // test_assert_exit(helper_test, EXIT_FAILURE); // } // @@ -50,17 +49,17 @@ // You need to create a helper test and pass it into test_assert_out in main test. // Pass the helper test, output stream, and expected output to it. // Example: -// Test helper_test() { +// TEST_HELPER(helper_test) { // printf("output"); // } -// Test main_test() { +// TEST(main_test) { // test_assert_out(helper_test, stdout, "output"); // } // // If your functions have output and you want to suppress them for the sake of tests, // you can do so using suppress_output and unsupress_outputs. // Example: -// Test error_test() { +// TEST(error_test) { // suppress_output(stdout); // suppress_output(stderr); // int code = fun_that_fails_with_output(); @@ -96,7 +95,8 @@ #ifndef MOS_FORCE_PREFIXES -#define Test MosTest +#define TEST MOS_TEST +#define TEST_HELPER MOS_TEST_HELPER #define Tester MosTester #define TestGroup MosTestGroup #define TestFn MosTestFn @@ -113,10 +113,11 @@ #endif // MOS_FORCE_PREFIXES -typedef void MosTest; // this is just for nice indication that a function is a test +#define MOS_TEST(name) static void name(void) +#define MOS_TEST_HELPER MOS_TEST typedef struct MosTester MosTester; typedef struct MosTestGroup MosTestGroup; -typedef MosTest (*MosTestFn)(void); +typedef void (*MosTestFn)(void); // Initalize new tester // You can skip this and just define it as NULL - it will initalize automatically diff --git a/src/ds/hashmap.c b/src/ds/hashmap.c index 9b92302..60c85af 100644 --- a/src/ds/hashmap.c +++ b/src/ds/hashmap.c @@ -11,6 +11,7 @@ typedef struct { uint8_t *filled; + uint8_t *dead; size_t size; size_t cap; uint32_t (*hash)(const void *key); @@ -25,14 +26,26 @@ static void *hdr2hm(Header *hdr) { return hdr + 1; } -static int filled(void *hm, size_t index) { +static int filled(const void *hm, size_t index) { return hm2hdr(hm)->filled[index / 8] & (1 << index % 8); } -static void fill(void *hm, size_t index) { +static void fill(const void *hm, size_t index) { hm2hdr(hm)->filled[index / 8] |= (1 << index % 8); } +static int dead(const void *hm, size_t index) { + return hm2hdr(hm)->dead[index / 8] & (1 << index % 8); +} + +static void kill(const void *hm, size_t index) { + hm2hdr(hm)->dead[index / 8] |= (1 << index % 8); +} + +static void unkill(const void *hm, size_t index) { + hm2hdr(hm)->dead[index / 8] &= (0xFF ^ (1 << index % 8)); +} + // FNV-1a static uint32_t default_hash(const void *key, size_t key_size) { const uint8_t *p = key; @@ -71,6 +84,7 @@ void mos_hm_init(void *p_hm, size_t entry_size) { Header *hdr = mos_safe_malloc(sizeof(Header) + (INIT_CAP + 1) * entry_size); *hdr = (Header){ .filled = mos_safe_calloc((INIT_CAP - 1) / 8 + 1, 1), + .dead = mos_safe_calloc((INIT_CAP - 1) / 8 + 1, 1), .size = 0, .cap = INIT_CAP, .hash = NULL, @@ -84,6 +98,7 @@ void mos_hm_init(void *p_hm, size_t entry_size) { if (hdr->cap == 0) { hdr = mos_safe_realloc(hdr, sizeof(Header) + (INIT_CAP + 1) * entry_size); hdr->filled = mos_safe_calloc((INIT_CAP - 1) / 8 + 1, 1); + hdr->dead = mos_safe_calloc((INIT_CAP - 1) / 8 + 1, 1); hdr->cap = INIT_CAP; *(void **)p_hm = hdr2hm(hdr); } @@ -92,6 +107,7 @@ void mos_hm_init(void *p_hm, size_t entry_size) { void *mos_hm_new_fn(MosHmInitArgs args) { Header *hdr = mos_safe_malloc(sizeof(Header)); hdr->filled = NULL; + hdr->dead = NULL; hdr->cap = 0; hdr->size = 0; @@ -118,16 +134,20 @@ void *mos_hm_new_fn(MosHmInitArgs args) { return hdr2hm(hdr); } -static size_t probe(void *hm, void *key, size_t entry_size, size_t key_size, size_t key_off) { +static size_t probe(const void *hm, const void *key, size_t entry_size, size_t key_size, size_t key_off, int put) { Header *hdr = hm2hdr(hm); uint32_t hash = hdr->hash ? hdr->hash(key) : default_hash(key, key_size); size_t i = hash % hdr->cap; + size_t tomb = 0; for (size_t it = 0; it < hdr->cap; it++) { void *key2 = (char *)hm + (i + 1) * entry_size + key_off; - if (!filled(hm, i) || (hdr->eq ? hdr->eq(key, key2) : default_eq(key, key2, key_size))) { + if (!filled(hm, i)) + return tomb ? tomb : i; + if (hdr->eq ? hdr->eq(key, key2) : default_eq(key, key2, key_size)) return i; - } + if (put && tomb == 0 && dead(hm, i)) + tomb = i; i = (i + 1) % hdr->cap; } return 0; @@ -140,7 +160,8 @@ static void expand(void *p_hm, size_t entry_size, size_t key_size, size_t key_of Header *new_hdr = mos_safe_malloc(sizeof(Header) + (2 * hdr->cap + 1) * entry_size); *new_hdr = (Header){ .filled = mos_safe_calloc((2 * hdr->cap - 1) / 8 + 1, 1), - .size = hdr->size, + .dead = mos_safe_calloc((2 * hdr->cap - 1) / 8 + 1, 1), + .size = mos_hm_size(hm), .cap = 2 * hdr->cap, .hash = hdr->hash, .eq = hdr->eq, @@ -148,7 +169,7 @@ static void expand(void *p_hm, size_t entry_size, size_t key_size, size_t key_of void *new_hm = hdr2hm(new_hdr); for (size_t i = 0; i < hdr->cap; i++) { - if (!filled(hm, i)) + if (!filled(hm, i) || dead(hm, i)) continue; void *entry = (char *)hm + (i + 1) * entry_size; @@ -167,6 +188,7 @@ static void expand(void *p_hm, size_t entry_size, size_t key_size, size_t key_of } free(hdr->filled); + free(hdr->dead); free(hdr); *(void **)p_hm = new_hm; } @@ -176,12 +198,13 @@ void mos_hm_put_fn(void *p_hm, void *key, size_t entry_size, size_t key_size, ui Header *hdr = hm2hdr(*(void **)p_hm); void *hm = *(void **)p_hm; - size_t i = probe(hm, key, entry_size, key_size, key_off); + size_t i = probe(hm, key, entry_size, key_size, key_off, 1); memcpy((char *)hm + (i + 1) * entry_size, hm, entry_size); if (!filled(hm, i)) { hdr->size++; fill(hm, i); } + unkill(hm, i); if (hdr->size * 100 >= hdr->cap * load_factor) expand(p_hm, entry_size, key_size, key_off); @@ -189,23 +212,32 @@ void mos_hm_put_fn(void *p_hm, void *key, size_t entry_size, size_t key_size, ui size_t mos_hm_get_fn(void *hm, void *key, size_t entry_size, size_t key_size) { size_t key_off = (char *)key - (char *)hm; - size_t i = probe(hm, key, entry_size, key_size, key_off); - if (!filled(hm, i)) { + size_t i = probe(hm, key, entry_size, key_size, key_off, 0); + if (!filled(hm, i) || dead(hm, i)) { memset(hm, 0, entry_size); return 0; } return i + 1; } -void *mos_hm_get_e_fn(void *hm, void *key, size_t entry_size, size_t key_size) { +void *mos_hm_get_e_fn(const void *hm, const void *key, size_t entry_size, size_t key_size) { size_t key_off = (char *)key - (char *)hm; - size_t i = probe(hm, key, entry_size, key_size, key_off); - if (!filled(hm, i)) + size_t i = probe(hm, key, entry_size, key_size, key_off, 0); + if (!filled(hm, i) || dead(hm, i)) return NULL; return (char *)hm + (i + 1) * entry_size; } -void *mos_hm_first_fn(void *hm, size_t entry_size) { +int mos_hm_del_fn(const void *hm, const void *key, size_t entry_size, size_t key_size) { + size_t key_off = (char *)key - (char *)hm; + size_t i = probe(hm, key, entry_size, key_size, key_off, 0); + if (!filled(hm, i) || dead(hm, i)) + return 0; + kill(hm, i); + return 1; +} + +void *mos_hm_first_fn(const void *hm, size_t entry_size) { if (!hm) return NULL; @@ -214,13 +246,13 @@ void *mos_hm_first_fn(void *hm, size_t entry_size) { return NULL; for (size_t i = 0; i < hdr->cap; i++) { - if (filled(hm, i)) + if (filled(hm, i) && !dead(hm, i)) return (char *)hm + (i + 1) * entry_size; } return NULL; } -void *mos_hm_next_fn(void *hm, void *curr, size_t entry_size) { +void *mos_hm_next_fn(const void *hm, const void *curr, size_t entry_size) { if (!hm) return NULL; @@ -236,16 +268,27 @@ void *mos_hm_next_fn(void *hm, void *curr, size_t entry_size) { return NULL; for (size_t i = index; i < hdr->cap; i++) { - if (filled(hm, i)) + if (filled(hm, i) && !dead(hm, i)) return (char *)hm + (i + 1) * entry_size; } return NULL; } -size_t mos_hm_size(void *hm) { +static size_t bit_count(const uint8_t *bitmap, size_t size) { + size_t count = 0; + for (size_t i = 0; i < size; i++) { + uint8_t c = (bitmap[i] & 0x55) + ((bitmap[i] >> 1) & 0x55); + c = (c & 0x33) + ((c >> 2) & 0x33); + count += (c & 0x0F) + ((c >> 4) & 0x0F); + } + return count; +} + +size_t mos_hm_size(const void *hm) { if (!hm) return 0; - return hm2hdr(hm)->size; + Header *hdr = hm2hdr(hm); + return hdr->size - bit_count(hdr->dead, (hdr->cap - 1) / 8 + 1); } void mos_hm_free(void *hm) { @@ -254,5 +297,6 @@ void mos_hm_free(void *hm) { Header *hdr = hm2hdr(hm); free(hdr->filled); + free(hdr->dead); free(hdr); } diff --git a/tests/ds/array_tests.c b/tests/ds/array_tests.c index b292407..c5d7c4d 100644 --- a/tests/ds/array_tests.c +++ b/tests/ds/array_tests.c @@ -4,7 +4,7 @@ #include <string.h> -Test cap_test() { +TEST(cap_test) { float *arr = NULL; test_assert(arr_cap(arr) == 0, "uninitialized array has capacity different than 0"); @@ -24,7 +24,7 @@ Test cap_test() { arr_free(arr); } -Test len_test() { +TEST(len_test) { char *arr = NULL; test_assert(arr_len(arr) == 0, "uninitialized array has length different than 0"); @@ -39,7 +39,7 @@ Test len_test() { arr_free(arr); } -Test adding_items() { +TEST(adding_items) { int *arr = NULL; // {3} @@ -84,7 +84,7 @@ Test adding_items() { arr_free(arr); } -Test getting_items() { +TEST(getting_items) { struct test { int f1; char f2; @@ -121,7 +121,7 @@ Test getting_items() { arr_free(arr); } -Test deleting_items() { +TEST(deleting_items) { int *arr = NULL; int items[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; arr_append_n(arr, items, 9); @@ -152,7 +152,7 @@ Test deleting_items() { arr_free(arr); } -Test arr_concat_test() { +TEST(arr_concat_test) { unsigned long *arr1 = NULL; unsigned long *arr2 = NULL; diff --git a/tests/ds/hashmap_tests.c b/tests/ds/hashmap_tests.c index 288bb4e..844ffb2 100644 --- a/tests/ds/hashmap_tests.c +++ b/tests/ds/hashmap_tests.c @@ -8,7 +8,9 @@ #include "moslib/ds/array.h" #include "moslib/string.h" -Test put_get() { +#define INIT_CAP 16 + +TEST(put_get) { HM_DEF(E, float, int); E *hm = NULL; @@ -21,22 +23,21 @@ Test put_get() { test_assert(hm_get(hm, 0.0f) == 2137, "hm_put didn't update value properly"); test_assert(hm_size(hm) == 2, "hm_size returned wrong entry count"); - // a lot of puts and gets to test expansion of hashmap - for (int i = 2; i < 100; i++) { + for (int i = 2; i < 2 * INIT_CAP + 2; i++) { hm_put(hm, (float)i, i); } int flag = 1; - for (int i = 2; i < 100; i++) { + for (int i = 2; i < 2 * INIT_CAP + 2; i++) { if (hm_get(hm, (float)i) != i) flag = 0; } test_assert(flag, "hm_put / hm_get failed when expansion was needed"); - test_assert(hm_size(hm) == 100, "hm_size returned wrong entry count"); + test_assert(hm_size(hm) == 2 * INIT_CAP + 2, "hm_size returned wrong entry count"); hm_free(hm); } -Test put_e_get_e() { +TEST(put_e_get_e) { HM_DEF(E, float, int); E *hm = NULL; @@ -54,7 +55,33 @@ Test put_e_get_e() { hm_free(hm); } -Test str_key() { +TEST(deleting) { + HM_DEF(E, long double, float); + E *hm = NULL; + + hm_put(hm, 1.0, 1.0); + hm_put(hm, 2.0, 2.0); + + int del = hm_del(hm, 1.0); + test_assert(hm_get_e(hm, 1.0) == NULL, "hm_del didn't delete entry it supposed to"); + test_assert(del == 1, "hm_del didn't return 1 when it deleted"); + test_assert(hm_size(hm) == 1, "hm_size after successful hm_del is incorrect"); + + del = hm_del(hm, 1.0); + test_assert(del == 0, "hm_del didn't return 0 when it didn't delete"); + test_assert(hm_get(hm, 2.0) == 2.0, "hm_del deleted wrong entry"); + test_assert(hm_size(hm) == 1, "hm_size after failed hm_del is incorrect"); + + for (int i = 3; i < 2 * INIT_CAP + 3; i++) { + hm_put(hm, (long double)i, (float)i); + } + test_assert(hm_get_e(hm, 1.0) == NULL, "expansion revived entry"); + test_assert(hm_size(hm) == 2 * INIT_CAP + 1, "hm_size after expansion is incorrect"); + + hm_free(hm); +} + +TEST(str_key) { HM_DEF(E, char *, int); E *hm = hm_new(.key = STR); @@ -72,7 +99,7 @@ Test str_key() { hm_free(hm); } -Test ss_key() { +TEST(ss_key) { HM_DEF(E, StringSlice, int); E *hm = hm_new(.key = SS); @@ -92,7 +119,7 @@ Test ss_key() { hm_free(hm); } -Test looping() { +TEST(looping) { HM_DEF(E, int, int); E *hm = NULL; @@ -127,6 +154,7 @@ void ds_hashmap_tests(Tester *tester) { TestGroup *group = add_test_group(tester, "moslib/ds/hashmap.h"); add_test(group, put_get); add_test(group, put_e_get_e); + add_test(group, deleting); add_test(group, str_key); add_test(group, ss_key); add_test(group, looping); diff --git a/tests/safe_tests.c b/tests/safe_tests.c index 3d46a37..b50b073 100644 --- a/tests/safe_tests.c +++ b/tests/safe_tests.c @@ -5,11 +5,11 @@ #include <stdlib.h> #include <unistd.h> -Test malloc_exit() { +TEST_HELPER(malloc_exit) { safe_malloc(ULLONG_MAX); } -Test test_safe_malloc() { +TEST(test_safe_malloc) { void *p = safe_malloc(1024); test_assert(p != NULL, "Failed to malloc 1KiB"); @@ -18,11 +18,11 @@ Test test_safe_malloc() { unsuppress_outputs(); } -Test calloc_exit() { +TEST_HELPER(calloc_exit) { safe_calloc(ULLONG_MAX, ULLONG_MAX); } -Test test_safe_calloc() { +TEST(test_safe_calloc) { void *p = safe_calloc(16, 16); test_assert(p != NULL, "Failed to calloc 16 items of 16 bytes"); @@ -31,12 +31,12 @@ Test test_safe_calloc() { unsuppress_outputs(); } -Test realloc_exit() { +TEST_HELPER(realloc_exit) { void *p = NULL; safe_realloc(p, ULLONG_MAX); } -Test test_safe_realloc() { +TEST(test_safe_realloc) { void *p = NULL; p = safe_realloc(p, 1024); test_assert(p != NULL, "Failed to realloc NULL to 1KiB"); @@ -49,11 +49,11 @@ Test test_safe_realloc() { unsuppress_outputs(); } -Test fopen_exit() { +TEST_HELPER(fopen_exit) { safe_fopen("/non-existing-file-name", "r"); } -Test test_safe_fopen() { +TEST(test_safe_fopen) { FILE *fp = safe_fopen(__FILE__, "r"); test_assert(fp != NULL, "Failed to fopen current file"); @@ -62,16 +62,16 @@ Test test_safe_fopen() { unsuppress_outputs(); } -Test test_safe_tmpfile() { +TEST(test_safe_tmpfile) { FILE *fp = safe_tmpfile(); test_assert(fp != NULL, "Failed to create a tmpfile"); } -Test dup_exit() { +TEST_HELPER(dup_exit) { safe_dup(-1); } -Test test_safe_dup() { +TEST(test_safe_dup) { int fd = safe_dup(STDOUT_FILENO); test_assert(fd != -1, "Failed to dup STDOUT_FILENO"); close(fd); @@ -81,11 +81,11 @@ Test test_safe_dup() { unsuppress_outputs(); } -Test dup2_exit() { +TEST_HELPER(dup2_exit) { safe_dup2(-1, STDOUT_FILENO); } -Test test_safe_dup2() { +TEST(test_safe_dup2) { int res = dup2(STDOUT_FILENO, STDOUT_FILENO); test_assert(res != -1, "Failed to dup STDOUT_FILENO 2 itself"); diff --git a/tests/string_tests.c b/tests/string_tests.c index 4cb6372..0d0d7e2 100644 --- a/tests/string_tests.c +++ b/tests/string_tests.c @@ -9,7 +9,7 @@ #define HELLO_WORLD_LIT "Hello, World!" -Test creating() { +TEST(creating) { char *str = HELLO_WORLD_LIT; size_t str_len = strlen(str); @@ -32,12 +32,12 @@ Test creating() { test_assert(ss5.data == ss1.data && ss5.len == ss1.len, "ss_from_arr created wrong slice"); } -Test ss_print_helper() { +TEST(ss_print_helper) { StringSlice ss = ss_from_str("test"); ss_print(ss); } -Test printing() { +TEST(printing) { test_assert_out(ss_print_helper, stdout, "test"); StringSlice ss = ss_from_str("slice"); @@ -46,7 +46,7 @@ Test printing() { test_assert(strcmp(buf, "out: slice :)") == 0, "SS_FMT + SS_ARGS printed wrong output"); } -Test comparing() { +TEST(comparing) { StringSlice ss = ss_from_str("hello world"); test_assert(ss_eq(ss, ss), "slice is not equal to itself"); test_assert(ss_eq_str(ss, ss.data), "slice is not equal to its C string"); @@ -66,7 +66,7 @@ Test comparing() { test_assert(ss_eq_str(ss4, "world") == 0, "slice is equal to different string"); } -Test trimming() { +TEST(trimming) { StringSlice ss = ss_from_str(" Hi :) "); StringSlice t = ss_trim(ss); test_assert(ss_eq_str(t, "Hi :)"), "trim didn't trim properly"); @@ -83,7 +83,7 @@ Test trimming() { test_assert(ss_eq_str(t, ""), "trimming breaks for all whitespace slice"); } -Test prefix_suffix() { +TEST(prefix_suffix) { StringSlice ss = ss_from_str("pre mid suf"); test_assert(ss_starts_with(ss, ss_from_str("pre")), "slice doesn't start with its slice prefix"); @@ -103,7 +103,7 @@ Test prefix_suffix() { test_assert(ss_ends_with(ss2, ss_from_str("")), "ends_with breaks for empty slice and suffix"); } -Test deleting() { +TEST(deleting) { StringSlice ss = ss_from_str("1234567890"); size_t deleted = ss_del_left(&ss, 2); @@ -147,7 +147,7 @@ Test deleting() { test_assert(!flag && ss.len == 7, "del_suffix_str didn't work properly for not found suffix"); } -Test splitting() { +TEST(splitting) { StringSlice ss1 = ss_from_str("Hello, World!"); StringSlice ss2 = ss_split(&ss1, ','); @@ -191,7 +191,7 @@ Test splitting() { test_assert(ss_eq_str(ss_right, "") && ss_eq_str(ss_middle, ""), "ss_split_right didn't split properly (n > len)"); } -Test finding() { +TEST(finding) { char *txt = "a slice of FINDME text"; StringSlice ss = ss_from_str(txt); @@ -205,7 +205,7 @@ Test finding() { test_assert(ss_eq_str(ss_find_str(ss, "abcd"), ""), "find_str didn't return empty slice for not found target"); } -Test utf8_len_test() { +TEST(utf8_len_test) { StringSlice ss = ss_from_str("1 byte chars"); test_assert(ss_utf8_len(ss) == ss.len, "utf8_len differs from len for all 1 byte characters"); |
