commit - 1a06caead69676af14aec4f145173cd819caf17d
commit + ec1b43354cef997f168f889d6830105e4ffcc292
blob - 82a7d72d0085fded034b6622d51eb0a1b5456546
blob + 5929800cc2f0c3b446496b3b877d8905ea0c6d2b
--- .gitignore
+++ .gitignore
test_*
.idea
netmanual
+CLAUDE.md
blob - c26da16ce4292aed9068c75fc09281101633362a
blob + 1c5b6b7488489a9b65510916e0c9bed3cf3a231b
--- CMakeLists.txt
+++ CMakeLists.txt
crypto
parsing
memory
+ utility
+ input
)
foreach(t ${TESTS})
blob - 5141822302a27a762d2adb8e63070a4c8f59207a
blob + 990a6b4b4f40c572c5304d2b7b4bf11c32065a5e
--- include/lfbinarytree.h
+++ include/lfbinarytree.h
#ifndef LIBFLINT_BINARY_TREE_H
#define LIBFLINT_BINARY_TREE_H
+#include <stddef.h>
+
typedef struct BinTreeNode {
void *data;
struct BinTreeNode *left;
typedef struct {
int size;
- int (*compare)(const void *a, const void *b);
-
void (*destroy)(void *data);
struct BinTreeNode *root;
} BinTree;
+enum {
+ BINTREE_PREORDER,
+ BINTREE_INORDER,
+ BINTREE_POSTORDER
+};
+
void bintree_init(BinTree *tree, void (*destroy)(void *data));
void bintree_destroy(BinTree *tree);
void bintree_rem_right(BinTree *tree, BinTreeNode *node);
-//int bintree_merge(BinTree *merge, BinTree *left, BinTree *right, void *data);
+int bintree_merge(BinTree *merge, BinTree *left, BinTree *right, void *data);
-void bintree_debug_print(BinTree *tree);
+void bintree_traverse(BinTree *tree, BinTreeNode *node, int order,
+ void (*visitor)(void *data));
+void bintree_debug_print(BinTree *tree,
+ void (*print_fn)(void *data, char *buf, size_t buf_sz));
+
#define bintree_is_eob(node) ((node) == NULL)
#define bintree_is_leaf(node) ((node)->left == NULL && (node)->right == NULL)
blob - 116107cf7edb41ba8c57145587e606f5ac7cd369
blob + 95b459a7133a40b484189cf4ccb3af097805d71c
--- include/lfcrypto.h
+++ include/lfcrypto.h
unsigned char* repeating_key_xor(const unsigned char* s, size_t s_sz, const unsigned char* key, size_t k_sz);
unsigned char *repeating_key_xor_s(const char* s, const char* key);
-unsigned int hamming_distance_s(const char *a, const char *b);
-unsigned int hamming_distance(unsigned char *a, unsigned char *b, size_t sz);
+int hamming_distance_s(const char *a, const char *b);
+int hamming_distance(const unsigned char *a, const unsigned char *b, size_t sz);
#endif // LIBFLINT_CRYPTO_H
blob - 3e5bc239140cb52650fb5c582e14275216e684a3
blob + 3fd88e9c777b1603f9e8a9b252d2662d1b3c38c7
--- include/lfinput.h
+++ include/lfinput.h
#include <stdlib.h>
-unsigned char *get_binary(const char *, size_t *fsz);
+unsigned char *inp_get_binary(const char *, size_t *fsz);
-char *get_input(const char *);
+char *inp_get_input(const char *);
-char **split(char *, size_t *, const char *);
+char **inp_split(char *, size_t *, const char *);
-char **get_lines(const char *, size_t *);
+char **inp_get_lines(const char *, size_t *);
-int *get_ints(const char *, size_t *);
+int *inp_get_ints(const char *, size_t *);
-void del_split(char **);
+void inp_del_split(char **);
-void del_lines(char **);
+void inp_del_lines(char **);
#define DEFAULT_CAPTURE_SYSTEM_BUFSIZE 1024
-const char *capture_system(const char *cmd, int buf_sz);
+char *inp_capture_system(const char *cmd, size_t buf_sz);
#endif // LIBFLINT_INPUT_H
blob - 6c63e57c408b7f62baa2bed580e9fa6b81c19e00
blob + a7e55bd3ed794ace7ba3394309b78fc3c49e9f93
--- include/lflinkedlist.h
+++ include/lflinkedlist.h
struct ListNode *tail;
} List;
-void ll_init(List *list, void (*destroy)(void *data));
+void ll_init(List *list, void (*destroy)(void *data),
+ int (*match)(const void *a, const void *b));
void ll_destroy(List *list);
int ll_remove_prev(List *list, ListNode *node, void **data);
-ListNode *ll_find(List *list, const void *data);
+ListNode *ll_find(const List *list, const void *data);
void ll_reverse(List *list);
void ll_sort(List *list, int (*cmp)(const void *a, const void *b));
-void **ll_to_array(List *list);
+void **ll_to_array(const List *list);
/* Provides ListNode *node for the iteration loop */
#define LL_ITER(list) for(ListNode *node = (list)->head; node != NULL; node = node->next)
blob - 4dde872bd863159c446a310946045764595ac6c6
blob + 77e756ed98a238fd981a346aae8fcb8baa780a4a
--- include/lfmacos.h
+++ include/lfmacos.h
#if defined(__APPLE__) || defined(__MACH__)
+#include <stdint.h>
#include <time.h>
typedef struct {
} ProcessData;
ProcessData *new_ProcessData();
+void destroy_ProcessData(ProcessData *pd);
int update_process(pid_t pid, ProcessData *proc);
void *reallocarray(void *optr, size_t nmemb, size_t size);
blob - 5267d993e8cabdd120bb33ff40697062085caf05
blob + 498c4fb3364edcf2c35928df63fa8685c10d13a0
--- include/lfmath.h
+++ include/lfmath.h
#include "lfutility.h"
+int abs_int(int a);
+
int max_int(int a, int b);
int min_int(int a, int b);
int binstr_to_int(const char *s);
-int abs_int(int i);
-
int is_power_of_two(int i);
int gcd(int a, int b);
blob - a1a15aebc088f0eccd463e74c523616e8a1a64d6
blob + 574d29a129a4809bbdc23f1b0d4adaf645caae65
--- include/lfmemory.h
+++ include/lfmemory.h
size_t save_count;
} ArenaAllocator;
-void arena_init(ArenaAllocator *allocator, size_t buf_sz);
+int arena_init(ArenaAllocator *allocator, size_t buf_sz);
void arena_free(ArenaAllocator *allocator);
void *arena_malloc(ArenaAllocator* allocator, size_t size);
-void arena_resize_buf(ArenaAllocator *allocator, size_t new_sz);
+int arena_resize_buf(ArenaAllocator *allocator, const size_t new_sz);
void *arena_resize(ArenaAllocator *allocator, void *mem, size_t old_sz, size_t new_sz);
void arena_clear(ArenaAllocator *allocator);
int arena_save(ArenaAllocator *allocator);
void arena_restore(ArenaAllocator *allocator);
typedef struct {
- unsigned char *buf;
+ unsigned char *buf;
size_t buf_sz;
size_t chunk_size;
+ size_t aligned_start;
List *free_list;
} PoolAllocator;
-void pool_init(PoolAllocator *allocator, size_t buf_sz, size_t chunk_sz, size_t chunk_align);
+int pool_init(PoolAllocator *allocator, size_t buf_sz, size_t chunk_sz, size_t chunk_align);
void pool_free(PoolAllocator *allocator, void *ptr);
void pool_free_all(PoolAllocator *allocator);
void *pool_alloc(PoolAllocator *allocator);
blob - 2cda586c07b5cccd7e27814fc6002bef118f21f3
blob + 328826df46992f5535d9323a8f63e1cec6afe61d
--- include/lfqueue.h
+++ include/lfqueue.h
#include "lflinkedlist.h"
#define Queue List
+#define queue_size(q) ((q)->size)
+#define queue_is_empty(q) ((q)->size == 0)
void queue_init(Queue *queue, void (*destroy)(void *data));
void queue_destroy(Queue *queue);
-int queue_enqueue(Queue *queue, void *data);
+int queue_enqueue(Queue *queue, const void *data);
int queue_dequeue(Queue *queue, void **data);
blob - b2c240f8a7546642af828c74086afbb91d4fa8f9
blob + 5ac9dc2b321fb8c32912d5d29a505e0c842e5349
--- include/lfset.h
+++ include/lfset.h
#include "lflinkedlist.h"
#define Set List
+#define set_size(s) ((s)->size)
void set_init(Set *set, int (*match)(const void *a, const void *b),
void (*destroy)(void *data));
void set_destroy(Set *set);
+/* Returns 0 on success, 1 if data is a duplicate, -1 on error */
int set_insert(Set *set, const void *data);
int set_remove(Set *set, void **data);
blob - 6f0739d385fe5b777b1296e05674f7d38beba69a
blob + 529493a95ebb78a3ef4c9a172475dabd2b08fb54
--- include/lfstack.h
+++ include/lfstack.h
#include "lflinkedlist.h"
#define Stack List
+#define stack_size(s) ((s)->size)
+#define stack_is_empty(s) ((s)->size == 0)
void stack_init(Stack *stack, void (*destroy)(void *data));
blob - 1e49819533239f64b0c2f0d005cdc4802c9cfd2d
blob + 7c37ca946b57b7d24bdb27a1948635e6866e069d
--- include/lfstring.h
+++ include/lfstring.h
#include <stddef.h>
-int find_substrings(const char* haystack, const char* needle, size_t *num_substrings, size_t **substrings);
+int str_find(const char* haystack, const char* needle, size_t *num_substrings, size_t **substrings);
-char* substr(const char* str, size_t idx, size_t len);
+char* str_substr(const char* str, size_t idx, size_t len);
char *str_trim(const char *str);
char *str_to_lower(const char *str);
+char **str_split(const char *str, const char *delim, int *count);
+
+int str_contains(const char *str, const char *substr);
+
#endif // LIBFLINT_H_STRING
blob - 9cf55b9abff79b53ae28c4118350e650b983fbd0
blob + 6278e8bb576be1f170d997739bf1e2d68ce76100
--- include/lfutility.h
+++ include/lfutility.h
Point Point_new(int x, int y);
Point *Point_new_p(int x, int y);
-int Point_cmp(Point a, Point b);
+void Point_destroy(Point *p);
+int Point_eq(const Point a, const Point b);
int Point_cmp_p(const Point *a, const Point *b);
int Point_cmp_v(const void *a, const void *b);
blob - ba38adb6678861381669e0b59ea2d874f47eb8ad
blob + 5a9eb12170d7652d176781cd41685ffa0547a466
--- include/lfvector.h
+++ include/lfvector.h
#ifndef LIBFLINT_H_VECTOR
#define LIBFLINT_H_VECTOR
-#include <memory.h>
+#include <string.h>
typedef struct Vector {
size_t capacity;
int vec_init_with_capacity(Vector *vec, void (*destroy)(void *data), size_t cap);
-void vec_clear(Vector *vec);
+int vec_clear(Vector *vec);
void vec_destroy(Vector *vec);
blob - 037cd2638c2f251bc8df208e644d4732c6b0fe71
blob + c1e9ea6c0a08802cf5cb014032f12ccd1906899a
--- src/binarytree.c
+++ src/binarytree.c
void bintree_init(BinTree *tree, void (*destroy)(void *data)) {
tree->size = 0;
tree->destroy = destroy;
- tree->compare = NULL;
tree->root = NULL;
}
if (node == NULL) {
if (tree->size > 0) {
- return 1;
+ return -1;
}
pos = &tree->root;
} else {
}
if ((new_node = malloc(sizeof(BinTreeNode))) == NULL) {
- return 2;
+ return -1;
}
new_node->data = data;
if (node == NULL) {
if (tree->size > 0) {
- return 1;
+ return -1;
}
pos = &tree->root;
} else {
}
if ((new_node = malloc(sizeof(BinTreeNode))) == NULL) {
- return 2;
+ return -1;
}
new_node->data = data;
}
int bintree_merge(BinTree *merge, BinTree *left, BinTree *right, void *data) {
+ if (left == right) {
+ return -1;
+ }
+
bintree_init(merge, left->destroy);
if (bintree_ins_left(merge, NULL, data) != 0) {
bintree_destroy(merge);
left->root = NULL;
left->size = 0;
+
+ /* Preserve right's destroy callback before clearing */
right->root = NULL;
right->size = 0;
return 0;
}
-void print_node(char *prefix, BinTreeNode *node, int is_left, void (*pfunc)(void *data)) {
+void bintree_traverse(BinTree *tree, BinTreeNode *node, int order,
+ void (*visitor)(void *data)) {
+ (void)tree;
+ if (node == NULL) {
+ return;
+ }
+
+ switch (order) {
+ case BINTREE_PREORDER:
+ visitor(node->data);
+ bintree_traverse(tree, node->left, order, visitor);
+ bintree_traverse(tree, node->right, order, visitor);
+ break;
+ case BINTREE_INORDER:
+ bintree_traverse(tree, node->left, order, visitor);
+ visitor(node->data);
+ bintree_traverse(tree, node->right, order, visitor);
+ break;
+ case BINTREE_POSTORDER:
+ bintree_traverse(tree, node->left, order, visitor);
+ bintree_traverse(tree, node->right, order, visitor);
+ visitor(node->data);
+ break;
+ }
+}
+
+static void print_node(char *prefix, BinTreeNode *node, int is_left,
+ void (*print_fn)(void *data, char *buf, size_t buf_sz)) {
if (node != NULL) {
- printf("%s%s", prefix, (is_left ? "├──" : "└──"));
- pfunc(node->data);
- char new_prefix[64];
- memset(new_prefix, 0, 64);
- strlcat(new_prefix, prefix, 64);
- strlcat(new_prefix, (is_left == 1 ? "│ " : " "), 64 - strlen(prefix));
- print_node(new_prefix, node->left, 1, pfunc);
- print_node(new_prefix, node->right, 0, pfunc);
+ char label[64];
+ print_fn(node->data, label, sizeof(label));
+ printf("%s%s%s\n", prefix, (is_left ? "├──" : "└──"), label);
+
+ char new_prefix[256];
+ snprintf(new_prefix, sizeof(new_prefix), "%s%s",
+ prefix, (is_left ? "│ " : " "));
+ print_node(new_prefix, node->left, 1, print_fn);
+ print_node(new_prefix, node->right, 0, print_fn);
}
}
-void bintree_debug_pfunc_int(void *data) {
- int i = *((int *) data);
- printf("%d\n", i);
+static void default_print_int(void *data, char *buf, size_t buf_sz) {
+ snprintf(buf, buf_sz, "%d", *(int *)data);
}
-void bintree_debug_print(BinTree *tree) {
- print_node("", tree->root, 0, bintree_debug_pfunc_int);
+void bintree_debug_print(BinTree *tree,
+ void (*print_fn)(void *data, char *buf, size_t buf_sz)) {
+ if (print_fn == NULL) {
+ print_fn = default_print_int;
+ }
+ print_node("", tree->root, 0, print_fn);
}
blob - 7dc6dc22e56c5d9d88b4e00d81e93377619c0ffc
blob + 8139381294e40e86fb576e7cea57329dd738e9eb
--- src/crypto.c
+++ src/crypto.c
}
unsigned char *hex_decode(const char *orig, size_t *sz) {
+ if (sz == NULL) {
+ return NULL;
+ }
+
size_t buf_sz = strlen(orig) + 1;
const char *sptr = orig;
if (strncmp(orig, "0x", 2) == 0) {
}
char *buf = malloc(sizeof(char) * buf_sz);
+ if (buf == NULL) {
+ return NULL;
+ }
+
if (strlen(sptr) % 2 != 0) {
- strlcpy(buf + 1, sptr, buf_sz - 1);
+ memcpy(buf + 1, sptr, strlen(sptr));
buf[0] = '0';
} else {
- strlcpy(buf, sptr, buf_sz);
+ memcpy(buf, sptr, strlen(sptr));
}
buf[buf_sz - 1] = '\0';
*sz = buf_sz / 2;
unsigned char *hex = malloc(sizeof(unsigned char) * *sz);
+ if (hex == NULL) {
+ free(buf);
+ return NULL;
+ }
+
const char *pos = buf;
for (size_t i = 0; i < *sz; ++i) {
char *hex_encode(const unsigned char *hex, size_t sz) {
size_t ssz = sz * 2 + 1;
char *s = malloc(sizeof(char) * ssz);
+ if (s == NULL) {
+ return NULL;
+ }
+
char *pos = s;
for (size_t i = 0; i < sz; ++i) {
char *hex_to_str(const unsigned char *hex, size_t sz) {
char *s = malloc(sizeof(char) * (sz + 1));
+ if (s == NULL) {
+ return NULL;
+ }
+
for (size_t i = 0; i < sz; ++i) {
s[i] = (char)hex[i];
}
}
unsigned char* repeating_key_xor(const unsigned char* s, size_t s_sz, const unsigned char* key, size_t k_sz) {
+ if (k_sz == 0) {
+ return NULL;
+ }
+
unsigned char* r = malloc(sizeof(unsigned char) * s_sz);
+ if (r == NULL) {
+ return NULL;
+ }
+
for (size_t i = 0, j = 0; i < s_sz; ++i) {
r[i] = s[i] ^ key[j];
j = (j + 1) % k_sz;
return repeating_key_xor((unsigned char*)s, strlen(s), (unsigned char*)key, strlen(key));
}
-unsigned int hamming_distance_s(const char *a, const char *b) {
+int hamming_distance_s(const char *a, const char *b) {
size_t sz = strlen(a);
if (sz != strlen(b)) {
return -1;
}
- return hamming_distance((unsigned char *)a, (unsigned char *)b, sz);
+ return hamming_distance((const unsigned char *)a, (const unsigned char *)b, sz);
}
-unsigned int hamming_distance(unsigned char *a, unsigned char *b, size_t sz) {
- unsigned int hamming = 0;
+int hamming_distance(const unsigned char *a, const unsigned char *b, size_t sz) {
+ int hamming = 0;
for (size_t i = 0; i < sz; ++i) {
if (a[i] == b[i]) {
continue;
}
unsigned char c = a[i] ^ b[i];
- unsigned int count = 0;
+ int count = 0;
for (; c; count++) {
c &= c - 1;
}
blob - dfb3e5a33f8c3184643b3c716537b25f2949adcc
blob + c90bf7dfe7be8484d7200668e9a862d2f7357ffd
--- src/input.c
+++ src/input.c
#include "lfinput.h"
-static FILE* open_file(const char *path, size_t *fsz) {
+static FILE* inp_open_file(const char *path, size_t *fsz, const char *mode) {
FILE *fp = NULL;
- fp = fopen(path, "r");
+ fp = fopen(path, mode);
if (fp == NULL) {
fprintf(stderr, "Failed to open %s. Returning NULL\n", path);
return NULL;
}
fseek(fp, 0, SEEK_END);
- *fsz = ftell(fp);
+ long pos = ftell(fp);
+ if (pos < 0) {
+ fprintf(stderr, "ftell failed for %s. Returning NULL\n", path);
+ fclose(fp);
+ return NULL;
+ }
+ *fsz = (size_t)pos;
rewind(fp);
return fp;
}
-unsigned char *get_binary(const char *path, size_t *fsz) {
- FILE *fp = open_file(path, fsz);
+unsigned char *inp_get_binary(const char *path, size_t *fsz) {
+ FILE *fp = inp_open_file(path, fsz, "rb");
if (fp == NULL) {
return NULL;
}
return buf;
}
-char *get_input(const char *path) {
+char *inp_get_input(const char *path) {
size_t fsz = 0;
- FILE *fp = open_file(path, &fsz);
+ FILE *fp = inp_open_file(path, &fsz, "r");
if (fp == NULL) {
return NULL;
}
return buf;
}
-char **split(char *s, size_t *lsz, const char *delim) {
+char **inp_split(char *s, size_t *lsz, const char *delim) {
+ if (s == NULL || lsz == NULL || delim == NULL) {
+ return NULL;
+ }
+
char **lines = NULL;
char *t = strtok(s, delim);
size_t n = 0;
while (t != NULL) {
- lines = realloc(lines, sizeof(char *) * ++n);
- if (lines == NULL) {
+ char **tmp = realloc(lines, sizeof(char *) * (n + 1));
+ if (tmp == NULL) {
fprintf(stderr, "Failed to realloc lines buffer. Returning NULL\n");
- free(s);
+ free(lines);
return NULL;
}
+ lines = tmp;
+ n++;
lines[n - 1] = t;
t = strtok(NULL, delim);
}
return lines;
}
-char **get_lines(const char *path, size_t *lsz) {
- return split(get_input(path), lsz, "\n");
+/*
+ * Internal split used by inp_get_lines. Stores the original string pointer
+ * at index [-1] (one slot before the returned array) so inp_del_lines can
+ * free the correct base even when strtok skips leading delimiters.
+ */
+static char **split_lines(char *s, size_t *lsz, const char *delim) {
+ if (s == NULL || lsz == NULL || delim == NULL) {
+ return NULL;
+ }
+
+ char *base = s;
+ /* Start with space for the hidden base slot + 1 token */
+ size_t n = 0;
+ size_t cap = 2;
+ char **raw = malloc(sizeof(char *) * cap);
+ if (raw == NULL) {
+ free(base);
+ return NULL;
+ }
+ raw[0] = base; /* hidden slot stores original allocation */
+
+ char *t = strtok(s, delim);
+ while (t != NULL) {
+ n++;
+ if (n + 1 >= cap) {
+ cap *= 2;
+ char **tmp = realloc(raw, sizeof(char *) * cap);
+ if (tmp == NULL) {
+ free(raw);
+ free(base);
+ *lsz = 0;
+ return NULL;
+ }
+ raw = tmp;
+ }
+ raw[n] = t;
+ t = strtok(NULL, delim);
+ }
+
+ if (n == 0) {
+ free(base);
+ free(raw);
+ *lsz = 0;
+ return NULL;
+ }
+
+ *lsz = n;
+ return raw + 1; /* return pointer past the hidden base slot */
}
-int *get_ints(const char *path, size_t *sz) {
- char **lines = get_lines(path, sz);
+char **inp_get_lines(const char *path, size_t *lsz) {
+ return split_lines(inp_get_input(path), lsz, "\n");
+}
+
+int *inp_get_ints(const char *path, size_t *sz) {
+ if (path == NULL || sz == NULL) {
+ return NULL;
+ }
+
+ char **lines = inp_get_lines(path, sz);
+ if (lines == NULL) {
+ return NULL;
+ }
+
int *i = malloc(sizeof(int) * *sz);
+ if (i == NULL) {
+ inp_del_lines(lines);
+ return NULL;
+ }
for (size_t idx = 0; idx < *sz; idx++) {
int n;
if (errstr) {
fprintf(stderr, "Failed to convert %s to int. Returning NULL\n", lines[idx]);
free(i);
- del_lines(lines);
+ inp_del_lines(lines);
return NULL;
}
i[idx] = n;
}
- del_lines(lines);
+ inp_del_lines(lines);
return i;
}
-void del_split(char **sp) {
- free(sp[0]);
+void inp_del_split(char **sp) {
+ if (sp == NULL) {
+ return;
+ }
free(sp);
}
-void del_lines(char **lines) {
- del_split(lines);
+void inp_del_lines(char **lines) {
+ if (lines == NULL) {
+ return;
+ }
+ /* lines[-1] holds the original string base pointer (set by split_lines) */
+ free(lines[-1]);
+ free(lines - 1);
}
-const char *capture_system(const char *cmd, int buf_sz) {
+char *inp_capture_system(const char *cmd, size_t buf_sz) {
+ if (cmd == NULL) {
+ return NULL;
+ }
+
if (buf_sz == 0) {
buf_sz = DEFAULT_CAPTURE_SYSTEM_BUFSIZE;
}
- char *buf = malloc(buf_sz);
+
FILE *tmp = popen(cmd, "r");
if (tmp == NULL) {
fprintf(stderr, "libflint: failed to open FILE *tmp in capture_system. Errno: %d\n", errno);
- free(buf);
return NULL;
}
- fgets(buf, buf_sz, tmp);
+
+ size_t total = 0;
+ size_t cap = buf_sz;
+ char *buf = malloc(cap);
+ if (buf == NULL) {
+ pclose(tmp);
+ return NULL;
+ }
+
+ size_t nread;
+ while ((nread = fread(buf + total, 1, cap - total - 1, tmp)) > 0) {
+ total += nread;
+ if (total + 1 >= cap) {
+ cap *= 2;
+ char *tmp2 = realloc(buf, cap);
+ if (tmp2 == NULL) {
+ free(buf);
+ pclose(tmp);
+ return NULL;
+ }
+ buf = tmp2;
+ }
+ }
+
+ buf[total] = '\0';
pclose(tmp);
return buf;
-}
\ No newline at end of file
+}
blob - 3efce6794774833d7c2752b2fe570b9e354da7dd
blob + 5caa87bc58c50c7faf32f28982bb3a2ca98399b9
--- src/linkedlist.c
+++ src/linkedlist.c
#include "lflinkedlist.h"
-void ll_init(List *list, void (*destroy)(void *data)) {
+void ll_init(List *list, void (*destroy)(void *data),
+ int (*match)(const void *a, const void *b)) {
list->size = 0;
list->destroy = destroy;
+ list->match = match;
list->head = NULL;
list->tail = NULL;
}
}
int ll_remove(List *list, ListNode *node, void **data) {
- if (node == NULL || list->size == 0) {
+ if (node == NULL || data == NULL || list->size == 0) {
return -1;
}
return ll_remove(list, node->prev, data);
}
-ListNode *ll_find(List *list, const void *data) {
- if (list->match == NULL) {
+ListNode *ll_find(const List *list, const void *data) {
+ if (list == NULL) {
return NULL;
}
- for (ListNode *node = list->head; node != NULL; node = node->next) {
- if (list->match(data, node->data)) {
- return node;
+ ListNode *node = list->head;
+ while (node != NULL) {
+ if (list->match != NULL) {
+ if (list->match(node->data, data) == 0) {
+ return node;
+ }
+ } else {
+ if (node->data == data) {
+ return node;
+ }
}
+ node = node->next;
}
return NULL;
}
list->tail = node;
}
-void **ll_to_array(List *list) {
- if (list->size == 0) {
+void **ll_to_array(const List *list) {
+ if (list == NULL || list->size == 0) {
return NULL;
}
void **arr = malloc(list->size * sizeof(void *));
blob - 3bbcf1c246a5b5475ef1fb51e62831f676c6dcf6
blob + 3409cf0851cd610e64365c0e575fc0044547bf0f
--- src/macos.c
+++ src/macos.c
+#if defined(__APPLE__) || defined(__MACH__)
+
#include <libproc.h>
#include <time.h>
#include <mach/mach_time.h>
#define NEW_PROCESS_SENTINEL (-1.0)
ProcessData *new_ProcessData() {
- ProcessData *pd = malloc(sizeof(ProcessData));
+ ProcessData *pd = calloc(1, sizeof(ProcessData));
+ if (!pd) return NULL;
pd->last_total_consumed = NEW_PROCESS_SENTINEL;
return pd;
}
+void destroy_ProcessData(ProcessData *pd) {
+ free(pd);
+}
+
int update_process(pid_t pid, ProcessData *proc) {
struct proc_taskinfo taskinfo;
const int r = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &taskinfo, PROC_PIDTASKINFO_SIZE);
if (r != PROC_PIDTASKINFO_SIZE) {
- return 1;
+ return -1;
}
- mach_timebase_info_data_t info;
- mach_timebase_info(&info);
+ static mach_timebase_info_data_t info;
+ static int info_init = 0;
+ if (!info_init) {
+ mach_timebase_info(&info);
+ info_init = 1;
+ }
const double ns_per_tick = (double)info.numer / (double)info.denom;
time(&(proc->timestamp));
if (proc->last_total_consumed != NEW_PROCESS_SENTINEL) {
time_t t = proc->timestamp - proc->last_timestamp;
- proc->percent_cpu = 100.0 * (proc->total_user_time + proc->total_kernel_time - proc->last_total_consumed) / t;
+ if (t > 0) {
+ proc->percent_cpu = 100.0 * (proc->total_user_time + proc->total_kernel_time - proc->last_total_consumed) / t;
+ } else {
+ proc->percent_cpu = 0.0;
+ }
} else {
proc->percent_cpu = 0.0;
}
}
return realloc(optr, size * nmemb);
}
+
+#endif /* defined(__APPLE__) || defined(__MACH__) */
blob - 08fed2d2db0c250cc94df7548df5cff989f536f2
blob + efcb9566eda70adaf457b15114aeb99bb658a2c6
--- src/math.c
+++ src/math.c
+#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include "lfmath.h"
+int abs_int(int a) {
+ if (a == INT_MIN) {
+ return INT_MAX;
+ }
+ return a < 0 ? -a : a;
+}
+
int max_int(int a, int b) {
if (a > b) {
return a;
}
int clamp_int(int i, int low, int high) {
+ if (low > high) {
+ int tmp = low;
+ low = high;
+ high = tmp;
+ }
if (i > high) {
return high;
} else if (i < low) {
}
int binstr_to_int(const char *s) {
+ if (!s) {
+ return -1;
+ }
int n = 0, m = 1;
for (int i = (int) strlen(s) - 1; i >= 0; --i) {
if (s[i] == '_') {
}
Point *bresenham(int x0, int y0, int x1, int y1, size_t *sz) {
- Point *line = NULL;
- size_t n = 0;
*sz = 0;
- int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
- int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
+ int dx = abs(x1 - x0);
+ int dy = abs(y1 - y0);
+ size_t npts = (size_t)(dx > dy ? dx : dy) + 1;
+
+ Point *line = malloc(sizeof(Point) * npts);
+ if (!line) {
+ return NULL;
+ }
+
+ int sx = x0 < x1 ? 1 : -1;
+ int sy = y0 < y1 ? 1 : -1;
int err = (dx > dy ? dx : -dy) / 2, e2;
+ size_t n = 0;
for (;;) {
- line = realloc(line, sizeof(Point) * ++n);
- ++*sz;
- line[n - 1].x = x0;
- line[n - 1].y = y0;
+ line[n].x = x0;
+ line[n].y = y0;
+ n++;
if (x0 == x1 && y0 == y1) {
break;
}
}
+ *sz = n;
return line;
}
return bresenham(p1.x, p1.y, p2.x, p2.y, sz);
}
-int abs_int(int i) {
- return i < 0 ? -i : i;
-}
-
int is_power_of_two(int i) {
return i > 0 && (i & (i - 1)) == 0;
}
blob - 627dbf52c50beebcc40de79d911dd68f39120235
blob + f3385917f6f35f40d939609e8e961ca55cdbed16
--- src/memory.c
+++ src/memory.c
#include "lfmemory.h"
-#define arena_sz(a) (a)->buf_sz
-
-void arena_init(ArenaAllocator *allocator, size_t buf_sz) {
+int arena_init(ArenaAllocator *allocator, size_t buf_sz) {
if (allocator == NULL) {
- return;
+ return -1;
}
allocator->buf = malloc(sizeof(unsigned char) * buf_sz);
+ if (allocator->buf == NULL) {
+ return -1;
+ }
allocator->buf_sz = buf_sz;
allocator->offset_cur = 0;
allocator->offset_prev = 0;
allocator->save_count = 0;
+ return 0;
}
void arena_free(ArenaAllocator *allocator) {
return NULL;
}
-void arena_resize_buf(ArenaAllocator *allocator, const size_t new_sz) {
+int arena_resize_buf(ArenaAllocator *allocator, const size_t new_sz) {
+ if (new_sz < allocator->offset_cur) {
+ return -1;
+ }
unsigned char *new_buf = realloc(allocator->buf, sizeof(unsigned char) * new_sz);
if (new_buf == NULL) {
- return;
+ return -1;
}
allocator->buf = new_buf;
allocator->buf_sz = new_sz;
+ return 0;
}
void *arena_malloc(ArenaAllocator *allocator, const size_t size) {
return arena_resize_align(allocator, mem, old_sz, new_sz, LF_DEFAULT_ALIGNMENT);
}
-void pool_init(PoolAllocator *allocator, size_t buf_sz, size_t chunk_sz, size_t chunk_align) {
+int pool_init(PoolAllocator *allocator, size_t buf_sz, size_t chunk_sz, size_t chunk_align) {
if (allocator == NULL) {
- return;
+ return -1;
}
allocator->buf = malloc(sizeof(unsigned char) * buf_sz);
+ if (allocator->buf == NULL) {
+ return -1;
+ }
uintptr_t istart = (uintptr_t)allocator->buf;
uintptr_t start = align_forward(istart, chunk_align);
- allocator->buf_sz = buf_sz - (start - istart);
+ allocator->aligned_start = (size_t)(start - istart);
+ allocator->buf_sz = buf_sz - allocator->aligned_start;
allocator->chunk_size = align_forward(chunk_sz, chunk_align);
if (allocator->chunk_size < sizeof(void *) || allocator->buf_sz < allocator->chunk_size) {
free(allocator->buf);
allocator->buf = NULL;
allocator->buf_sz = 0;
- return;
+ return -1;
}
allocator->free_list = malloc(sizeof(List));
- ll_init(allocator->free_list, NULL);
+ if (allocator->free_list == NULL) {
+ free(allocator->buf);
+ allocator->buf = NULL;
+ allocator->buf_sz = 0;
+ return -1;
+ }
+ ll_init(allocator->free_list, NULL, NULL);
pool_free_all(allocator);
+ return 0;
}
void pool_free(PoolAllocator *allocator, void *ptr) {
- const void *start = allocator->buf;
- const void *end = &allocator->buf[allocator->buf_sz];
+ const void *start = allocator->buf + allocator->aligned_start;
+ const void *end = allocator->buf + allocator->aligned_start + allocator->buf_sz;
if (ptr == NULL) {
return;
void pool_free_all(PoolAllocator *allocator) {
ll_destroy(allocator->free_list);
- ll_init(allocator->free_list, NULL);
+ ll_init(allocator->free_list, NULL, 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]);
+ ll_ins_next(allocator->free_list, allocator->free_list->head,
+ &allocator->buf[allocator->aligned_start + i * allocator->chunk_size]);
}
}
ll_destroy(allocator->free_list);
free(allocator->free_list);
free(allocator->buf);
- free(allocator);
+ allocator->buf = NULL;
+ allocator->free_list = NULL;
+ allocator->buf_sz = 0;
}
blob - b4f2ebfa3ef9b4d8dd0f24d89f8d435b77ab21c0
blob + fb880b8851bdf1114fda35c721753926cf02e1ad
--- src/network.c
+++ src/network.c
#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
continue;
}
+ int yes = 1;
+ setsockopt(s->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
+
if (bind(s->fd, p->ai_addr, p->ai_addrlen) != 0) {
close(s->fd);
continue;
if (p == NULL) {
fprintf(stderr, "Failed to bind\n");
+ freeaddrinfo(addr);
free(s);
return NULL;
}
}
void delete_server(Server *s) {
+ if (s == NULL) return;
+ close(s->fd);
free(s);
- s = NULL;
}
int serve(Server *s, int backlog_size) {
backlog_size = DEFAULT_BACKLOG;
}
- if (listen(s->fd, backlog_size) != 0) {
- return 1;
+ if (s->server_type != SERVERTYPE_UDP) {
+ if (listen(s->fd, backlog_size) != 0) {
+ return -1;
+ }
}
// Linux doesn't handle SA_RESTART properly, and I don't know about Windows (nor do I care)
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
fprintf(stderr, "Failed to set sigaction\n");
- return 1;
+ return -1;
}
#endif
}
static void *tcp_echo_thread(void *vargp) {
+ int fd = (int)(intptr_t)vargp;
while (1) {
char recv_buf[256];
- int fd = *(int *) vargp;
int r = (int)recv(fd, recv_buf, 256, 0);
if (r < 1) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&srv_tid, &attr, tcp_echo_thread, &new_fd);
+ pthread_create(&srv_tid, &attr, tcp_echo_thread, (void *)(intptr_t)new_fd);
+ pthread_attr_destroy(&attr);
}
}
blob - 5fa7f48c7a3818d6b9211a70803e00e0572e2362
blob + 18a81d0e82958063db5ea097fa554dbb7df9ea02
--- src/parsing.c
+++ src/parsing.c
+#include <stddef.h>
#include "lfparsing.h"
static int ses_score_sw(char c) {
}
int simple_english_scoring(const char *s) {
+ if (s == NULL) {
+ return -1;
+ }
int score = 0;
for (const char *c = s; *c != '\0'; ++c) {
score += ses_score_sw(*c);
blob - c591d62d376d9c307faf43a8ab13cdf29fe75098
blob + 264690c25a6336bdd59acf253c19fff5db139a6a
--- src/queue.c
+++ src/queue.c
#include "lfqueue.h"
void queue_init(Queue *queue, void (*destroy)(void *data)) {
- ll_init(queue, destroy);
+ ll_init(queue, destroy, NULL);
}
void queue_destroy(Queue *queue) {
ll_destroy(queue);
}
-int queue_enqueue(Queue *queue, void *data) {
- if (queue->size == 0) {
- return ll_ins_next(queue, NULL, data);
- }
+int queue_enqueue(Queue *queue, const void *data) {
return ll_ins_next(queue, queue->tail, data);
}
blob - e9ea33f070449ed8609fba04178972b065dba6a4
blob + 9370b765ba442a103da7c95ae4cafb9809a705e6
--- src/set.c
+++ src/set.c
void set_init(Set *set, int (*match)(const void *a, const void *b),
void (*destroy)(void *data)) {
- ll_init(set, destroy);
- set->match = match;
+ ll_init(set, destroy, match);
}
void set_destroy(Set *set) {
}
int set_remove(Set *set, void **data) {
+ if (data == NULL) {
+ return -1;
+ }
ListNode *node = ll_find(set, *data);
if (node == NULL) {
return -1;
}
int set_is_member(const Set *set, const void *data) {
- return ll_find((List *)set, data) != NULL;
+ return ll_find(set, data) != NULL;
}
int set_is_subset(const Set *a, const Set *b) {
blob - f8d1c4953df8c14efac4525ba9cf646abf697df6
blob + 7e0123a98021a825274196aed34c7e5aecb5480d
--- src/stack.c
+++ src/stack.c
#include "lfstack.h"
void stack_init(Stack *stack, void (*destroy)(void *data)) {
- ll_init(stack, destroy);
+ ll_init(stack, destroy, NULL);
}
void stack_destroy(Stack *stack) {
blob - a39bd8b1795b4f994bca76be4054f8820f1fa1c0
blob + 77e8f45842e4a65ef489d3d6940f5a23bbfffcc1
--- src/string.c
+++ src/string.c
#include "lfstring.h"
-int find_substrings(const char* haystack, const char* needle, size_t *num_substrings, size_t **substrings) {
+int str_find(const char* haystack, const char* needle, size_t *num_substrings, size_t **substrings) {
if (*substrings != NULL) {
return 1;
}
+ *num_substrings = 0;
+
size_t sz_h = strlen(haystack);
size_t sz_n = strlen(needle);
- if ((int)sz_h - (int)sz_n < 0) {
+ if (sz_n > sz_h) {
return 0;
}
- *num_substrings = 0;
for (size_t i = 0; i <= sz_h - sz_n; ++i) {
if (strncmp(haystack + i, needle, sz_n) == 0) {
++(*num_substrings);
return 0;
}
-char* substr(const char* str, size_t idx, size_t len) {
+char* str_substr(const char* str, size_t idx, size_t len) {
size_t sz_str = strlen(str);
if (sz_str < len || idx + len > sz_str) {
return NULL;
}
- char *substr = malloc(sizeof(char) * (len + 1));
- if (substr == NULL) {
+ char *sub = malloc(sizeof(char) * (len + 1));
+ if (sub == NULL) {
return NULL;
}
- memcpy(substr, str + idx, len);
- substr[len] = '\0';
+ memcpy(sub, str + idx, len);
+ sub[len] = '\0';
- return substr;
+ return sub;
}
char *str_trim(const char *str) {
out[len] = '\0';
return out;
}
+
+char **str_split(const char *str, const char *delim, int *count) {
+ *count = 0;
+ size_t delim_len = strlen(delim);
+
+ if (delim_len == 0) {
+ char **result = malloc(sizeof(char *));
+ if (result == NULL) {
+ return NULL;
+ }
+ result[0] = strdup(str);
+ if (result[0] == NULL) {
+ free(result);
+ return NULL;
+ }
+ *count = 1;
+ return result;
+ }
+
+ /* count segments */
+ int n = 1;
+ const char *p = str;
+ while ((p = strstr(p, delim)) != NULL) {
+ n++;
+ p += delim_len;
+ }
+
+ char **result = malloc(sizeof(char *) * n);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ int i = 0;
+ p = str;
+ const char *next;
+ while ((next = strstr(p, delim)) != NULL) {
+ size_t seg_len = next - p;
+ result[i] = malloc(seg_len + 1);
+ if (result[i] == NULL) {
+ for (int j = 0; j < i; j++) {
+ free(result[j]);
+ }
+ free(result);
+ return NULL;
+ }
+ memcpy(result[i], p, seg_len);
+ result[i][seg_len] = '\0';
+ i++;
+ p = next + delim_len;
+ }
+
+ /* last segment */
+ result[i] = strdup(p);
+ if (result[i] == NULL) {
+ for (int j = 0; j < i; j++) {
+ free(result[j]);
+ }
+ free(result);
+ return NULL;
+ }
+ *count = n;
+ return result;
+}
+
+int str_contains(const char *str, const char *substr) {
+ return strstr(str, substr) != NULL;
+}
blob - 9330ab238d5ddcad1e3170a2bd13ee8171d2d716
blob + 5e347290ae4488a0d8be1d5f61fa2c54ea42eb3f
--- src/utility.c
+++ src/utility.c
Point *Point_new_p(int x, int y) {
Point *p = malloc(sizeof(struct Point));
+ if (!p) {
+ return NULL;
+ }
p->x = x;
p->y = y;
return p;
}
-int Point_cmp(const Point a, const Point b) {
+
+void Point_destroy(Point *p) {
+ free(p);
+}
+
+int Point_eq(const Point a, const Point b) {
if (a.x == b.x && a.y == b.y) {
return 1;
}
int Point_cmp_v(const void *a, const void *b) {
return Point_cmp_p(a, b);
}
-
blob - 4fcf4f00c195c3b8f19fab2c186ffad1ee7d1aa9
blob + 42f1e34652af4031642d8236205413ea425b8c1c
--- src/vector.c
+++ src/vector.c
#define VEC_INIT_CAP 2
-static int (*vec_sort_cmp_fn)(const void *, const void *);
-
int vec_init(Vector *vec, void (*destroy)(void *data)) {
return vec_init_with_capacity(vec, destroy, VEC_INIT_CAP);
}
}
static int vec_expand(Vector *vec, size_t new_cap) {
- vec->capacity = new_cap;
- vec->elements = reallocarray(vec->elements, new_cap, sizeof(void *));
-
- if (vec->elements == NULL) {
+ void *tmp = reallocarray(vec->elements, new_cap, sizeof(void *));
+ if (tmp == NULL) {
return -1;
}
+ vec->elements = tmp;
+ vec->capacity = new_cap;
return 0;
}
static int vec_grow(Vector *const vec) {
size_t new_cap;
if (vec->capacity == 0) {
- new_cap = VEC_INIT_CAP; ;
+ new_cap = VEC_INIT_CAP;
} else {
new_cap = vec->capacity * 2;
}
return vec_expand(vec, new_cap);
}
-void vec_clear(Vector *vec) {
+int vec_clear(Vector *vec) {
+ void (*destroy)(void *data) = vec->destroy;
vec_destroy(vec);
- vec_init(vec, vec->destroy);
+ if (vec_init(vec, destroy) != 0) {
+ return -1;
+ }
+ return 0;
}
void vec_destroy(Vector *vec) {
return -1;
}
- if (vec_len(vec) + 1 >= vec->capacity) {
+ if (vec_len(vec) + 1 > vec->capacity) {
if (vec_grow(vec) != 0) {
return -1;
}
}
- if (index > vec_len(vec)) {
- return -1;
- }
-
if (index < vec_len(vec)) {
void *a = vec->elements[index];
vec->elements[index] = data;
return 0;
}
- vec->capacity = vec_len(vec);
+ if (vec_len(vec) == 0) {
+ free(vec->elements);
+ vec->elements = NULL;
+ vec->capacity = 0;
+ return 0;
+ }
+ size_t new_cap = vec_len(vec);
+
#if !defined(__OpenBSD__)
- vec->elements = reallocf(vec->elements, sizeof(void *) * vec->capacity);
+ void *tmp = reallocf(vec->elements, sizeof(void *) * new_cap);
#else
- vec->elements = reallocarray(vec->elements, vec->capacity, sizeof(void *));
+ void *tmp = reallocarray(vec->elements, new_cap, sizeof(void *));
#endif
- if (vec->elements == NULL) {
+ if (tmp == NULL) {
return -1;
}
+ vec->elements = tmp;
+ vec->capacity = new_cap;
+
return 0;
}
}
}
-static int vec_sort_cmp_wrapper(const void *a, const void *b) {
- /* qsort passes pointers to elements; our elements are void*, so a is void** */
+#if defined(__APPLE__)
+static int vec_sort_cmp_wrapper(void *thunk, const void *a, const void *b) {
+ int (*cmp)(const void *, const void *) = thunk;
const void *ea = *(const void **)a;
const void *eb = *(const void **)b;
- return vec_sort_cmp_fn(ea, eb);
+ return cmp(ea, eb);
}
+#else
+static int vec_sort_cmp_wrapper(const void *a, const void *b, void *thunk) {
+ int (*cmp)(const void *, const void *) = thunk;
+ const void *ea = *(const void **)a;
+ const void *eb = *(const void **)b;
+ return cmp(ea, eb);
+}
+#endif
void vec_sort(Vector *vec, int (*cmp)(const void *a, const void *b)) {
if (vec_len(vec) < 2) {
return;
}
- vec_sort_cmp_fn = cmp;
- qsort(vec->elements, vec_len(vec), sizeof(void *), vec_sort_cmp_wrapper);
+#if defined(__APPLE__)
+ qsort_r(vec->elements, vec_len(vec), sizeof(void *), (void *)cmp, vec_sort_cmp_wrapper);
+#else
+ qsort_r(vec->elements, vec_len(vec), sizeof(void *), vec_sort_cmp_wrapper, (void *)cmp);
+#endif
}
void *vec_bsearch(Vector *vec, const void *key, int (*cmp)(const void *a, const void *b)) {
blob - fe79293ff6446784eaeff8ae652c0ab90891af70
blob + 3346d0cbbfc1802e839c173c5fe00ab6e0176fec
--- tests/test_binarytree.c
+++ tests/test_binarytree.c
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "lftest.h"
#include "lfbinarytree.h"
+static int destroy_count;
+
+static void counting_destroy(void *data) {
+ (void)data;
+ destroy_count++;
+}
+
+/* Traversal helper: append int values to a static buffer */
+static int traversal_buf[32];
+static int traversal_idx;
+
+static void collect_int(void *data) {
+ traversal_buf[traversal_idx++] = *(int *)data;
+}
+
int main() {
+ /* Basic insertion and data access */
BinTree *tree = malloc(sizeof(BinTree));
bintree_init(tree, NULL);
int r1 = 12;
int r2 = 200;
- bintree_ins_left(tree, NULL, &root);
+ ASSERT_EQ(bintree_ins_left(tree, NULL, &root), 0);
ASSERT_NOT_NULL(tree->root);
+ ASSERT_EQ(tree->size, 1);
- 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(bintree_ins_left(tree, tree->root, &l1), 0);
+ ASSERT_EQ(bintree_ins_left(tree, tree->root->left, &l2), 0);
+ ASSERT_EQ(bintree_ins_right(tree, tree->root->left, &r2), 0);
+ ASSERT_EQ(bintree_ins_right(tree, tree->root, &r1), 0);
+ ASSERT_EQ(bintree_ins_right(tree, tree->root->right, &r2), 0);
+ ASSERT_EQ(bintree_ins_left(tree, tree->root->right, &l1), 0);
+ ASSERT_EQ(tree->size, 7);
ASSERT_EQ(*(int *)tree->root->data, 0);
ASSERT_EQ(*(int *)tree->root->left->data, 1);
ASSERT_EQ(*(int *)tree->root->right->data, 12);
+ /* Error: insert root when tree already has one */
+ ASSERT_EQ(bintree_ins_left(tree, NULL, &root), -1);
+ ASSERT_EQ(bintree_ins_right(tree, NULL, &root), -1);
+
+ /* Error: insert left/right where child already exists */
+ ASSERT_EQ(bintree_ins_left(tree, tree->root, &l1), -1);
+ ASSERT_EQ(bintree_ins_right(tree, tree->root, &r1), -1);
+
+ /* Macros */
+ ASSERT_FALSE(bintree_is_eob(tree->root));
+ ASSERT_TRUE(bintree_is_eob(NULL));
+ ASSERT_FALSE(bintree_is_leaf(tree->root));
+ ASSERT_TRUE(bintree_is_leaf(tree->root->left->left));
+
bintree_destroy(tree);
+ ASSERT_EQ(tree->size, 0);
+ ASSERT_NULL(tree->root);
free(tree);
+ /* Destroy callback */
+ destroy_count = 0;
+ BinTree dt;
+ bintree_init(&dt, counting_destroy);
+
+ int a = 10, b = 20, c = 30;
+ bintree_ins_left(&dt, NULL, &a);
+ bintree_ins_left(&dt, dt.root, &b);
+ bintree_ins_right(&dt, dt.root, &c);
+ ASSERT_EQ(dt.size, 3);
+
+ bintree_destroy(&dt);
+ ASSERT_EQ(destroy_count, 3);
+
+ /* Partial removal with destroy callback */
+ destroy_count = 0;
+ BinTree dt2;
+ bintree_init(&dt2, counting_destroy);
+ bintree_ins_left(&dt2, NULL, &a);
+ bintree_ins_left(&dt2, dt2.root, &b);
+ bintree_ins_right(&dt2, dt2.root, &c);
+ bintree_rem_left(&dt2, dt2.root);
+ ASSERT_EQ(destroy_count, 1);
+ ASSERT_EQ(dt2.size, 2);
+ ASSERT_NULL(dt2.root->left);
+ bintree_destroy(&dt2);
+ ASSERT_EQ(destroy_count, 3);
+
+ /* Traversal: build tree
+ * 1
+ * / \
+ * 2 3
+ * / \
+ * 4 5
+ */
+ BinTree tt;
+ bintree_init(&tt, NULL);
+ int v1 = 1, v2 = 2, v3 = 3, v4 = 4, v5 = 5;
+ bintree_ins_left(&tt, NULL, &v1);
+ bintree_ins_left(&tt, tt.root, &v2);
+ bintree_ins_right(&tt, tt.root, &v3);
+ bintree_ins_left(&tt, tt.root->left, &v4);
+ bintree_ins_right(&tt, tt.root->left, &v5);
+
+ /* Preorder: 1 2 4 5 3 */
+ traversal_idx = 0;
+ bintree_traverse(&tt, tt.root, BINTREE_PREORDER, collect_int);
+ ASSERT_EQ(traversal_idx, 5);
+ ASSERT_EQ(traversal_buf[0], 1);
+ ASSERT_EQ(traversal_buf[1], 2);
+ ASSERT_EQ(traversal_buf[2], 4);
+ ASSERT_EQ(traversal_buf[3], 5);
+ ASSERT_EQ(traversal_buf[4], 3);
+
+ /* Inorder: 4 2 5 1 3 */
+ traversal_idx = 0;
+ bintree_traverse(&tt, tt.root, BINTREE_INORDER, collect_int);
+ ASSERT_EQ(traversal_idx, 5);
+ ASSERT_EQ(traversal_buf[0], 4);
+ ASSERT_EQ(traversal_buf[1], 2);
+ ASSERT_EQ(traversal_buf[2], 5);
+ ASSERT_EQ(traversal_buf[3], 1);
+ ASSERT_EQ(traversal_buf[4], 3);
+
+ /* Postorder: 4 5 2 3 1 */
+ traversal_idx = 0;
+ bintree_traverse(&tt, tt.root, BINTREE_POSTORDER, collect_int);
+ ASSERT_EQ(traversal_idx, 5);
+ ASSERT_EQ(traversal_buf[0], 4);
+ ASSERT_EQ(traversal_buf[1], 5);
+ ASSERT_EQ(traversal_buf[2], 2);
+ ASSERT_EQ(traversal_buf[3], 3);
+ ASSERT_EQ(traversal_buf[4], 1);
+
+ /* Traversal on NULL node is a no-op */
+ traversal_idx = 0;
+ bintree_traverse(&tt, NULL, BINTREE_INORDER, collect_int);
+ ASSERT_EQ(traversal_idx, 0);
+
+ bintree_destroy(&tt);
+
+ /* Merge */
+ BinTree ml, mr, mm;
+ int mroot = 100, mlv = 10, mrv = 20;
+ bintree_init(&ml, NULL);
+ bintree_init(&mr, NULL);
+ bintree_ins_left(&ml, NULL, &mlv);
+ bintree_ins_left(&mr, NULL, &mrv);
+
+ ASSERT_EQ(bintree_merge(&mm, &ml, &mr, &mroot), 0);
+ ASSERT_EQ(mm.size, 3);
+ ASSERT_EQ(*(int *)mm.root->data, 100);
+ ASSERT_EQ(*(int *)mm.root->left->data, 10);
+ ASSERT_EQ(*(int *)mm.root->right->data, 20);
+ ASSERT_EQ(ml.size, 0);
+ ASSERT_NULL(ml.root);
+ ASSERT_EQ(mr.size, 0);
+ ASSERT_NULL(mr.root);
+ bintree_destroy(&mm);
+
+ /* Merge: left == right should fail */
+ BinTree self;
+ bintree_init(&self, NULL);
+ bintree_ins_left(&self, NULL, &a);
+ BinTree merged;
+ ASSERT_EQ(bintree_merge(&merged, &self, &self, &b), -1);
+ bintree_destroy(&self);
+
+ /* Size tracking through insertions and removals */
+ BinTree st;
+ bintree_init(&st, NULL);
+ ASSERT_EQ(st.size, 0);
+ bintree_ins_left(&st, NULL, &a);
+ ASSERT_EQ(st.size, 1);
+ bintree_ins_left(&st, st.root, &b);
+ ASSERT_EQ(st.size, 2);
+ bintree_ins_right(&st, st.root, &c);
+ ASSERT_EQ(st.size, 3);
+ bintree_rem_right(&st, st.root);
+ ASSERT_EQ(st.size, 2);
+ bintree_destroy(&st);
+
TEST_REPORT();
}
blob - 42b3af2038c8a4078c1f6260551b08f1dd30c637
blob + a7a6a4e8933defb45ed9cdec55444cd752cfc482
--- tests/test_crypto.c
+++ tests/test_crypto.c
#include "lfcrypto.h"
int main() {
- char *in = "BUTT";
- unsigned char *s = b64_encode(in, strlen(in));
- ASSERT_STR_EQ((char *)s, "QlVUVA==");
- free(s);
+ const unsigned char *in = (const unsigned char *)"BUTT";
+ char *cs = b64_encode(in, strlen((const char *)in));
+ ASSERT_STR_EQ(cs, "QlVUVA==");
+ free(cs);
- char *in2 = "a longer base64 test, apparently";
- s = b64_encode(in2, strlen(in2));
- ASSERT_STR_EQ((char *)s, "YSBsb25nZXIgYmFzZTY0IHRlc3QsIGFwcGFyZW50bHk=");
- free(s);
+ const unsigned char *in2 = (const unsigned char *)"a longer base64 test, apparently";
+ cs = b64_encode(in2, strlen((const char *)in2));
+ ASSERT_STR_EQ(cs, "YSBsb25nZXIgYmFzZTY0IHRlc3QsIGFwcGFyZW50bHk=");
+ free(cs);
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);
+ unsigned char *us = b64_decode(out2, strlen(out2), &s_sz);
+ ASSERT_STR_EQ((char *)us, "a longer base64 test, apparently");
+ ASSERT_EQ(strlen((char *)us), s_sz);
+ free(us);
- s = hex_decode("DEADBEEF", &s_sz);
+ us = 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]);
+ ASSERT_EQ(us[i], h[i]);
}
- free(s);
+ free(us);
- s = hex_decode("f00f5", &s_sz);
+ us = 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]);
+ ASSERT_EQ(us[i], h2[i]);
}
- free(s);
+ free(us);
- s = hex_decode("0xf00f5", &s_sz);
+ us = hex_decode("0xf00f5", &s_sz);
for (size_t i = 0; i < 3; ++i) {
- ASSERT_EQ(s[i], h2[i]);
+ ASSERT_EQ(us[i], h2[i]);
}
- free(s);
+ free(us);
char *enc_s = hex_encode(h, 4);
ASSERT_STR_EQ(enc_s, "deadbeef");
unsigned char ua[2] = {0x2, 0xF};
unsigned char ub[2] = {0x4, 0xE};
- unsigned int hamming = hamming_distance(ua, ub, 2);
+ 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);
+ /* -- expanded tests -- */
+
+ /* empty b64 encode/decode */
+ cs = b64_encode((const unsigned char *)"", 0);
+ ASSERT_STR_EQ(cs, "");
+ free(cs);
+
+ us = b64_decode("", 0, &s_sz);
+ ASSERT_EQ(s_sz, (size_t)0);
+ free(us);
+
+ /* empty hex encode */
+ enc_s = hex_encode((const unsigned char *)"", 0);
+ ASSERT_STR_EQ(enc_s, "");
+ free(enc_s);
+
+ /* hex_to_str empty */
+ enc_s = hex_to_str((const unsigned char *)"", 0);
+ ASSERT_STR_EQ(enc_s, "");
+ free(enc_s);
+
+ /* binary roundtrip through hex encode/decode */
+ unsigned char bin[5] = { 0x00, 0xFF, 0x7F, 0x80, 0x01 };
+ enc_s = hex_encode(bin, 5);
+ us = hex_decode(enc_s, &s_sz);
+ ASSERT_EQ(s_sz, (size_t)5);
+ for (size_t i = 0; i < 5; ++i) {
+ ASSERT_EQ(us[i], bin[i]);
+ }
+ free(enc_s);
+ free(us);
+
+ /* hex_decode with NULL sz returns NULL */
+ us = hex_decode("DEADBEEF", NULL);
+ ASSERT_NULL(us);
+
+ /* hex_decode size validation */
+ us = hex_decode("AB", &s_sz);
+ ASSERT_EQ(s_sz, (size_t)1);
+ ASSERT_EQ(us[0], (unsigned char)0xAB);
+ free(us);
+
+ us = hex_decode("ABCD", &s_sz);
+ ASSERT_EQ(s_sz, (size_t)2);
+ free(us);
+
+ /* hamming_distance_s mismatched lengths returns -1 */
+ hamming = hamming_distance_s("short", "longer string");
+ ASSERT_EQ(hamming, -1);
+
+ /* hamming_distance empty strings */
+ hamming = hamming_distance_s("", "");
+ ASSERT_EQ(hamming, 0);
+
+ /* hamming_distance identical strings */
+ hamming = hamming_distance_s("same", "same");
+ ASSERT_EQ(hamming, 0);
+
+ /* repeating_key_xor with zero-length key returns NULL */
+ xor_s = repeating_key_xor((const unsigned char *)"test", 4, (const unsigned char *)"", 0);
+ ASSERT_NULL(xor_s);
+
TEST_REPORT();
}
blob - ff52d5816b27025a8199993784ea05baa32931ad
blob + c4ac31580e34498b9875dd6a0bc03e7a2ec977a5
--- tests/test_linkedlist.c
+++ tests/test_linkedlist.c
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "lftest.h"
#include "lflinkedlist.h"
static int match_int(const void *a, const void *b) {
- return *(const int *)a == *(const int *)b;
+ return *(const int *)a - *(const int *)b;
}
static int cmp_int(const void *a, const void *b) {
}
int main() {
- /* basic insert/remove */
+ /* Basic insertion and size */
List *list = malloc(sizeof(List));
- ll_init(list, NULL);
+ ll_init(list, NULL, NULL);
int i = 1;
int j = 2;
ll_destroy(list);
free(list);
- /* ll_find */
+ /* ll_ins_prev */
list = malloc(sizeof(List));
- ll_init(list, NULL);
- list->match = match_int;
+ ll_init(list, NULL, NULL);
int a = 10, b = 20, c = 30;
- ll_ins_next(list, list->head, &a);
- ll_ins_next(list, list->tail, &b);
- ll_ins_next(list, list->tail, &c);
+ ll_ins_next(list, list->head, &b); /* [20] */
+ ll_ins_prev(list, list->head, &a); /* [10, 20] */
+ ll_ins_next(list, list->tail, &c); /* [10, 20, 30] */
- ListNode *found = ll_find(list, &b);
+ ASSERT_EQ(list->size, 3);
+ ASSERT_EQ(*(int *)list->head->data, 10);
+ ASSERT_EQ(*(int *)list->head->next->data, 20);
+ ASSERT_EQ(*(int *)list->tail->data, 30);
+
+ /* ll_ins_prev into middle */
+ int d = 15;
+ ll_ins_prev(list, list->head->next, &d); /* [10, 15, 20, 30] */
+ ASSERT_EQ(list->size, 4);
+ ASSERT_EQ(*(int *)list->head->next->data, 15);
+
+ ll_destroy(list);
+ free(list);
+
+ /* ll_remove direct */
+ list = malloc(sizeof(List));
+ ll_init(list, NULL, NULL);
+
+ int x = 100, y = 200, z = 300;
+ ll_ins_next(list, list->head, &x);
+ ll_ins_next(list, list->tail, &y);
+ ll_ins_next(list, list->tail, &z);
+
+ /* Remove middle node */
+ ll_remove(list, list->head->next, &data);
+ ASSERT_EQ(*(int *)data, 200);
+ ASSERT_EQ(list->size, 2);
+ ASSERT_EQ(*(int *)list->head->data, 100);
+ ASSERT_EQ(*(int *)list->tail->data, 300);
+
+ /* Remove head */
+ ll_remove(list, list->head, &data);
+ ASSERT_EQ(*(int *)data, 100);
+ ASSERT_EQ(list->size, 1);
+ ASSERT_EQ(*(int *)list->head->data, 300);
+
+ /* Remove tail (last element) */
+ ll_remove(list, list->tail, &data);
+ ASSERT_EQ(*(int *)data, 300);
+ ASSERT_EQ(list->size, 0);
+ ASSERT_NULL(list->head);
+ ASSERT_NULL(list->tail);
+
+ ll_destroy(list);
+ free(list);
+
+ /* ll_remove_prev */
+ list = malloc(sizeof(List));
+ ll_init(list, NULL, NULL);
+
+ int p = 1, q = 2, r = 3;
+ ll_ins_next(list, list->head, &p);
+ ll_ins_next(list, list->tail, &q);
+ ll_ins_next(list, list->tail, &r);
+
+ /* Remove prev of tail (should remove middle) */
+ ll_remove_prev(list, list->tail, &data);
+ ASSERT_EQ(*(int *)data, 2);
+ ASSERT_EQ(list->size, 2);
+
+ /* Remove prev of head should fail */
+ ASSERT_EQ(ll_remove_prev(list, list->head, &data), -1);
+
+ ll_destroy(list);
+ free(list);
+
+ /* ll_remove NULL data pointer */
+ list = malloc(sizeof(List));
+ ll_init(list, NULL, NULL);
+
+ int val = 42;
+ ll_ins_next(list, list->head, &val);
+ ASSERT_EQ(ll_remove(list, list->head, NULL), -1);
+ ASSERT_EQ(list->size, 1);
+
+ ll_destroy(list);
+ free(list);
+
+ /* Destroy callback with free (heap-allocated data) */
+ list = malloc(sizeof(List));
+ ll_init(list, free, NULL);
+
+ for (int n = 0; n < 5; n++) {
+ int *heap_val = malloc(sizeof(int));
+ *heap_val = n * 10;
+ ll_ins_next(list, list->tail, heap_val);
+ }
+ ASSERT_EQ(list->size, 5);
+ ll_destroy(list);
+ ASSERT_EQ(list->size, 0);
+ free(list);
+
+ /* Error paths: NULL node for insert when list non-empty */
+ list = malloc(sizeof(List));
+ ll_init(list, NULL, NULL);
+
+ int e = 1;
+ ll_ins_next(list, list->head, &e);
+ ASSERT_EQ(ll_ins_next(list, NULL, &e), -1);
+ ASSERT_EQ(ll_ins_prev(list, NULL, &e), -1);
+
+ /* Error paths: remove from empty list */
+ List *empty = malloc(sizeof(List));
+ ll_init(empty, NULL, NULL);
+ ASSERT_EQ(ll_remove(empty, NULL, &data), -1);
+ ASSERT_EQ(ll_remove_next(empty, NULL, &data), -1);
+ ASSERT_EQ(ll_remove_prev(empty, NULL, &data), -1);
+ free(empty);
+
+ ll_destroy(list);
+ free(list);
+
+ /* ll_find with match callback */
+ list = malloc(sizeof(List));
+ ll_init(list, NULL, match_int);
+
+ int f1 = 10, f2 = 20, f3 = 30;
+ ll_ins_next(list, list->head, &f1);
+ ll_ins_next(list, list->tail, &f2);
+ ll_ins_next(list, list->tail, &f3);
+
+ int search = 20;
+ ListNode *found = ll_find(list, &search);
ASSERT_NOT_NULL(found);
ASSERT_EQ(*(int *)found->data, 20);
int missing = 99;
- found = ll_find(list, &missing);
- ASSERT_NULL(found);
+ ASSERT_NULL(ll_find(list, &missing));
- /* ll_find with no match callback */
+ /* ll_find with NULL match (pointer comparison) */
list->match = NULL;
- found = ll_find(list, &a);
- ASSERT_NULL(found);
- list->match = match_int;
+ found = ll_find(list, &f2);
+ ASSERT_NOT_NULL(found);
+ ASSERT_EQ(*(int *)found->data, 20);
+ ASSERT_NULL(ll_find(list, &missing));
+ ASSERT_NULL(ll_find(NULL, &search));
+
+ ll_destroy(list);
+ free(list);
+
/* ll_reverse */
+ list = malloc(sizeof(List));
+ ll_init(list, NULL, NULL);
+
+ int ra = 10, rb = 20, rc = 30;
+ ll_ins_next(list, list->head, &ra);
+ ll_ins_next(list, list->tail, &rb);
+ ll_ins_next(list, list->tail, &rc);
+
ll_reverse(list);
ASSERT_EQ(*(int *)list->head->data, 30);
ASSERT_EQ(*(int *)list->tail->data, 10);
ASSERT_EQ(*(int *)node->data, expected_fwd[idx++]);
}
- /* ll_to_array */
- void **arr = ll_to_array(list);
- ASSERT_NOT_NULL(arr);
- ASSERT_EQ(*(int *)arr[0], 30);
- ASSERT_EQ(*(int *)arr[1], 20);
- ASSERT_EQ(*(int *)arr[2], 10);
- free(arr);
-
ll_destroy(list);
free(list);
/* ll_sort */
list = malloc(sizeof(List));
- ll_init(list, NULL);
+ ll_init(list, NULL, NULL);
int s1 = 3, s2 = 1, s3 = 5, s4 = 2, s5 = 4;
ll_ins_next(list, list->head, &s1);
/* sort empty and single-element lists */
ll_destroy(list);
- ll_init(list, NULL);
+ ll_init(list, NULL, NULL);
ll_sort(list, cmp_int);
ASSERT_EQ(list->size, 0);
ASSERT_EQ(list->size, 1);
ASSERT_EQ(*(int *)list->head->data, 42);
- /* ll_to_array on empty list */
ll_destroy(list);
- ll_init(list, NULL);
+ free(list);
+
+ /* ll_to_array: single element */
+ list = malloc(sizeof(List));
+ ll_init(list, NULL, NULL);
+
+ int single = 42;
+ ll_ins_next(list, list->head, &single);
+
+ void **arr = ll_to_array(list);
+ ASSERT_NOT_NULL(arr);
+ ASSERT_EQ(*(int *)arr[0], 42);
+ free(arr);
+
+ ll_destroy(list);
+ free(list);
+
+ /* ll_to_array: empty list */
+ list = malloc(sizeof(List));
+ ll_init(list, NULL, NULL);
+ ASSERT_NULL(ll_to_array(list));
+ ASSERT_NULL(ll_to_array(NULL));
+ ll_destroy(list);
+ free(list);
+
+ /* ll_to_array: multiple elements */
+ list = malloc(sizeof(List));
+ ll_init(list, NULL, NULL);
+
+ int m1 = 1, m2 = 2, m3 = 3;
+ ll_ins_next(list, list->head, &m1);
+ ll_ins_next(list, list->tail, &m2);
+ ll_ins_next(list, list->tail, &m3);
+
arr = ll_to_array(list);
- ASSERT_NULL(arr);
+ ASSERT_NOT_NULL(arr);
+ ASSERT_EQ(*(int *)arr[0], 1);
+ ASSERT_EQ(*(int *)arr[1], 2);
+ ASSERT_EQ(*(int *)arr[2], 3);
+ free(arr);
ll_destroy(list);
free(list);
blob - /dev/null
blob + ba4d898681161690dee7dbb49800e4f0771585a7 (mode 644)
--- /dev/null
+++ tests/test_input.c
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lftest.h"
+#include "lfinput.h"
+
+static void test_split_basic(void) {
+ char *s = strdup("one,two,three");
+ size_t n = 0;
+ char **parts = inp_split(s, &n, ",");
+ ASSERT_NOT_NULL(parts);
+ ASSERT_EQ(n, 3);
+ ASSERT_STR_EQ(parts[0], "one");
+ ASSERT_STR_EQ(parts[1], "two");
+ ASSERT_STR_EQ(parts[2], "three");
+ inp_del_split(parts);
+ free(s);
+}
+
+static void test_split_single(void) {
+ char *s = strdup("hello");
+ size_t n = 0;
+ char **parts = inp_split(s, &n, ",");
+ ASSERT_NOT_NULL(parts);
+ ASSERT_EQ(n, 1);
+ ASSERT_STR_EQ(parts[0], "hello");
+ inp_del_split(parts);
+ free(s);
+}
+
+static void test_split_null(void) {
+ size_t n = 0;
+ ASSERT_NULL(inp_split(NULL, &n, ","));
+ char *s = strdup("a,b");
+ ASSERT_NULL(inp_split(s, NULL, ","));
+ free(s);
+ s = strdup("a,b");
+ ASSERT_NULL(inp_split(s, &n, NULL));
+ free(s);
+}
+
+static void test_del_split_null(void) {
+ inp_del_split(NULL); /* should not crash */
+}
+
+static void test_del_lines_null(void) {
+ inp_del_lines(NULL); /* should not crash */
+}
+
+static void test_capture_system(void) {
+ char *out = inp_capture_system("echo hello", 0);
+ ASSERT_NOT_NULL(out);
+ ASSERT_STR_EQ(out, "hello\n");
+ free(out);
+}
+
+static void test_capture_system_null(void) {
+ ASSERT_NULL(inp_capture_system(NULL, 0));
+}
+
+static void test_capture_system_large(void) {
+ /* Generate output larger than the default buffer size */
+ char *out = inp_capture_system("seq 1 1000", 32);
+ ASSERT_NOT_NULL(out);
+ /* Check it contains the last line */
+ ASSERT_TRUE(strstr(out, "1000") != NULL);
+ free(out);
+}
+
+static void test_file_roundtrip(void) {
+ /* Write a temp file, read it back */
+ const char *tmppath = "/tmp/libflint_test_input.txt";
+ FILE *f = fopen(tmppath, "w");
+ ASSERT_NOT_NULL(f);
+ fprintf(f, "line1\nline2\nline3\n");
+ fclose(f);
+
+ char *contents = inp_get_input(tmppath);
+ ASSERT_NOT_NULL(contents);
+ ASSERT_STR_EQ(contents, "line1\nline2\nline3\n");
+ free(contents);
+
+ size_t n = 0;
+ char **lines = inp_get_lines(tmppath, &n);
+ ASSERT_NOT_NULL(lines);
+ ASSERT_EQ(n, 3);
+ ASSERT_STR_EQ(lines[0], "line1");
+ ASSERT_STR_EQ(lines[1], "line2");
+ ASSERT_STR_EQ(lines[2], "line3");
+ inp_del_lines(lines);
+
+ remove(tmppath);
+}
+
+static void test_get_binary(void) {
+ const char *tmppath = "/tmp/libflint_test_input.bin";
+ FILE *f = fopen(tmppath, "wb");
+ ASSERT_NOT_NULL(f);
+ unsigned char data[] = {0x00, 0x01, 0x02, 0xFF};
+ fwrite(data, 1, sizeof(data), f);
+ fclose(f);
+
+ size_t fsz = 0;
+ unsigned char *buf = inp_get_binary(tmppath, &fsz);
+ ASSERT_NOT_NULL(buf);
+ ASSERT_EQ(fsz, 4);
+ ASSERT_EQ(buf[0], 0x00);
+ ASSERT_EQ(buf[3], 0xFF);
+ free(buf);
+
+ remove(tmppath);
+}
+
+static void test_get_ints(void) {
+ const char *tmppath = "/tmp/libflint_test_ints.txt";
+ FILE *f = fopen(tmppath, "w");
+ ASSERT_NOT_NULL(f);
+ fprintf(f, "10\n20\n30\n");
+ fclose(f);
+
+ size_t n = 0;
+ int *ints = inp_get_ints(tmppath, &n);
+ ASSERT_NOT_NULL(ints);
+ ASSERT_EQ(n, 3);
+ ASSERT_EQ(ints[0], 10);
+ ASSERT_EQ(ints[1], 20);
+ ASSERT_EQ(ints[2], 30);
+ free(ints);
+
+ remove(tmppath);
+}
+
+static void test_get_ints_null(void) {
+ size_t n = 0;
+ ASSERT_NULL(inp_get_ints(NULL, &n));
+ ASSERT_NULL(inp_get_ints("/tmp/nonexistent_libflint", NULL));
+}
+
+int main(void) {
+ test_split_basic();
+ test_split_single();
+ test_split_null();
+ test_del_split_null();
+ test_del_lines_null();
+ test_capture_system();
+ test_capture_system_null();
+ test_capture_system_large();
+ test_file_roundtrip();
+ test_get_binary();
+ test_get_ints();
+ test_get_ints_null();
+
+ TEST_REPORT();
+}
blob - 48c994ca9950ca8f7a752bc05da4cd93b1d76514
blob + 262b329f842039d67b578681399b563fef392c93
--- tests/test_macos.c
+++ tests/test_macos.c
int main() {
pid_t pid = getpid();
+
+ /* new_ProcessData returns zeroed memory with sentinel */
ProcessData *pd = new_ProcessData();
ASSERT_NOT_NULL(pd);
+ ASSERT_EQ(pd->percent_cpu, 0.0);
+ ASSERT_EQ(pd->virtual_memory, 0);
+ ASSERT_EQ(pd->resident_memory, 0);
+ ASSERT_EQ(pd->total_user_time, 0.0);
+ ASSERT_EQ(pd->total_kernel_time, 0.0);
- for (int i = 0; i < 2; i++) {
- update_process(pid, pd);
- sleep(1);
- }
+ /* first update succeeds and populates fields */
+ int rc = update_process(pid, pd);
+ ASSERT_EQ(rc, 0);
+ ASSERT_TRUE(pd->resident_memory > 0);
+ ASSERT_TRUE(pd->virtual_memory > 0);
+ ASSERT_TRUE(pd->percent_cpu == 0.0);
+
+ sleep(1);
+
+ /* second update succeeds */
+ rc = update_process(pid, pd);
+ ASSERT_EQ(rc, 0);
ASSERT_TRUE(pd->percent_cpu >= 0.0);
- free(pd);
+ /* error path: invalid PID returns -1 */
+ rc = update_process(-1, pd);
+ ASSERT_EQ(rc, -1);
+
+ destroy_ProcessData(pd);
+
+ /* destroy_ProcessData handles NULL safely */
+ destroy_ProcessData(NULL);
+
TEST_REPORT();
}
#else
blob - 50629b4a980d0cab64d560728ae38875b324dfb6
blob + b55e738cf14edadb083270493ac21260e5cddfd6
--- tests/test_math.c
+++ tests/test_math.c
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#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);
-
/* abs_int */
ASSERT_EQ(abs_int(5), 5);
ASSERT_EQ(abs_int(-5), 5);
ASSERT_EQ(abs_int(0), 0);
+ ASSERT_EQ(abs_int(INT_MIN), INT_MAX);
+ /* max/min */
+ ASSERT_EQ(max_int(1, 2), 2);
+ ASSERT_EQ(min_int(1, 2), 1);
+
+ /* binstr_to_int */
+ ASSERT_EQ(binstr_to_int("10101101"), 173);
+ ASSERT_EQ(binstr_to_int("1010_1101"), 173);
+ ASSERT_EQ(binstr_to_int(NULL), -1);
+
+ /* clamp_int - all branches */
+ ASSERT_EQ(clamp_int(10, 2, 5), 5); /* above high */
+ ASSERT_EQ(clamp_int(1, 2, 5), 2); /* below low */
+ ASSERT_EQ(clamp_int(3, 2, 5), 3); /* in range */
+ ASSERT_EQ(clamp_int(3, 5, 2), 3); /* low > high, swap */
+ ASSERT_EQ(clamp_int(10, 5, 2), 5); /* low > high, above */
+
+ /* is_power_of_two */
+ ASSERT_TRUE(is_power_of_two(1));
+ ASSERT_TRUE(is_power_of_two(2));
+ ASSERT_TRUE(is_power_of_two(4));
+ ASSERT_TRUE(is_power_of_two(1024));
+ ASSERT_FALSE(is_power_of_two(0));
+ ASSERT_FALSE(is_power_of_two(3));
+ ASSERT_FALSE(is_power_of_two(-1));
+
/* gcd */
ASSERT_EQ(gcd(12, 8), 4);
ASSERT_EQ(gcd(7, 13), 1);
ASSERT_EQ(isqrt(100), 10);
ASSERT_EQ(isqrt(-1), -1);
+ /* bresenham coordinate verification */
size_t sz = 0;
Point *line = bresenham(0, 0, 2, 5, &sz);
+ ASSERT_NOT_NULL(line);
ASSERT_TRUE(sz > 0);
+ /* first point */
+ ASSERT_EQ(line[0].x, 0);
+ ASSERT_EQ(line[0].y, 0);
+ /* last point */
+ ASSERT_EQ(line[sz - 1].x, 2);
+ ASSERT_EQ(line[sz - 1].y, 5);
+ free(line);
+
+ /* bresenham single point */
+ line = bresenham(3, 3, 3, 3, &sz);
ASSERT_NOT_NULL(line);
+ ASSERT_EQ(sz, 1);
+ ASSERT_EQ(line[0].x, 3);
+ ASSERT_EQ(line[0].y, 3);
free(line);
+ /* bresenham_p */
+ Point p1 = Point_new(0, 0);
+ Point p2 = Point_new(4, 0);
+ line = bresenham_p(p1, p2, &sz);
+ ASSERT_NOT_NULL(line);
+ ASSERT_EQ(sz, 5);
+ ASSERT_EQ(line[0].x, 0);
+ ASSERT_EQ(line[4].x, 4);
+ free(line);
+
TEST_REPORT();
}
blob - 6fc0580bc98896e1b56234a8c7a163f12e7c9289
blob + 43153093ad2f9e586c56f012db8fb3943526d80a
--- tests/test_memory.c
+++ tests/test_memory.c
int main() {
ArenaAllocator *arena = malloc(sizeof(ArenaAllocator));
- arena_init(arena, 1024);
+ ASSERT_EQ(arena_init(arena, 1024), 0);
int *i1 = arena_malloc(arena, sizeof(int));
int *i2 = arena_malloc(arena, sizeof(int));
ASSERT_NOT_NULL(after_clear);
/* Test arena_resize_buf */
- arena_resize_buf(arena, 2048);
+ ASSERT_EQ(arena_resize_buf(arena, 2048), 0);
void *big_alloc = arena_malloc(arena, 1500);
ASSERT_NOT_NULL(big_alloc);
+ /* Test arena_resize_buf rejects shrink below offset_cur */
+ ASSERT_EQ(arena_resize_buf(arena, 1), -1);
+
+ /* Test arena_init returns -1 for NULL */
+ ASSERT_EQ(arena_init(NULL, 64), -1);
+
arena_free(arena);
free(arena);
/* Test stack-allocated arena */
ArenaAllocator stack_arena;
- arena_init(&stack_arena, 256);
+ ASSERT_EQ(arena_init(&stack_arena, 256), 0);
int *si = arena_malloc(&stack_arena, sizeof(int));
ASSERT_NOT_NULL(si);
*si = 99;
ASSERT_EQ(*si, 99);
arena_free(&stack_arena);
+ /* Pool tests */
PoolAllocator *pool = malloc(sizeof(PoolAllocator));
- pool_init(pool, 64, 16, LF_DEFAULT_ALIGNMENT);
+ ASSERT_EQ(pool_init(pool, 64, 16, LF_DEFAULT_ALIGNMENT), 0);
void *a = pool_alloc(pool);
void *b = pool_alloc(pool);
void *c = pool_alloc(pool);
/* Test pool_free_all resets properly */
pool_free_all(pool);
- size_t chunk_count = 64 / 16;
+ size_t chunk_count = pool->buf_sz / pool->chunk_size;
ASSERT_EQ(pool_count_available(pool), chunk_count);
/* Allocate again after free_all to verify no corruption */
ASSERT_NOT_NULL(b);
pool_destroy(pool);
+ free(pool);
+ /* Pool exhaustion: allocating more chunks than capacity returns NULL */
+ PoolAllocator pool_ex;
+ ASSERT_EQ(pool_init(&pool_ex, 64, 16, LF_DEFAULT_ALIGNMENT), 0);
+ size_t ex_count = pool_ex.buf_sz / pool_ex.chunk_size;
+ for (size_t i = 0; i < ex_count; ++i) {
+ ASSERT_NOT_NULL(pool_alloc(&pool_ex));
+ }
+ ASSERT_NULL(pool_alloc(&pool_ex));
+ pool_destroy(&pool_ex);
+
+ /* Pool free with bad pointers (outside buffer range) */
+ PoolAllocator pool_bad;
+ ASSERT_EQ(pool_init(&pool_bad, 64, 16, LF_DEFAULT_ALIGNMENT), 0);
+ size_t before = pool_count_available(&pool_bad);
+ int dummy = 0;
+ pool_free(&pool_bad, &dummy); /* pointer outside pool */
+ pool_free(&pool_bad, NULL); /* NULL pointer */
+ ASSERT_EQ(pool_count_available(&pool_bad), before); /* count unchanged */
+ pool_destroy(&pool_bad);
+
+ /* Pool free + realloc cycle */
+ PoolAllocator pool_cycle;
+ ASSERT_EQ(pool_init(&pool_cycle, 64, 16, LF_DEFAULT_ALIGNMENT), 0);
+ /* drain all chunks first */
+ size_t cycle_count = pool_cycle.buf_sz / pool_cycle.chunk_size;
+ for (size_t i = 0; i < cycle_count; ++i) {
+ pool_alloc(&pool_cycle);
+ }
+ ASSERT_EQ(pool_count_available(&pool_cycle), 0);
+ /* free one, then alloc -- must get it back */
+ void *p1 = &pool_cycle.buf[pool_cycle.aligned_start]; /* first chunk addr */
+ pool_free(&pool_cycle, p1);
+ void *p2 = pool_alloc(&pool_cycle);
+ ASSERT_NOT_NULL(p2);
+ ASSERT_EQ(p1, p2); /* should reuse the freed chunk */
+ pool_destroy(&pool_cycle);
+
+ /* Pool init with bad params */
+ PoolAllocator pool_bp;
+ ASSERT_EQ(pool_init(&pool_bp, 4, 16, LF_DEFAULT_ALIGNMENT), -1); /* buf too small */
+ ASSERT_EQ(pool_init(NULL, 64, 16, LF_DEFAULT_ALIGNMENT), -1); /* NULL allocator */
+
/* arena save/restore */
ArenaAllocator save_arena;
arena_init(&save_arena, 512);
blob - 9fa89c42d0b00b733699a8d0ad057431232d3eda
blob + b1c95cf8ed22b0e2919ac7558c9b4e65077c41cf
--- tests/test_network.c
+++ tests/test_network.c
return NULL;
}
+static void dummy_handler(Server *s) {
+ (void)s;
+}
+
int main() {
+ /* Test new_server with bad port returns NULL */
+ Server *bad = new_server(SERVERTYPE_TCP, "notaport", dummy_handler);
+ ASSERT_NULL(bad);
+
+ /* Test new_server creates valid TCP server and delete_server cleans up */
+ Server *tcp = new_server(SERVERTYPE_TCP, "18640", dummy_handler);
+ ASSERT_NOT_NULL(tcp);
+ ASSERT_EQ(tcp->server_type, SERVERTYPE_TCP);
+ ASSERT_EQ(tcp->port, 18640);
+ ASSERT_TRUE(tcp->fd >= 0);
+ delete_server(tcp);
+
+ /* Test new_server creates valid UDP server and delete_server cleans up */
+ Server *udp = new_server(SERVERTYPE_UDP, "18641", dummy_handler);
+ ASSERT_NOT_NULL(udp);
+ ASSERT_EQ(udp->server_type, SERVERTYPE_UDP);
+ ASSERT_EQ(udp->port, 18641);
+ ASSERT_TRUE(udp->fd >= 0);
+ delete_server(udp);
+
+ /* Test delete_server with NULL doesn't crash */
+ delete_server(NULL);
+
+ /* TCP echo test */
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);
+ char *s = inp_capture_system("echo hello | nc localhost 18632", 0);
ASSERT_STR_EQ(s, NET_MSG);
- free((char *) s);
+ free(s);
pthread_join(srv_tid, NULL);
+ /* UDP test */
pthread_create(&srv_tid, NULL, udp_server_thread, NULL);
sleep(1);
system("echo hello | nc localhost 18633");
blob - 57abe442572fbbbc6526d2271a7729463d8b5d61
blob + 6247350fe666d76a5521f0f7b9a2cbae9382810c
--- tests/test_parsing.c
+++ tests/test_parsing.c
char *english = "This is an English sentence!";
ASSERT_TRUE(simple_english_scoring(english) > simple_english_scoring(nonsense));
+ /* NULL input */
+ ASSERT_EQ(simple_english_scoring(NULL), -1);
+
+ /* empty string */
+ ASSERT_EQ(simple_english_scoring(""), 0);
+
+ /* known absolute score: "the" = t(12) + h(5) + e(13) = 30 */
+ ASSERT_EQ(simple_english_scoring("the"), 30);
+
+ /* single space scores 7 */
+ ASSERT_EQ(simple_english_scoring(" "), 7);
+
+ /* unknown chars score 0 */
+ ASSERT_EQ(simple_english_scoring("!!!"), 0);
+
TEST_REPORT();
}
blob - 89facce7f60029c4e811cf64a51698d0f9ac07fc
blob + 9006ae42082a6ff913cb0eee7cc7faaa21748fe8
--- tests/test_queue.c
+++ tests/test_queue.c
#include "lftest.h"
#include "lfqueue.h"
+static int destroyed_count;
+
+static void counting_destroy(void *data) {
+ (void)data;
+ destroyed_count++;
+}
+
int main() {
+ /* basic enqueue/dequeue FIFO */
Queue *q = malloc(sizeof(Queue));
queue_init(q, NULL);
queue_enqueue(q, &a);
queue_enqueue(q, &b);
queue_enqueue(q, &c);
- ASSERT_EQ(q->size, 3);
+ ASSERT_EQ(queue_size(q), 3);
+ ASSERT_FALSE(queue_is_empty(q));
- /* peek returns front without removing */
int *p = queue_peek(q);
ASSERT_EQ(*p, 1);
- ASSERT_EQ(q->size, 3);
+ ASSERT_EQ(queue_size(q), 3);
- /* FIFO order */
queue_dequeue(q, (void **)&p);
ASSERT_EQ(*p, 1);
queue_dequeue(q, (void **)&p);
ASSERT_EQ(*p, 2);
queue_dequeue(q, (void **)&p);
ASSERT_EQ(*p, 3);
- ASSERT_EQ(q->size, 0);
+ ASSERT_EQ(queue_size(q), 0);
+ ASSERT_TRUE(queue_is_empty(q));
/* peek on empty queue */
p = queue_peek(q);
ASSERT_NULL(p);
- /* dequeue on empty queue */
+ /* dequeue on empty queue returns -1 */
int ret = queue_dequeue(q, (void **)&p);
ASSERT_EQ(ret, -1);
queue_destroy(q);
free(q);
+ /* return values from enqueue/dequeue */
+ q = malloc(sizeof(Queue));
+ queue_init(q, NULL);
+
+ ret = queue_enqueue(q, &a);
+ ASSERT_EQ(ret, 0);
+ ret = queue_dequeue(q, (void **)&p);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(*p, 1);
+
+ queue_destroy(q);
+ free(q);
+
+ /* destroy callback */
+ q = malloc(sizeof(Queue));
+ destroyed_count = 0;
+ queue_init(q, counting_destroy);
+
+ int *d1 = malloc(sizeof(int));
+ int *d2 = malloc(sizeof(int));
+ *d1 = 10; *d2 = 20;
+ queue_enqueue(q, d1);
+ queue_enqueue(q, d2);
+
+ queue_destroy(q);
+ ASSERT_EQ(destroyed_count, 2);
+ free(d1); free(d2);
+ free(q);
+
+ /* enqueue after drain */
+ q = malloc(sizeof(Queue));
+ queue_init(q, NULL);
+
+ queue_enqueue(q, &a);
+ queue_dequeue(q, (void **)&p);
+ ASSERT_TRUE(queue_is_empty(q));
+
+ queue_enqueue(q, &b);
+ ASSERT_EQ(queue_size(q), 1);
+ p = queue_peek(q);
+ ASSERT_EQ(*p, 2);
+
+ queue_dequeue(q, (void **)&p);
+ ASSERT_EQ(*p, 2);
+ ASSERT_TRUE(queue_is_empty(q));
+
+ queue_destroy(q);
+ free(q);
+
+ /* single-element operations */
+ q = malloc(sizeof(Queue));
+ queue_init(q, NULL);
+
+ int v = 77;
+ queue_enqueue(q, &v);
+ ASSERT_EQ(queue_size(q), 1);
+
+ p = queue_peek(q);
+ ASSERT_EQ(*p, 77);
+
+ ret = queue_dequeue(q, (void **)&p);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(*p, 77);
+ ASSERT_TRUE(queue_is_empty(q));
+
+ queue_destroy(q);
+ free(q);
+
TEST_REPORT();
}
blob - 278cc30436e944c2424022d7e15b7ed2b6d3e657
blob + 894da44be9bdb69a88e1342314d9b31fa360dc48
--- tests/test_set.c
+++ tests/test_set.c
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "lftest.h"
#include "lfset.h"
static int int_match(const void *a, const void *b) {
- return *((int *) a) == *((int *) b);
+ return *(const int *)a - *(const int *)b;
}
+static void free_data(void *data) {
+ free(data);
+}
+
int main() {
+ /* Basic insert and duplicate rejection */
Set *set = malloc(sizeof(Set));
set_init(set, int_match, NULL);
int j = 2;
int k = 2;
- set_insert(set, &i);
+ ASSERT_EQ(set_insert(set, &i), 0);
+ ASSERT_EQ(set_insert(set, &j), 0);
+ ASSERT_EQ(set_insert(set, &k), 1); /* duplicate returns 1 */
+
+ ASSERT_EQ(set_size(set), 2);
+
+ /* set_is_member */
+ ASSERT_TRUE(set_is_member(set, &i));
+ ASSERT_TRUE(set_is_member(set, &j));
+ int missing = 99;
+ ASSERT_FALSE(set_is_member(set, &missing));
+
+ /* set_remove */
+ void *removed = &j;
+ ASSERT_EQ(set_remove(set, &removed), 0);
+ ASSERT_EQ(set_size(set), 1);
+ ASSERT_FALSE(set_is_member(set, &j));
+
+ /* set_remove: not found */
+ removed = &missing;
+ ASSERT_EQ(set_remove(set, &removed), -1);
+
+ /* set_remove: NULL data pointer */
+ ASSERT_EQ(set_remove(set, NULL), -1);
+
+ /* Re-insert removed element for set operations */
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_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} */
+ ASSERT_EQ(set_size(set_u), 3); /* {1, 2, 4} */
+ ASSERT_EQ(set_size(set_d), 1); /* {2} */
+ ASSERT_EQ(set_size(set_i), 1); /* {1} */
+ /* set_is_subset */
+ Set *sub = malloc(sizeof(Set));
+ set_init(sub, int_match, NULL);
+ set_insert(sub, &i); /* {1} is subset of {1, 2} */
+ ASSERT_TRUE(set_is_subset(sub, set));
+ ASSERT_FALSE(set_is_subset(set, sub));
+
+ /* set_is_equal */
+ Set *eq = malloc(sizeof(Set));
+ set_init(eq, int_match, NULL);
+ set_insert(eq, &i);
+ set_insert(eq, &j);
+ ASSERT_TRUE(set_is_equal(set, eq));
+ ASSERT_FALSE(set_is_equal(set, sub));
+
set_destroy(set);
set_destroy(set2);
set_destroy(set_u);
set_destroy(set_i);
set_destroy(set_d);
+ set_destroy(sub);
+ set_destroy(eq);
free(set);
free(set2);
free(set_u);
free(set_i);
free(set_d);
+ free(sub);
+ free(eq);
+ /* Heap-allocated data with destroy callback */
+ Set *hset = malloc(sizeof(Set));
+ set_init(hset, int_match, free_data);
+
+ int *a = malloc(sizeof(int)); *a = 10;
+ int *b = malloc(sizeof(int)); *b = 20;
+ int *c = malloc(sizeof(int)); *c = 10; /* duplicate value */
+
+ ASSERT_EQ(set_insert(hset, a), 0);
+ ASSERT_EQ(set_insert(hset, b), 0);
+ ASSERT_EQ(set_insert(hset, c), 1); /* duplicate */
+ free(c); /* caller responsible for rejected data */
+
+ ASSERT_EQ(set_size(hset), 2);
+ ASSERT_TRUE(set_is_member(hset, a));
+ ASSERT_TRUE(set_is_member(hset, b));
+
+ /* destroy frees heap data */
+ set_destroy(hset);
+ free(hset);
+
TEST_REPORT();
}
blob - ae60a2174307462510938d3759e5dd662d312bdf
blob + 0ef2e1eef7f25d0c07f3de0074bcfb23e14e4da0
--- tests/test_stack.c
+++ tests/test_stack.c
#include "lftest.h"
#include "lfstack.h"
+static int destroyed_count;
+
+static void counting_destroy(void *data) {
+ (void)data;
+ destroyed_count++;
+}
+
int main() {
+ /* basic push/pop */
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);
+ ASSERT_EQ(stack_size(stack), 2);
+ ASSERT_FALSE(stack_is_empty(stack));
int *p = NULL;
- stack_pop(stack, (void **) &p);
+ stack_pop(stack, (void **)&p);
ASSERT_EQ(*p, 2);
- stack_pop(stack, (void **) &p);
+ stack_pop(stack, (void **)&p);
ASSERT_EQ(*p, 1);
- ASSERT_EQ(stack->size, 0);
+ ASSERT_EQ(stack_size(stack), 0);
+ ASSERT_TRUE(stack_is_empty(stack));
stack_destroy(stack);
free(stack);
+ /* peek */
+ stack = malloc(sizeof(Stack));
+ stack_init(stack, NULL);
+
+ ASSERT_NULL(stack_peek(stack));
+
+ int x = 42;
+ stack_push(stack, &x);
+ p = stack_peek(stack);
+ ASSERT_NOT_NULL(p);
+ ASSERT_EQ(*p, 42);
+ ASSERT_EQ(stack_size(stack), 1);
+
+ stack_destroy(stack);
+ free(stack);
+
+ /* empty pop returns -1 */
+ stack = malloc(sizeof(Stack));
+ stack_init(stack, NULL);
+
+ int ret = stack_pop(stack, (void **)&p);
+ ASSERT_EQ(ret, -1);
+
+ stack_destroy(stack);
+ free(stack);
+
+ /* return values from push/pop */
+ stack = malloc(sizeof(Stack));
+ stack_init(stack, NULL);
+
+ ret = stack_push(stack, &a);
+ ASSERT_EQ(ret, 0);
+ ret = stack_pop(stack, (void **)&p);
+ ASSERT_EQ(ret, 0);
+
+ stack_destroy(stack);
+ free(stack);
+
+ /* destroy callback */
+ stack = malloc(sizeof(Stack));
+ destroyed_count = 0;
+ stack_init(stack, counting_destroy);
+
+ int *d1 = malloc(sizeof(int));
+ int *d2 = malloc(sizeof(int));
+ int *d3 = malloc(sizeof(int));
+ *d1 = 10; *d2 = 20; *d3 = 30;
+ stack_push(stack, d1);
+ stack_push(stack, d2);
+ stack_push(stack, d3);
+
+ stack_destroy(stack);
+ ASSERT_EQ(destroyed_count, 3);
+ free(d1); free(d2); free(d3);
+ free(stack);
+
+ /* single-element push and pop */
+ stack = malloc(sizeof(Stack));
+ stack_init(stack, NULL);
+
+ int v = 99;
+ stack_push(stack, &v);
+ ASSERT_EQ(stack_size(stack), 1);
+
+ p = stack_peek(stack);
+ ASSERT_EQ(*p, 99);
+
+ ret = stack_pop(stack, (void **)&p);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(*p, 99);
+ ASSERT_TRUE(stack_is_empty(stack));
+
+ stack_destroy(stack);
+ free(stack);
+
TEST_REPORT();
}
blob - 8e29b506d9e134285c55909bb2bf72a0651d9280
blob + 3f0b829a6caea9cf9d0e8fbca2ddd54a7a8e8740
--- tests/test_string.c
+++ tests/test_string.c
#include "lfstring.h"
int main() {
- /* existing find_substrings tests */
+ /* str_find tests */
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[] = {
size_t sub_sz = 0;
size_t *subs = NULL;
- find_substrings(haystack, needles[0], &sub_sz, &subs);
+ str_find(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]));
+ char *s = str_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);
+ str_find(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);
+ str_find("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);
+ str_find("123", "nopes", &sub_sz, &subs);
ASSERT_EQ(sub_sz, 0);
ASSERT_NULL(subs);
free(subs);
subs = NULL;
+ /* str_find: empty needle matches every position */
+ str_find("abc", "", &sub_sz, &subs);
+ ASSERT_EQ(sub_sz, 4);
+ free(subs);
+ subs = NULL;
+
+ /* str_find: empty haystack with empty needle */
+ str_find("", "", &sub_sz, &subs);
+ ASSERT_EQ(sub_sz, 1);
+ free(subs);
+ subs = NULL;
+
+ /* str_find: empty haystack with non-empty needle */
+ str_find("", "abc", &sub_sz, &subs);
+ ASSERT_EQ(sub_sz, 0);
+ ASSERT_NULL(subs);
+ subs = NULL;
+
+ /* str_substr edge cases */
+ s = str_substr("hello", 0, 5);
+ ASSERT_STR_EQ(s, "hello");
+ free(s);
+
+ s = str_substr("hello", 0, 0);
+ ASSERT_STR_EQ(s, "");
+ free(s);
+
+ s = str_substr("hello", 5, 0);
+ ASSERT_STR_EQ(s, "");
+ free(s);
+
+ s = str_substr("hello", 4, 1);
+ ASSERT_STR_EQ(s, "o");
+ free(s);
+
+ /* substr beyond bounds */
+ s = str_substr("hello", 3, 5);
+ ASSERT_NULL(s);
+
+ s = str_substr("hello", 0, 6);
+ ASSERT_NULL(s);
+
/* str_trim */
s = str_trim(" hello world ");
ASSERT_STR_EQ(s, "hello world");
ASSERT_STR_EQ(s, "hi");
free(s);
+ s = str_trim("");
+ ASSERT_STR_EQ(s, "");
+ free(s);
+
/* str_join */
const char *parts[] = {"foo", "bar", "baz"};
s = str_join(parts, 3, ", ");
ASSERT_TRUE(str_starts_with("hello", "hello"));
ASSERT_FALSE(str_starts_with("hello", "world"));
ASSERT_TRUE(str_starts_with("hello", ""));
+ ASSERT_TRUE(str_starts_with("", ""));
+ ASSERT_FALSE(str_starts_with("", "a"));
/* str_ends_with */
ASSERT_TRUE(str_ends_with("hello world", "world"));
ASSERT_FALSE(str_ends_with("hello", "world"));
ASSERT_TRUE(str_ends_with("hello", ""));
ASSERT_FALSE(str_ends_with("hi", "longer"));
+ ASSERT_TRUE(str_ends_with("", ""));
+ ASSERT_FALSE(str_ends_with("", "a"));
/* str_replace */
s = str_replace("foo bar foo baz foo", "foo", "qux");
ASSERT_STR_EQ(s, "");
free(s);
+ /* str_replace with empty old string returns copy */
+ s = str_replace("hello", "", "X");
+ ASSERT_STR_EQ(s, "hello");
+ free(s);
+
+ /* str_replace on empty input */
+ s = str_replace("", "a", "b");
+ ASSERT_STR_EQ(s, "");
+ free(s);
+
/* str_to_upper / str_to_lower */
s = str_to_upper("hello World 123");
ASSERT_STR_EQ(s, "HELLO WORLD 123");
ASSERT_STR_EQ(s, "hello world 123");
free(s);
+ s = str_to_upper("");
+ ASSERT_STR_EQ(s, "");
+ free(s);
+
+ s = str_to_lower("");
+ ASSERT_STR_EQ(s, "");
+ free(s);
+
+ /* str_split */
+ int count = 0;
+ char **split = str_split("foo,bar,baz", ",", &count);
+ ASSERT_EQ(count, 3);
+ ASSERT_STR_EQ(split[0], "foo");
+ ASSERT_STR_EQ(split[1], "bar");
+ ASSERT_STR_EQ(split[2], "baz");
+ for (int i = 0; i < count; i++) free(split[i]);
+ free(split);
+
+ split = str_split("hello", ",", &count);
+ ASSERT_EQ(count, 1);
+ ASSERT_STR_EQ(split[0], "hello");
+ free(split[0]);
+ free(split);
+
+ split = str_split(",a,,b,", ",", &count);
+ ASSERT_EQ(count, 5);
+ ASSERT_STR_EQ(split[0], "");
+ ASSERT_STR_EQ(split[1], "a");
+ ASSERT_STR_EQ(split[2], "");
+ ASSERT_STR_EQ(split[3], "b");
+ ASSERT_STR_EQ(split[4], "");
+ for (int i = 0; i < count; i++) free(split[i]);
+ free(split);
+
+ /* str_split with multi-char delimiter */
+ split = str_split("a::b::c", "::", &count);
+ ASSERT_EQ(count, 3);
+ ASSERT_STR_EQ(split[0], "a");
+ ASSERT_STR_EQ(split[1], "b");
+ ASSERT_STR_EQ(split[2], "c");
+ for (int i = 0; i < count; i++) free(split[i]);
+ free(split);
+
+ /* str_split with empty delimiter returns whole string */
+ split = str_split("hello", "", &count);
+ ASSERT_EQ(count, 1);
+ ASSERT_STR_EQ(split[0], "hello");
+ free(split[0]);
+ free(split);
+
+ /* str_split empty string */
+ split = str_split("", ",", &count);
+ ASSERT_EQ(count, 1);
+ ASSERT_STR_EQ(split[0], "");
+ free(split[0]);
+ free(split);
+
+ /* str_contains */
+ ASSERT_TRUE(str_contains("hello world", "world"));
+ ASSERT_TRUE(str_contains("hello world", "hello"));
+ ASSERT_TRUE(str_contains("hello", "hello"));
+ ASSERT_FALSE(str_contains("hello", "xyz"));
+ ASSERT_TRUE(str_contains("hello", ""));
+ ASSERT_TRUE(str_contains("", ""));
+ ASSERT_FALSE(str_contains("", "a"));
+
TEST_REPORT();
}
blob - 104b6f1acfc1c7a060396ba8ebc70626d3995941
blob + fa31ddfd0081614dd96eb80b4bc1b218634abf4c
--- tests/test_vector.c
+++ tests/test_vector.c
#include "lftest.h"
#include "lfvector.h"
+static int destroy_count;
+
+static void counting_destroy(void *data) {
+ (void)data;
+ destroy_count++;
+}
+
int main() {
+ /* --- existing tests --- */
Vector *v = malloc(sizeof(Vector));
vec_init(v, NULL);
vec_destroy(v);
free(v);
+ /* --- destroy callback --- */
+ destroy_count = 0;
+ Vector dv;
+ vec_init(&dv, counting_destroy);
+ int a = 1, b = 2, c = 3;
+ vec_push(&dv, &a);
+ vec_push(&dv, &b);
+ vec_push(&dv, &c);
+ vec_destroy(&dv);
+ ASSERT_EQ(destroy_count, 3);
+
+ /* --- vec_init_with_capacity --- */
+ Vector cv;
+ ASSERT_EQ(vec_init_with_capacity(&cv, NULL, 16), 0);
+ ASSERT_EQ(vec_cap(&cv), 16);
+ ASSERT_EQ(vec_len(&cv), 0);
+ vec_destroy(&cv);
+
+ /* --- vec_init NULL check --- */
+ ASSERT_EQ(vec_init(NULL, NULL), -1);
+ ASSERT_EQ(vec_init_with_capacity(NULL, NULL, 4), -1);
+
+ /* --- insert at index 0 --- */
+ Vector iv;
+ vec_init(&iv, NULL);
+ int x1 = 10, x2 = 20, x3 = 30;
+ vec_push(&iv, &x1);
+ vec_push(&iv, &x2);
+ vec_insert(&iv, &x3, 0);
+ ASSERT_EQ(*(int *)vec_at(&iv, 0), 30);
+ ASSERT_EQ(*(int *)vec_at(&iv, 1), 10);
+ ASSERT_EQ(*(int *)vec_at(&iv, 2), 20);
+ ASSERT_EQ(vec_len(&iv), 3);
+
+ /* --- insert out of bounds --- */
+ ASSERT_EQ(vec_insert(&iv, &x1, 100), -1);
+
+ vec_destroy(&iv);
+
+ /* --- vec_sort empty --- */
+ Vector sv;
+ vec_init(&sv, NULL);
+ vec_sort(&sv, vec_cmp_int);
+ ASSERT_EQ(vec_len(&sv), 0);
+
+ /* --- vec_sort single element --- */
+ int ss1 = 42;
+ vec_push(&sv, &ss1);
+ vec_sort(&sv, vec_cmp_int);
+ ASSERT_EQ(vec_len(&sv), 1);
+ ASSERT_EQ(*(int *)vec_at(&sv, 0), 42);
+
+ /* --- vec_sort multiple elements --- */
+ int ss2 = 5, ss3 = 99, ss4 = 1;
+ vec_push(&sv, &ss2);
+ vec_push(&sv, &ss3);
+ vec_push(&sv, &ss4);
+ vec_sort(&sv, vec_cmp_int);
+ ASSERT_EQ(*(int *)vec_at(&sv, 0), 1);
+ ASSERT_EQ(*(int *)vec_at(&sv, 1), 5);
+ ASSERT_EQ(*(int *)vec_at(&sv, 2), 42);
+ ASSERT_EQ(*(int *)vec_at(&sv, 3), 99);
+ vec_destroy(&sv);
+
+ /* --- vec_shrink on empty vector --- */
+ Vector ev;
+ vec_init(&ev, NULL);
+ ASSERT_EQ(vec_shrink(&ev), 0);
+ ASSERT_EQ(vec_cap(&ev), 0);
+ ASSERT_NULL(ev.elements);
+
+ /* --- vec_clear return check --- */
+ Vector clv;
+ vec_init(&clv, NULL);
+ int cl1 = 1;
+ vec_push(&clv, &cl1);
+ ASSERT_EQ(vec_clear(&clv), 0);
+ ASSERT_EQ(vec_len(&clv), 0);
+ vec_destroy(&clv);
+
+ /* --- vec_remove out of bounds --- */
+ Vector rv;
+ vec_init(&rv, NULL);
+ ASSERT_NULL(vec_remove(&rv, 0));
+ ASSERT_NULL(vec_safe_at(&rv, 0));
+ vec_destroy(&rv);
+
+ /* --- vec_grow_to smaller fails --- */
+ Vector gv;
+ vec_init(&gv, NULL);
+ ASSERT_EQ(vec_grow_to(&gv, 1), -1);
+ vec_destroy(&gv);
+
TEST_REPORT();
}
blob - /dev/null
blob + 063e3213f5fbb2126021a6460d57417a91325581 (mode 644)
--- /dev/null
+++ tests/test_utility.c
+#include <stdio.h>
+#include <stdlib.h>
+#include "lftest.h"
+#include "lfutility.h"
+
+int main() {
+ /* Point_new */
+ Point p = Point_new(3, 7);
+ ASSERT_EQ(p.x, 3);
+ ASSERT_EQ(p.y, 7);
+
+ /* Point_new_p */
+ Point *pp = Point_new_p(5, 11);
+ ASSERT_NOT_NULL(pp);
+ ASSERT_EQ(pp->x, 5);
+ ASSERT_EQ(pp->y, 11);
+
+ /* Point_eq */
+ Point a = Point_new(1, 2);
+ Point b = Point_new(1, 2);
+ Point c = Point_new(3, 4);
+ ASSERT_TRUE(Point_eq(a, b));
+ ASSERT_FALSE(Point_eq(a, c));
+
+ /* Point_cmp_p */
+ Point *pa = Point_new_p(1, 2);
+ Point *pb = Point_new_p(1, 2);
+ Point *pc = Point_new_p(9, 9);
+ ASSERT_NOT_NULL(pa);
+ ASSERT_NOT_NULL(pb);
+ ASSERT_NOT_NULL(pc);
+ ASSERT_TRUE(Point_cmp_p(pa, pb));
+ ASSERT_FALSE(Point_cmp_p(pa, pc));
+
+ /* Point_cmp_v */
+ ASSERT_TRUE(Point_cmp_v(pa, pb));
+ ASSERT_FALSE(Point_cmp_v(pa, pc));
+
+ /* Point_destroy */
+ Point_destroy(pp);
+ Point_destroy(pa);
+ Point_destroy(pb);
+ Point_destroy(pc);
+ Point_destroy(NULL); /* should not crash */
+
+ TEST_REPORT();
+}