commit da735c49230ce27cc18449d4d5d7f3bcfecaa7de from: Evan Burkey date: Sun Feb 15 05:42:05 2026 UTC fix memory bugs, general code cleanup, implement ctest commit - dfbe39864b6e5026765fb16732426ea0100f396e commit + da735c49230ce27cc18449d4d5d7f3bcfecaa7de blob - 221cf5558f79da78e54a00bb1e33cb3b7b840279 blob + 82a7d72d0085fded034b6622d51eb0a1b5456546 --- .gitignore +++ .gitignore @@ -7,5 +7,6 @@ libflint.so test tcptest testrunner +test_* .idea netmanual blob - 2fd17e00ad933ad40ed49fb4cce439bb2a8c93ac blob + c24d9315fdc198311dd387eec1a0fe4f21aae62c --- CMakeLists.txt +++ CMakeLists.txt @@ -36,21 +36,51 @@ if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux")) endif() if(${CMAKE_PROJECT_NAME} STREQUAL flint) - add_executable(tests tests/tests.c) - target_include_directories(tests PRIVATE include) + enable_testing() if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - target_link_libraries(tests flint pthread bsd) + set(FLINT_TEST_LIBS flint pthread bsd) else() - target_link_libraries(tests flint pthread) + set(FLINT_TEST_LIBS flint pthread) endif() + set(TESTS + linkedlist + set + stack + binarytree + math + vector + string + crypto + parsing + memory + ) + + foreach(t ${TESTS}) + add_executable(test_${t} tests/test_${t}.c) + target_include_directories(test_${t} PRIVATE include) + target_link_libraries(test_${t} ${FLINT_TEST_LIBS}) + add_test(NAME ${t} COMMAND test_${t}) + endforeach() + + # Network test (slow, uses sleep + sockets) + add_executable(test_network tests/test_network.c) + target_include_directories(test_network PRIVATE include) + target_link_libraries(test_network ${FLINT_TEST_LIBS}) + add_test(NAME network COMMAND test_network) + set_tests_properties(network PROPERTIES LABELS "slow") + + # macOS-only test + if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + add_executable(test_macos tests/test_macos.c) + target_include_directories(test_macos PRIVATE include) + target_link_libraries(test_macos ${FLINT_TEST_LIBS}) + add_test(NAME macos COMMAND test_macos) + set_tests_properties(macos PROPERTIES LABELS "slow") + endif() + add_executable(netmanual tests/netmanual.c) target_include_directories(netmanual PRIVATE include) - - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - target_link_libraries(netmanual flint pthread bsd) - else() - target_link_libraries(netmanual flint pthread) - endif() + target_link_libraries(netmanual ${FLINT_TEST_LIBS}) endif() blob - 2768f4d06b3602b115b09dcf2cd98a2de2a7f17b blob + 171a33440699c49f52cca8fb2fd1d322cfe13875 --- README.md +++ README.md @@ -4,8 +4,7 @@ My personal library of common C data structures and al ## Documentation -Extensive documentation can be found [here](https://burkey.co/Software+Documentation/libflint/libflint). You can also check out `tests/tests.c` to -see example usage from most of the library's API. +Extensive documentation can be found [here](https://burkey.co/Software+Documentation/libflint/libflint). You can also check out the per-module test files in `tests/` for example usage. ## Building @@ -22,6 +21,15 @@ target_include_directories(${TARGET} PRIVATE lib/libfl target_link_libraries(${TARGET} PRIVATE flint ) ``` +## Testing + +```sh +cmake -B build && cmake --build build +ctest --test-dir build # run all tests +ctest --test-dir build --parallel # run in parallel +ctest --test-dir build --label-exclude slow # skip slow tests (network, macos) +``` + ## Requirements Building on Linux requires `libbsd`. Building on macOS, OpenBSD, or FreeBSD requires no extra dependencies. blob - 9bcb2fd8c09c5f4ce210a98b0d1240e559cd0c60 blob + af1bf32c978a6307eeb41f46b079b5affe93f477 --- include/lfmemory.h +++ include/lfmemory.h @@ -5,9 +5,9 @@ #include "lflinkedlist.h" -#ifndef DEFAULT_ALIGNMENT +#ifndef LF_DEFAULT_ALIGNMENT #define LF_DEFAULT_ALIGNMENT (2*sizeof(void*)) -#endif // DEFAULT_ALIGNMENT +#endif // LF_DEFAULT_ALIGNMENT typedef struct { unsigned char* buf; blob - /dev/null blob + 1f3824fd374d29737e21ca07953ec4764eaa03ae (mode 644) --- /dev/null +++ include/lftest.h @@ -0,0 +1,60 @@ +#ifndef LFTEST_H +#define LFTEST_H + +#include +#include + +static int lf_tests_total; +static int lf_tests_failed; + +#define ASSERT_TRUE(expr) do { \ + lf_tests_total++; \ + if (!(expr)) { \ + lf_tests_failed++; \ + fprintf(stderr, " FAIL %s:%d: %s\n", __FILE__, __LINE__, #expr); \ + } \ +} while(0) + +#define ASSERT_FALSE(expr) ASSERT_TRUE(!(expr)) + +#define ASSERT_EQ(a, b) do { \ + lf_tests_total++; \ + if ((a) != (b)) { \ + lf_tests_failed++; \ + fprintf(stderr, " FAIL %s:%d: %s != %s\n", __FILE__, __LINE__, #a, #b); \ + } \ +} while(0) + +#define ASSERT_NEQ(a, b) do { \ + lf_tests_total++; \ + if ((a) == (b)) { \ + lf_tests_failed++; \ + fprintf(stderr, " FAIL %s:%d: %s == %s\n", __FILE__, __LINE__, #a, #b); \ + } \ +} while(0) + +#define ASSERT_LT(a, b) do { \ + lf_tests_total++; \ + if (!((a) < (b))) { \ + lf_tests_failed++; \ + fprintf(stderr, " FAIL %s:%d: %s >= %s\n", __FILE__, __LINE__, #a, #b); \ + } \ +} while(0) + +#define ASSERT_STR_EQ(a, b) do { \ + lf_tests_total++; \ + if (strcmp((a), (b)) != 0) { \ + lf_tests_failed++; \ + fprintf(stderr, " FAIL %s:%d: \"%s\" != \"%s\"\n", __FILE__, __LINE__, (a), (b)); \ + } \ +} while(0) + +#define ASSERT_NULL(expr) ASSERT_EQ((void *)(expr), NULL) +#define ASSERT_NOT_NULL(expr) ASSERT_NEQ((void *)(expr), NULL) + +#define TEST_REPORT() do { \ + printf("%d/%d passed\n", lf_tests_total - lf_tests_failed, lf_tests_total); \ + return lf_tests_failed ? 1 : 0; \ +} while(0) + +#endif /* LFTEST_H */ blob - ba1a8603f7586d7eeb17a88cfc6ff4b521905727 (mode 755) blob + /dev/null --- run_tests.sh +++ /dev/null @@ -1,12 +0,0 @@ -set -e - -#./testrunner -./tcptest & -tcpout=$(echo "hello" | nc localhost 18632) -echo "tcpout: $tcpout" -if [ "$tcpout" != "TEST SEND" ]; then - echo "Error: \"$tcpout\" != \"TEST SEND\"" - exit 1 -fi - -exit 0 blob - a0f755715046807ad86e477d29bea7d3dd73b17b blob + 037cd2638c2f251bc8df208e644d4732c6b0fe71 --- src/binarytree.c +++ src/binarytree.c @@ -131,6 +131,7 @@ int bintree_merge(BinTree *merge, BinTree *left, BinTr merge->root->left = left->root; merge->root->right = right->root; + merge->size = 1 + left->size + right->size; left->root = NULL; left->size = 0; blob - 3d47bb055dcc82e60c8aa50c424b65ade9a9e5de blob + 7dc6dc22e56c5d9d88b4e00d81e93377619c0ffc --- src/crypto.c +++ src/crypto.c @@ -129,7 +129,7 @@ unsigned char *b64_decode(const char *s, size_t sz, si break; } // Not base64 characters - if (!isalnum(s[j]) || s[j] == '+' || s[j] == '/') { + if (!isalnum(s[j]) && s[j] != '+' && s[j] != '/') { break; } blob - 23d54c9df9d8498a4e6c0e3b3fc2ff863ecb955e blob + dfb3e5a33f8c3184643b3c716537b25f2949adcc --- src/input.c +++ src/input.c @@ -135,5 +135,6 @@ const char *capture_system(const char *cmd, int buf_sz return NULL; } fgets(buf, buf_sz, tmp); + pclose(tmp); return buf; } \ No newline at end of file blob - 1eb166ac02c8c4fd1e7e973c8040eb3088d7aa80 blob + 53ec9d9a88a03fb3090e822ddcc9959b4fef0560 --- src/linkedlist.c +++ src/linkedlist.c @@ -107,14 +107,14 @@ int ll_remove(List *list, ListNode *node, void **data) } int ll_remove_next(List *list, ListNode *node, void **data) { - if (node->next == NULL) { + if (node == NULL || node->next == NULL) { return -1; } return ll_remove(list, node->next, data); } int ll_remove_prev(List *list, ListNode *node, void **data) { - if (node->prev == NULL) { + if (node == NULL || node->prev == NULL) { return -1; } return ll_remove(list, node->prev, data); blob - 14e275b908de1b802c8ebf3e5d73acc95d2f19aa blob + 5659ee6ca791e2ed0df101b495a7236946c2a812 --- src/math.c +++ src/math.c @@ -78,5 +78,5 @@ Point *bresenham_p(Point p1, Point p2, size_t *sz) { } int is_power_of_two(int i) { - return (i & (i - 1)) == 0; + return i > 0 && (i & (i - 1)) == 0; } blob - 6cfe72d28dc88b08e240782f73007000a8b8da3c blob + 83289bdda46e17a6c8bf99a1fbcdf72cef59c53c --- src/memory.c +++ src/memory.c @@ -19,8 +19,14 @@ void arena_init(ArenaAllocator *allocator, size_t buf_ } void arena_free(ArenaAllocator *allocator) { + if (allocator == NULL) { + return; + } free(allocator->buf); - free(allocator); + allocator->buf = NULL; + allocator->buf_sz = 0; + allocator->offset_cur = 0; + allocator->offset_prev = 0; } void arena_clear(ArenaAllocator *allocator) { @@ -28,9 +34,9 @@ void arena_clear(ArenaAllocator *allocator) { allocator->offset_prev = 0; } -static uintptr_t align_forward_uintptr(const uintptr_t ptr, const uintptr_t align) { +static uintptr_t align_forward(const uintptr_t ptr, const uintptr_t align) { if (!is_power_of_two(align)) { - // TODO: Error + return 0; } uintptr_t p = ptr; const uintptr_t m = p & (align - 1); @@ -41,24 +47,11 @@ static uintptr_t align_forward_uintptr(const uintptr_t return p; } -static uintptr_t align_forward_size(const size_t ptr, const size_t align) { - if (!is_power_of_two(align)) { - // TODO: Error - } - uintptr_t p = ptr; - const uintptr_t m = p & (align - 1); - - if (m != 0) { - p += align - m; - } - return p; -} - static void *arena_malloc_align(ArenaAllocator *allocator, const size_t size, size_t align) { uintptr_t cur_ptr = (uintptr_t)allocator->buf + allocator->offset_cur; // Push forward to align, then change to relative offset - uintptr_t offset = align_forward_uintptr(cur_ptr, align); + uintptr_t offset = align_forward(cur_ptr, align); offset -= (uintptr_t)allocator->buf; if (offset + size <= allocator->buf_sz) { @@ -76,7 +69,7 @@ static void *arena_malloc_align(ArenaAllocator *alloca static void *arena_resize_align(ArenaAllocator *allocator, void *mem, const size_t old_sz, const size_t new_sz, size_t align) { unsigned char *old_mem = mem; if (!is_power_of_two(align)) { - // TODO: Error handling + return NULL; } if (old_mem == NULL || old_sz == 0) { @@ -85,15 +78,20 @@ static void *arena_resize_align(ArenaAllocator *alloca if (allocator->buf <= (unsigned char*)mem && (unsigned char*)mem < allocator->buf + allocator->buf_sz) { if (allocator->buf + allocator->offset_prev == old_mem) { + if (allocator->offset_prev + new_sz > allocator->buf_sz) { + return NULL; + } allocator->offset_cur = allocator->offset_prev + new_sz; if (new_sz > old_sz) { - // Zero out memory - memset(&allocator->buf[allocator->offset_cur], 0, new_sz - old_sz); + memset(&allocator->buf[allocator->offset_prev + old_sz], 0, new_sz - old_sz); } return old_mem; } void *new_mem = arena_malloc_align(allocator, new_sz, align); + if (new_mem == NULL) { + return NULL; + } size_t copy_size = old_sz < new_sz ? old_sz : new_sz; memmove(new_mem, old_mem, copy_size); return new_mem; @@ -103,7 +101,12 @@ static void *arena_resize_align(ArenaAllocator *alloca } void arena_resize_buf(ArenaAllocator *allocator, const size_t new_sz) { - allocator->buf = realloc(allocator->buf, sizeof(unsigned char) * new_sz); + unsigned char *new_buf = realloc(allocator->buf, sizeof(unsigned char) * new_sz); + if (new_buf == NULL) { + return; + } + allocator->buf = new_buf; + allocator->buf_sz = new_sz; } void *arena_malloc(ArenaAllocator *allocator, const size_t size) { @@ -121,12 +124,14 @@ void pool_init(PoolAllocator *allocator, size_t buf_sz allocator->buf = malloc(sizeof(unsigned char) * buf_sz); uintptr_t istart = (uintptr_t)allocator->buf; - uintptr_t start = align_forward_uintptr(istart, chunk_align); + uintptr_t start = align_forward(istart, chunk_align); allocator->buf_sz = buf_sz - (start - istart); - allocator->chunk_size = align_forward_size(chunk_sz, chunk_align); + allocator->chunk_size = align_forward(chunk_sz, chunk_align); if (allocator->chunk_size < sizeof(void *) || allocator->buf_sz < allocator->chunk_size) { - //TODO: Handle error better + free(allocator->buf); + allocator->buf = NULL; + allocator->buf_sz = 0; return; } @@ -137,7 +142,6 @@ void pool_init(PoolAllocator *allocator, size_t buf_sz } void pool_free(PoolAllocator *allocator, void *ptr) { - ListNode *node = NULL; const void *start = allocator->buf; const void *end = &allocator->buf[allocator->buf_sz]; @@ -146,7 +150,6 @@ void pool_free(PoolAllocator *allocator, void *ptr) { } if (!(start <= ptr && ptr < end)) { - // TODO: Handle error better return; } @@ -154,6 +157,9 @@ void pool_free(PoolAllocator *allocator, void *ptr) { } void pool_free_all(PoolAllocator *allocator) { + ll_destroy(allocator->free_list); + ll_init(allocator->free_list, NULL); + size_t chunk_count = allocator->buf_sz / allocator->chunk_size; for (size_t i = 0; i < chunk_count; ++i) { ll_ins_next(allocator->free_list, allocator->free_list->head, &allocator->buf[i * allocator->chunk_size]); @@ -163,7 +169,6 @@ void pool_free_all(PoolAllocator *allocator) { void *pool_alloc(PoolAllocator *allocator) { ListNode *node = allocator->free_list->head; if (node == NULL) { - // TODO: Handle error better return NULL; } @@ -173,6 +178,9 @@ void *pool_alloc(PoolAllocator *allocator) { } void pool_destroy(PoolAllocator *allocator) { + if (allocator == NULL) { + return; + } ll_destroy(allocator->free_list); free(allocator->free_list); free(allocator->buf); blob - 29841222c56782549f59bf4c7bff135b55aafe67 blob + b4f2ebfa3ef9b4d8dd0f24d89f8d435b77ab21c0 --- src/network.c +++ src/network.c @@ -96,7 +96,8 @@ int serve(Server *s, int backlog_size) { // This is just for macOS and BSDs #if !defined(__linux__) && !defined(_WIN32) struct sigaction sa; - sa.sa_handler = sighandler; + sigemptyset(&sa.sa_mask); + sa.sa_handler = sighandler; sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { fprintf(stderr, "Failed to set sigaction\n"); @@ -123,12 +124,13 @@ static void *tcp_echo_thread(void *vargp) { break; } - if (send(fd, recv_buf, strlen(recv_buf), 0) == -1) { + if (send(fd, recv_buf, r, 0) == -1) { fprintf(stderr, "Failed to send echo. Errno: %d\n", errno); close(fd); break; } } + return NULL; } void handler_tcp_echo(Server *s) { blob - 0857c95fd03a046ef2ae07d90a6aa4cb1618b109 blob + 9e68fc54b2da44997bbd2dcc4d980f68c25aaef4 --- src/set.c +++ src/set.c @@ -29,7 +29,7 @@ int set_remove(Set *set, void **data) { if (node == NULL) { return -1; } - return ll_remove_next(set, node, data); + return ll_remove(set, node, data); } int set_union(Set *setu, const Set *a, const Set *b) { @@ -117,7 +117,7 @@ int set_is_subset(const Set *a, const Set *b) { } int set_is_equal(const Set *a, const Set *b) { - if (a->size == b->size) { + if (a->size != b->size) { return 0; } return set_is_subset(a, b); blob - 4fe56033bd86f75901823d8367d78b305597e022 blob + 2cb1d2572d1af0dac58eb454a6b5905d9111c579 --- src/string.c +++ src/string.c @@ -46,7 +46,7 @@ char* substr(const char* str, size_t idx, size_t len) return NULL; } - char *substr = malloc(sizeof(char) * len + 1); + char *substr = malloc(sizeof(char) * (len + 1)); if (substr == NULL) { return NULL; } blob - 83da588467cb044d00a0cbb1bc97c7cdcc691505 blob + 86f65c6f6b4f52c38a382ae4a35ab935d0a45eb9 --- src/vector.c +++ src/vector.c @@ -153,6 +153,9 @@ int vec_shrink(Vector *vec) { } const void *vec_min(const Vector *vec, int(*cmp)(const void *a, const void *b)) { + if (vec_len(vec) == 0) { + return NULL; + } void *a = vec->elements[0]; for (size_t i = 1; i < vec_len(vec); ++i) { if (cmp(a, vec->elements[i]) > 0) { @@ -163,6 +166,9 @@ const void *vec_min(const Vector *vec, int(*cmp)(const } const void *vec_max(const Vector *vec, int(*cmp)(const void *a, const void *b)) { + if (vec_len(vec) == 0) { + return NULL; + } void *a = vec->elements[0]; for (size_t i = 1; i < vec_len(vec); ++i) { if (cmp(a, vec->elements[i]) < 0) { @@ -186,8 +192,8 @@ int vec_cmp_int(const void *a, const void *b) { } int vec_cmp_char(const void *a, const void *b) { - const char x = *(int*)a; - const char y = *(int*)b; + const char x = *(char*)a; + const char y = *(char*)b; if (x > y) { return 1; blob - bf4544915dcf359a7e1d70423f9d57eba614ec03 (mode 644) blob + /dev/null --- tests/tests.c +++ /dev/null @@ -1,546 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "lflinkedlist.h" -#include "lfnetwork.h" -#include "lfset.h" -#include "lfstack.h" -#include "lfbinarytree.h" -#include "lfvector.h" -#include "lfmath.h" -#include "lfstring.h" -#include "lfcrypto.h" -#include "lfparsing.h" -#include "lfinput.h" -#include "lfmemory.h" - -#if defined(__APPLE__) || defined(__MACH__) -#include "lfmacos.h" -#endif /* defined(__APPLE__) || defined(__MACH__) */ - -void print_ll(List *list) { - LL_ITER(list) { - printf(" %d", *((int *) node->data)); - } - printf("\n"); -} - -void test_ll() { - printf("\n--- LIST TEST ---\n"); - List *list = malloc(sizeof(List)); - ll_init(list, NULL); - - int i = 1; - int j = 2; - int k = 4; - - ll_ins_next(list, list->head, (void *) &i); - ll_ins_next(list, list->tail, (void *) &j); - ll_ins_next(list, list->tail, (void *) &k); - - printf("List: "); - print_ll(list); - - void *data; - ll_remove_next(list, list->head, &data); - - printf("List: "); - print_ll(list); - assert(*(int*)data == 2); - printf("Removed: %d\n", *((int *) data)); - - ll_destroy(list); - free(list); -} - -int int_match(const void *a, const void *b) { - return *((int *) a) == *((int *) b); -} - -void test_set() { - printf("\n--- SET TEST ---\n"); - Set *set = malloc(sizeof(Set)); - set_init(set, int_match, NULL); - - int i = 1; - int j = 2; - int k = 2; - - set_insert(set, &i); - set_insert(set, &j); - set_insert(set, &k); - - int i2 = 1; - int j2 = 4; - - Set *set2 = malloc(sizeof(Set)); - set_init(set2, int_match, NULL); - - set_insert(set2, &i2); - set_insert(set2, &j2); - - printf("Set 1:"); - print_ll(set); - - printf("Set 2:"); - print_ll(set2); - printf("\n"); - - Set *set_u = malloc(sizeof(Set)); - Set *set_i = malloc(sizeof(Set)); - Set *set_d = malloc(sizeof(Set)); - - set_union(set_u, set, set2); - printf("Union:"); - print_ll(set_u); - - set_difference(set_d, set, set2); - printf("Difference:"); - print_ll(set_d); - - set_intersection(set_i, set, set2); - printf("Intersection:"); - print_ll(set_i); - - set_destroy(set); - set_destroy(set2); - set_destroy(set_u); - set_destroy(set_i); - set_destroy(set_d); - free(set); - free(set2); - free(set_u); - free(set_i); - free(set_d); -} - -void test_stack() { - printf("\n--- STACK TEST ---\n"); - Stack *stack = malloc(sizeof(Stack)); - stack_init(stack, NULL); - - int a = 1, b = 2; - stack_push(stack, &a); - stack_push(stack, &b); - printf("Stack size: %lu\n", stack->size); - - int *p = NULL; - stack_pop(stack, (void **) &p); - printf("b = %d\n", *p); - - stack_pop(stack, (void **) &p); - printf("a = %d\n", *p); - printf("Stack size: %lu\n", stack->size); - - stack_destroy(stack); - free(stack); - stack = NULL; -} - -void test_bintree() { - printf("\n--- BINARY TREE TEST ---\n"); - BinTree *tree = malloc(sizeof(BinTree)); - bintree_init(tree, NULL); - - int root = 0; - int l1 = 1; - int l2 = 2; - int r1 = 12; - int r2 = 200; - - bintree_ins_left(tree, NULL, &root); - bintree_ins_left(tree, tree->root, &l1); - bintree_ins_left(tree, tree->root->left, &l2); - bintree_ins_right(tree, tree->root->left, &r2); - bintree_ins_right(tree, tree->root, &r1); - bintree_ins_right(tree, tree->root->right, &r2); - bintree_ins_left(tree, tree->root->right, &l1); - - bintree_debug_print(tree); - - printf("Changing r2\n"); - r2 = 100; - bintree_debug_print(tree); - - bintree_destroy(tree); - free(tree); - tree = NULL; -} - -void test_math() { - printf("\n--- MATH TEST ---\n"); - int i = 1, j = 2; - assert(max_int(i, j) == j); - printf("Between %d and %d, %d is larger\n", i, j, max_int(i, j)); - printf("Between %d and %d, %d is smaller\n", i, j, min_int(i, j)); - - char *s = "10101101"; - printf("Binary: %s\n", s); - printf("Decimal: %d\n", binstr_to_int(s)); - - char *s2 = "1010_1101"; - printf("Binary: %s\n", s2); - printf("Decimal: %d\n", binstr_to_int(s2)); - - i = 10; - i = clamp_int(i, 2, 5); - assert(i == 5); - - printf("\nGenerate line from 0,0 to 2,5\n"); - size_t sz = 0; - Point *line = bresenham(0, 0, 2, 5, &sz); - for (size_t idx = 0; idx < sz; idx++) { - printf("%d,%d ", line[idx].x, line[idx].y); - } - printf("\n"); - free(line); -} - -void print_vector(Vector *vec) { - for (size_t i = 0; i < vec->length; ++i) { - int t = *(int *) vec_at(vec, i); - printf("%d ", t); - } - printf("\n"); -} - -void test_vector() { - printf("\n--- VECTOR TEST ---\n"); - Vector *v = malloc(sizeof(Vector)); - vec_init(v, NULL); - - int e0 = 0; - int e1 = 1; - int e2 = 2; - int e3 = 3; - int e4 = 4; - - vec_push(v, &e0); - assert(v->length == 1); - int *t = vec_at(v, 0); - assert(*t == 0); - - vec_push(v, &e1); - vec_push(v, &e2); - assert(v->length == 3); - - // test access outside bounds - t = (int *) vec_safe_at(v, 3); - assert(t == NULL); - - printf("Before insert: "); - print_vector(v); - vec_push(v, &e3); - vec_insert(v, &e4, 1); - printf("After insert: "); - print_vector(v); - - t = (int *) vec_at(v, 4); - assert(*t == e3); - t = (int *) vec_at(v, 1); - assert(*t == e4); - - const int *min = vec_min(v, vec_cmp_int); - const int *max = vec_max(v, vec_cmp_int); - printf("min: %d\n", *min); - printf("max: %d\n", *max); - assert(*min == e0); - assert(*max == e4); - - t = (int *) vec_remove(v, 1); - assert(t != NULL); - assert(*t == 4); - printf("After removal: "); - print_vector(v); - - t = (int *) vec_remove(v, 10); - assert(t == NULL); - - printf("\ncap before shrink: %zu\n", vec_cap(v)); - vec_shrink(v); - assert(vec_len(v) == vec_cap(v)); - printf("cap after shrink: %zu\n", vec_cap(v)); - - vec_clear(v); - assert(vec_len(v) == 0); - printf("\ncap after clear: %zu\n", vec_cap(v)); - printf("len after clear: %zu\n", vec_len(v)); - - vec_grow_to(v, 10); - assert(vec_cap(v) == 10); - assert(vec_len(v) == 0); - - vec_destroy(v); - free(v); -} - -void test_string() { - printf("\n--- STRING TEST ---\n"); - const char *haystack = - "Test one two one and also maybe two but not Gabe's least favorite number, which is not one."; - const char *needles[] = { - "one", - "two", - "Gabe" - }; - - size_t sub_sz = 0; - size_t *subs = NULL; - find_substrings(haystack, needles[0], &sub_sz, &subs); - - assert(sub_sz == 3); - assert(subs[0] == 5); - assert(subs[1] == 13); - assert(subs[2] == 87); - - char *s = substr(haystack, subs[0], strlen(needles[0])); - assert(strcmp(s, needles[0]) == 0); - - free(s); - free(subs); - subs = NULL; - - find_substrings(haystack, needles[1], &sub_sz, &subs); - assert(sub_sz == 2); - assert(subs[0] == 9); - - free(subs); - subs = NULL; - - find_substrings("test one two", "nope", &sub_sz, &subs); - assert(sub_sz == 0); - assert(subs == NULL); - free(subs); - subs = NULL; - - find_substrings("123", "nopes", &sub_sz, &subs); - assert(sub_sz == 0); - assert(subs == NULL); - free(subs); - subs = NULL; - - printf("Passes all string tests\n"); -} - -void test_crypto() { - printf("\n--- CRYPTO TEST ---\n"); - - char *in = "BUTT"; - unsigned char *s = b64_encode(in, strlen(in)); - assert(strcmp(s, "QlVUVA==") == 0); - free(s); - - char *in2 = "a longer base64 test, apparently"; - s = b64_encode(in2, strlen(in2)); - assert(strcmp(s, "YSBsb25nZXIgYmFzZTY0IHRlc3QsIGFwcGFyZW50bHk=") == 0); - free(s); - - char *out2 = "YSBsb25nZXIgYmFzZTY0IHRlc3QsIGFwcGFyZW50bHk="; - size_t s_sz = 0; - s = (char *) b64_decode(out2, strlen(out2), &s_sz); - assert(strcmp(s, "a longer base64 test, apparently") == 0); - assert(strlen(s) == s_sz); - free(s); - - s = hex_decode("DEADBEEF", &s_sz); - unsigned char h[4] = { - 0xDE, 0xAD, 0xBE, 0xEF - }; - for (size_t i = 0; i < 4; ++i) { - assert(s[i] == h[i]); - } - free(s); - - // Odd number of characters - s = hex_decode("f00f5", &s_sz); - unsigned char h2[4] = { - 0x0F, 0x00, 0xF5 - }; - for (size_t i = 0; i < 3; ++i) { - assert(s[i] == h2[i]); - } - free(s); - - // leading 0x - s = hex_decode("0xf00f5", &s_sz); - for (size_t i = 0; i < 3; ++i) { - assert(s[i] == h2[i]); - } - free(s); - - s = hex_encode(h, 4); - assert(strcmp(s, "deadbeef") == 0); - free(s); - - // "Sup?" - unsigned char hexsup[4] = { - 0x53, 0x75, 0x70, 0x3F - }; - s = hex_to_str(hexsup, 4); - assert(strcmp(s, "Sup?") == 0); - free(s); - - s = repeating_key_xor_s("TEST", "HI"); - char *enc = hex_encode(s, 4); - assert(strcmp(enc, "1c0c1b1d") == 0); - free(enc); - free(s); - - unsigned char ua[2] = {0x2, 0xF}; - unsigned char ub[2] = {0x4, 0xE}; - unsigned int hamming = hamming_distance(ua, ub, 2); - assert(hamming == 3); - - hamming = hamming_distance_s("this is a test", "wokka wokka!!!"); - assert(hamming == 37); - - printf("Passes all crypto tests\n"); -} - -void test_parsing() { - printf("\n--- PARSING TEST ---\n"); - - char *nonsense = "8d82jI|dms~<>s2d"; - char *english = "This is an English sentence!"; - assert(simple_english_scoring(english) > simple_english_scoring(nonsense)); - - printf("Passes all parsing tests\n"); -} - -#define NET_MSG "TEST SEND" - -void tcp_test_handler(Server *s) { - struct sockaddr_storage client_addr; - socklen_t client_addr_sz = sizeof(client_addr); - int new_fd = accept(s->fd, (struct sockaddr *) &client_addr, &client_addr_sz); - assert(new_fd != -1); - assert(send(new_fd, NET_MSG, 10, 0) != -1); - close(new_fd); -} - -void *tcp_server_thread(void *vargp) { - Server *server = new_server(SERVERTYPE_TCP, "18632", tcp_test_handler); - serve(server, DEFAULT_BACKLOG); - delete_server(server); -} - -void udp_test_handler(Server *s) { - struct sockaddr_storage client_addr; - socklen_t client_addr_sz = sizeof(client_addr); - char recv_buf[128]; - - int r = (int) recvfrom(s->fd, recv_buf, 128, 0, (struct sockaddr *) &client_addr, &client_addr_sz); - assert(r > 0); - assert(strcmp(recv_buf, NET_MSG) == 0); -} - -void *udp_server_thread(void *vargp) { - Server *server = new_server(SERVERTYPE_UDP, "18633", udp_test_handler); - serve(server, DEFAULT_BACKLOG); - delete_server(server); -} - -void test_network() { - printf("\n--- NETWORK TEST ---\n"); - pthread_t srv_tid; - pthread_create(&srv_tid, NULL, tcp_server_thread, NULL); - - sleep(1); - const char *s = capture_system("echo hello | nc localhost 18632", 0); - assert(strcmp(s, NET_MSG) == 0); - free((char *) s); - - pthread_join(srv_tid, NULL); - printf("Passed TCP test\n"); - - pthread_create(&srv_tid, NULL, udp_server_thread, NULL); - sleep(1); - system("echo hello | nc localhost 18633"); - - pthread_join(srv_tid, NULL); - printf("Passed UDP test\n"); -} - -#if defined(__APPLE__) || defined(__MACH__) -void test_macos() { - printf("\n--- macOS TEST ---\n"); - - pid_t pid = getpid(); - ProcessData *pd = new_ProcessData(); - for (int i = 0; i < 4; i++) { - update_process(pid, pd); - printf("CPU: %.2f\n", pd->percent_cpu); - sleep(1); - } - free(pd); -} -#endif - -void test_memory() { - printf("\n--- MEMORY TEST ---\n"); - ArenaAllocator *arena = malloc(sizeof(ArenaAllocator)); - arena_init(arena, 1024); - - int *i1 = arena_malloc(arena, sizeof(int)); - int *i2 = arena_malloc(arena, sizeof(int)); - - *i1 = 1; - *i2 = 2; - - assert(i1 < i2); - assert(*i1 < *i2); - - long *l = arena_resize(arena, i1, sizeof(int), sizeof(long)); - assert(*l == 1); - - unsigned char *char_test = arena_resize(arena, i2, sizeof(int), sizeof(unsigned char)); - assert(*char_test == 2); - - arena_free(arena); - arena = NULL; - - PoolAllocator *pool = malloc(sizeof(PoolAllocator)); - pool_init(pool, 64, 16, LF_DEFAULT_ALIGNMENT); - void *a = pool_alloc(pool); - void *b = pool_alloc(pool); - void *c = pool_alloc(pool); - void *d = pool_alloc(pool); - - assert(a != NULL); - assert(b != NULL); - assert(c != NULL); - assert(d != NULL); - - assert(pool_count_available(pool) == 0); - pool_free(pool, d); - d = NULL; - assert(pool_count_available(pool) == 1); - - pool_destroy(pool); - printf("Passes all memory tests\n"); -} - -int main() { - test_ll(); - test_set(); - test_stack(); - test_bintree(); - test_math(); - test_vector(); - test_string(); - test_crypto(); - test_parsing(); - test_network(); - test_memory(); - -#if defined(__APPLE__) || defined(__MACH__) - test_macos(); -#endif - - return 0; -} blob - /dev/null blob + fe79293ff6446784eaeff8ae652c0ab90891af70 (mode 644) --- /dev/null +++ tests/test_binarytree.c @@ -0,0 +1,34 @@ +#include +#include +#include "lftest.h" +#include "lfbinarytree.h" + +int main() { + BinTree *tree = malloc(sizeof(BinTree)); + bintree_init(tree, NULL); + + int root = 0; + int l1 = 1; + int l2 = 2; + int r1 = 12; + int r2 = 200; + + bintree_ins_left(tree, NULL, &root); + ASSERT_NOT_NULL(tree->root); + + bintree_ins_left(tree, tree->root, &l1); + bintree_ins_left(tree, tree->root->left, &l2); + bintree_ins_right(tree, tree->root->left, &r2); + bintree_ins_right(tree, tree->root, &r1); + bintree_ins_right(tree, tree->root->right, &r2); + bintree_ins_left(tree, tree->root->right, &l1); + + ASSERT_EQ(*(int *)tree->root->data, 0); + ASSERT_EQ(*(int *)tree->root->left->data, 1); + ASSERT_EQ(*(int *)tree->root->right->data, 12); + + bintree_destroy(tree); + free(tree); + + TEST_REPORT(); +} blob - /dev/null blob + 42b3af2038c8a4078c1f6260551b08f1dd30c637 (mode 644) --- /dev/null +++ tests/test_crypto.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include "lftest.h" +#include "lfcrypto.h" + +int main() { + char *in = "BUTT"; + unsigned char *s = b64_encode(in, strlen(in)); + ASSERT_STR_EQ((char *)s, "QlVUVA=="); + free(s); + + char *in2 = "a longer base64 test, apparently"; + s = b64_encode(in2, strlen(in2)); + ASSERT_STR_EQ((char *)s, "YSBsb25nZXIgYmFzZTY0IHRlc3QsIGFwcGFyZW50bHk="); + free(s); + + char *out2 = "YSBsb25nZXIgYmFzZTY0IHRlc3QsIGFwcGFyZW50bHk="; + size_t s_sz = 0; + s = (unsigned char *) b64_decode(out2, strlen(out2), &s_sz); + ASSERT_STR_EQ((char *)s, "a longer base64 test, apparently"); + ASSERT_EQ(strlen((char *)s), s_sz); + free(s); + + s = hex_decode("DEADBEEF", &s_sz); + unsigned char h[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; + for (size_t i = 0; i < 4; ++i) { + ASSERT_EQ(s[i], h[i]); + } + free(s); + + s = hex_decode("f00f5", &s_sz); + unsigned char h2[3] = { 0x0F, 0x00, 0xF5 }; + for (size_t i = 0; i < 3; ++i) { + ASSERT_EQ(s[i], h2[i]); + } + free(s); + + s = hex_decode("0xf00f5", &s_sz); + for (size_t i = 0; i < 3; ++i) { + ASSERT_EQ(s[i], h2[i]); + } + free(s); + + char *enc_s = hex_encode(h, 4); + ASSERT_STR_EQ(enc_s, "deadbeef"); + free(enc_s); + + unsigned char hexsup[4] = { 0x53, 0x75, 0x70, 0x3F }; + enc_s = hex_to_str(hexsup, 4); + ASSERT_STR_EQ(enc_s, "Sup?"); + free(enc_s); + + unsigned char *xor_s = repeating_key_xor_s("TEST", "HI"); + enc_s = hex_encode(xor_s, 4); + ASSERT_STR_EQ(enc_s, "1c0c1b1d"); + free(enc_s); + free(xor_s); + + unsigned char ua[2] = {0x2, 0xF}; + unsigned char ub[2] = {0x4, 0xE}; + unsigned int hamming = hamming_distance(ua, ub, 2); + ASSERT_EQ(hamming, 3); + + hamming = hamming_distance_s("this is a test", "wokka wokka!!!"); + ASSERT_EQ(hamming, 37); + + TEST_REPORT(); +} blob - /dev/null blob + 02121eab523233f0ce728df2fc6931aba6901619 (mode 644) --- /dev/null +++ tests/test_linkedlist.c @@ -0,0 +1,29 @@ +#include +#include +#include "lftest.h" +#include "lflinkedlist.h" + +int main() { + List *list = malloc(sizeof(List)); + ll_init(list, NULL); + + int i = 1; + int j = 2; + int k = 4; + + ll_ins_next(list, list->head, (void *) &i); + ll_ins_next(list, list->tail, (void *) &j); + ll_ins_next(list, list->tail, (void *) &k); + + ASSERT_EQ(list->size, 3); + + void *data; + ll_remove_next(list, list->head, &data); + ASSERT_EQ(*(int *)data, 2); + ASSERT_EQ(list->size, 2); + + ll_destroy(list); + free(list); + + TEST_REPORT(); +} blob - /dev/null blob + 48c994ca9950ca8f7a752bc05da4cd93b1d76514 (mode 644) --- /dev/null +++ tests/test_macos.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include "lftest.h" + +#if defined(__APPLE__) || defined(__MACH__) +#include "lfmacos.h" + +int main() { + pid_t pid = getpid(); + ProcessData *pd = new_ProcessData(); + ASSERT_NOT_NULL(pd); + + for (int i = 0; i < 2; i++) { + update_process(pid, pd); + sleep(1); + } + ASSERT_TRUE(pd->percent_cpu >= 0.0); + + free(pd); + TEST_REPORT(); +} +#else +int main() { + printf("Skipped (not macOS)\n"); + return 0; +} +#endif blob - /dev/null blob + 780eca704baf4f47eec03ef622bf50095d48d0bb (mode 644) --- /dev/null +++ tests/test_math.c @@ -0,0 +1,28 @@ +#include +#include +#include "lftest.h" +#include "lfmath.h" + +int main() { + int i = 1, j = 2; + ASSERT_EQ(max_int(i, j), j); + ASSERT_EQ(min_int(i, j), i); + + char *s = "10101101"; + ASSERT_EQ(binstr_to_int(s), 173); + + char *s2 = "1010_1101"; + ASSERT_EQ(binstr_to_int(s2), 173); + + i = 10; + i = clamp_int(i, 2, 5); + ASSERT_EQ(i, 5); + + size_t sz = 0; + Point *line = bresenham(0, 0, 2, 5, &sz); + ASSERT_TRUE(sz > 0); + ASSERT_NOT_NULL(line); + free(line); + + TEST_REPORT(); +} blob - /dev/null blob + 11d06ce65252457ffd479c6d1f893f96c1b21ca5 (mode 644) --- /dev/null +++ tests/test_memory.c @@ -0,0 +1,92 @@ +#include +#include +#include "lftest.h" +#include "lfmemory.h" + +int main() { + ArenaAllocator *arena = malloc(sizeof(ArenaAllocator)); + arena_init(arena, 1024); + + int *i1 = arena_malloc(arena, sizeof(int)); + int *i2 = arena_malloc(arena, sizeof(int)); + + *i1 = 1; + *i2 = 2; + + ASSERT_LT(i1, i2); + ASSERT_LT(*i1, *i2); + + long *l = arena_resize(arena, i1, sizeof(int), sizeof(long)); + ASSERT_EQ(*l, 1); + + unsigned char *char_test = arena_resize(arena, i2, sizeof(int), sizeof(unsigned char)); + ASSERT_EQ(*char_test, 2); + + /* Test in-place resize (most recent allocation) */ + int *last = arena_malloc(arena, sizeof(int)); + *last = 42; + long *last_resized = arena_resize(arena, last, sizeof(int), sizeof(long)); + ASSERT_EQ((void *)last_resized, (void *)last); + ASSERT_EQ(*last_resized, 42); + + /* Test resize returns NULL when arena is full */ + void *too_big = arena_resize(arena, last_resized, sizeof(long), 2048); + ASSERT_NULL(too_big); + + /* Test arena_malloc returns NULL when full */ + void *full = arena_malloc(arena, 2048); + ASSERT_NULL(full); + + /* Test arena_clear resets offsets */ + arena_clear(arena); + int *after_clear = arena_malloc(arena, sizeof(int)); + ASSERT_NOT_NULL(after_clear); + + /* Test arena_resize_buf */ + arena_resize_buf(arena, 2048); + void *big_alloc = arena_malloc(arena, 1500); + ASSERT_NOT_NULL(big_alloc); + + arena_free(arena); + free(arena); + + /* Test stack-allocated arena */ + ArenaAllocator stack_arena; + arena_init(&stack_arena, 256); + int *si = arena_malloc(&stack_arena, sizeof(int)); + ASSERT_NOT_NULL(si); + *si = 99; + ASSERT_EQ(*si, 99); + arena_free(&stack_arena); + + PoolAllocator *pool = malloc(sizeof(PoolAllocator)); + pool_init(pool, 64, 16, LF_DEFAULT_ALIGNMENT); + void *a = pool_alloc(pool); + void *b = pool_alloc(pool); + void *c = pool_alloc(pool); + void *d = pool_alloc(pool); + + ASSERT_NOT_NULL(a); + ASSERT_NOT_NULL(b); + ASSERT_NOT_NULL(c); + ASSERT_NOT_NULL(d); + + ASSERT_EQ(pool_count_available(pool), 0); + pool_free(pool, d); + ASSERT_EQ(pool_count_available(pool), 1); + + /* Test pool_free_all resets properly */ + pool_free_all(pool); + size_t chunk_count = 64 / 16; + ASSERT_EQ(pool_count_available(pool), chunk_count); + + /* Allocate again after free_all to verify no corruption */ + a = pool_alloc(pool); + ASSERT_NOT_NULL(a); + b = pool_alloc(pool); + ASSERT_NOT_NULL(b); + + pool_destroy(pool); + + TEST_REPORT(); +} blob - /dev/null blob + 9fa89c42d0b00b733699a8d0ad057431232d3eda (mode 644) --- /dev/null +++ tests/test_network.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include "lftest.h" +#include "lfnetwork.h" +#include "lfinput.h" + +#define NET_MSG "TEST SEND" + +static void tcp_test_handler(Server *s) { + struct sockaddr_storage client_addr; + socklen_t client_addr_sz = sizeof(client_addr); + int new_fd = accept(s->fd, (struct sockaddr *) &client_addr, &client_addr_sz); + ASSERT_NEQ(new_fd, -1); + ASSERT_NEQ((int)send(new_fd, NET_MSG, 10, 0), -1); + close(new_fd); +} + +static void *tcp_server_thread(void *vargp) { + (void)vargp; + Server *server = new_server(SERVERTYPE_TCP, "18632", tcp_test_handler); + serve(server, DEFAULT_BACKLOG); + delete_server(server); + return NULL; +} + +static void udp_test_handler(Server *s) { + struct sockaddr_storage client_addr; + socklen_t client_addr_sz = sizeof(client_addr); + char recv_buf[128]; + + int r = (int) recvfrom(s->fd, recv_buf, 128, 0, (struct sockaddr *) &client_addr, &client_addr_sz); + ASSERT_TRUE(r > 0); + ASSERT_STR_EQ(recv_buf, NET_MSG); +} + +static void *udp_server_thread(void *vargp) { + (void)vargp; + Server *server = new_server(SERVERTYPE_UDP, "18633", udp_test_handler); + serve(server, DEFAULT_BACKLOG); + delete_server(server); + return NULL; +} + +int main() { + pthread_t srv_tid; + pthread_create(&srv_tid, NULL, tcp_server_thread, NULL); + + sleep(1); + const char *s = capture_system("echo hello | nc localhost 18632", 0); + ASSERT_STR_EQ(s, NET_MSG); + free((char *) s); + + pthread_join(srv_tid, NULL); + + pthread_create(&srv_tid, NULL, udp_server_thread, NULL); + sleep(1); + system("echo hello | nc localhost 18633"); + + pthread_join(srv_tid, NULL); + + TEST_REPORT(); +} blob - /dev/null blob + 57abe442572fbbbc6526d2271a7729463d8b5d61 (mode 644) --- /dev/null +++ tests/test_parsing.c @@ -0,0 +1,11 @@ +#include +#include "lftest.h" +#include "lfparsing.h" + +int main() { + char *nonsense = "8d82jI|dms~<>s2d"; + char *english = "This is an English sentence!"; + ASSERT_TRUE(simple_english_scoring(english) > simple_english_scoring(nonsense)); + + TEST_REPORT(); +} blob - /dev/null blob + 278cc30436e944c2424022d7e15b7ed2b6d3e657 (mode 644) --- /dev/null +++ tests/test_set.c @@ -0,0 +1,56 @@ +#include +#include +#include "lftest.h" +#include "lfset.h" + +static int int_match(const void *a, const void *b) { + return *((int *) a) == *((int *) b); +} + +int main() { + Set *set = malloc(sizeof(Set)); + set_init(set, int_match, NULL); + + int i = 1; + int j = 2; + int k = 2; + + set_insert(set, &i); + set_insert(set, &j); + set_insert(set, &k); + + ASSERT_EQ(set->size, 2); /* duplicate should not be inserted */ + + int i2 = 1; + int j2 = 4; + + Set *set2 = malloc(sizeof(Set)); + set_init(set2, int_match, NULL); + set_insert(set2, &i2); + set_insert(set2, &j2); + + Set *set_u = malloc(sizeof(Set)); + Set *set_i = malloc(sizeof(Set)); + Set *set_d = malloc(sizeof(Set)); + + set_union(set_u, set, set2); + set_difference(set_d, set, set2); + set_intersection(set_i, set, set2); + + ASSERT_EQ(set_u->size, 3); /* {1, 2, 4} */ + ASSERT_EQ(set_d->size, 1); /* {2} */ + ASSERT_EQ(set_i->size, 1); /* {1} */ + + set_destroy(set); + set_destroy(set2); + set_destroy(set_u); + set_destroy(set_i); + set_destroy(set_d); + free(set); + free(set2); + free(set_u); + free(set_i); + free(set_d); + + TEST_REPORT(); +} blob - /dev/null blob + ae60a2174307462510938d3759e5dd662d312bdf (mode 644) --- /dev/null +++ tests/test_stack.c @@ -0,0 +1,27 @@ +#include +#include +#include "lftest.h" +#include "lfstack.h" + +int main() { + Stack *stack = malloc(sizeof(Stack)); + stack_init(stack, NULL); + + int a = 1, b = 2; + stack_push(stack, &a); + stack_push(stack, &b); + ASSERT_EQ(stack->size, 2); + + int *p = NULL; + stack_pop(stack, (void **) &p); + ASSERT_EQ(*p, 2); + + stack_pop(stack, (void **) &p); + ASSERT_EQ(*p, 1); + ASSERT_EQ(stack->size, 0); + + stack_destroy(stack); + free(stack); + + TEST_REPORT(); +} blob - /dev/null blob + ba720d22e8bd1104d7cf1fc2952c5df00d8f4b50 (mode 644) --- /dev/null +++ tests/test_string.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include "lftest.h" +#include "lfstring.h" + +int main() { + const char *haystack = + "Test one two one and also maybe two but not Gabe's least favorite number, which is not one."; + const char *needles[] = { + "one", + "two", + "Gabe" + }; + + size_t sub_sz = 0; + size_t *subs = NULL; + find_substrings(haystack, needles[0], &sub_sz, &subs); + + ASSERT_EQ(sub_sz, 3); + ASSERT_EQ(subs[0], 5); + ASSERT_EQ(subs[1], 13); + ASSERT_EQ(subs[2], 87); + + char *s = substr(haystack, subs[0], strlen(needles[0])); + ASSERT_STR_EQ(s, needles[0]); + + free(s); + free(subs); + subs = NULL; + + find_substrings(haystack, needles[1], &sub_sz, &subs); + ASSERT_EQ(sub_sz, 2); + ASSERT_EQ(subs[0], 9); + + free(subs); + subs = NULL; + + find_substrings("test one two", "nope", &sub_sz, &subs); + ASSERT_EQ(sub_sz, 0); + ASSERT_NULL(subs); + free(subs); + subs = NULL; + + find_substrings("123", "nopes", &sub_sz, &subs); + ASSERT_EQ(sub_sz, 0); + ASSERT_NULL(subs); + free(subs); + subs = NULL; + + TEST_REPORT(); +} blob - /dev/null blob + efca273644b392b0885d8e9f10840b81d4e34dc7 (mode 644) --- /dev/null +++ tests/test_vector.c @@ -0,0 +1,62 @@ +#include +#include +#include "lftest.h" +#include "lfvector.h" + +int main() { + Vector *v = malloc(sizeof(Vector)); + vec_init(v, NULL); + + int e0 = 0; + int e1 = 1; + int e2 = 2; + int e3 = 3; + int e4 = 4; + + vec_push(v, &e0); + ASSERT_EQ(v->length, 1); + int *t = vec_at(v, 0); + ASSERT_EQ(*t, 0); + + vec_push(v, &e1); + vec_push(v, &e2); + ASSERT_EQ(v->length, 3); + + t = (int *) vec_safe_at(v, 3); + ASSERT_NULL(t); + + vec_push(v, &e3); + vec_insert(v, &e4, 1); + + t = (int *) vec_at(v, 4); + ASSERT_EQ(*t, e3); + t = (int *) vec_at(v, 1); + ASSERT_EQ(*t, e4); + + const int *min = vec_min(v, vec_cmp_int); + const int *max = vec_max(v, vec_cmp_int); + ASSERT_EQ(*min, e0); + ASSERT_EQ(*max, e4); + + t = (int *) vec_remove(v, 1); + ASSERT_NOT_NULL(t); + ASSERT_EQ(*t, 4); + + t = (int *) vec_remove(v, 10); + ASSERT_NULL(t); + + vec_shrink(v); + ASSERT_EQ(vec_len(v), vec_cap(v)); + + vec_clear(v); + ASSERT_EQ(vec_len(v), 0); + + vec_grow_to(v, 10); + ASSERT_EQ(vec_cap(v), 10); + ASSERT_EQ(vec_len(v), 0); + + vec_destroy(v); + free(v); + + TEST_REPORT(); +}