diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 17:53:40 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 17:53:40 +0100 |
| commit | 6cb22fd7f2c20be2cf268d6bcd236252d7847763 (patch) | |
| tree | 10891dcea861e5b3a9d8af3114393e650cdaae1d /tests.c | |
| download | nonstd-6cb22fd7f2c20be2cf268d6bcd236252d7847763.tar.gz | |
Engage!
Diffstat (limited to 'tests.c')
| -rw-r--r-- | tests.c | 984 |
1 files changed, 984 insertions, 0 deletions
@@ -0,0 +1,984 @@ +#define _POSIX_C_SOURCE 200112L +#include "minunit.h" + +#define NONSTD_IMPLEMENTATION +#include "nonstd.h" + +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +// Custom test runner that prints test names +#define RUN_TEST_WITH_NAME(test) \ + do { \ + printf(" %-50s ", #test); \ + fflush(stdout); \ + int before_fail = minunit_fail; \ + int saved_stdout = dup(STDOUT_FILENO); \ + int devnull = open("/dev/null", O_WRONLY); \ + dup2(devnull, STDOUT_FILENO); \ + close(devnull); \ + MU_RUN_TEST(test); \ + fflush(stdout); \ + dup2(saved_stdout, STDOUT_FILENO); \ + close(saved_stdout); \ + if (minunit_fail == before_fail) { \ + printf("PASS\n"); \ + } \ + } while (0) + +// String view tests +MU_TEST(test_sv_from_cstr) { + stringv sv = sv_from_cstr("hello"); + mu_assert_int_eq(5, sv.length); + mu_check(sv.data != NULL); + mu_check(strncmp(sv.data, "hello", 5) == 0); +} + +MU_TEST(test_sv_from_cstr_null) { + stringv sv = sv_from_cstr(NULL); + mu_assert_int_eq(0, sv.length); +} + +MU_TEST(test_sv_from_parts) { + const char *str = "hello world"; + stringv sv = sv_from_parts(str, 5); + mu_assert_int_eq(5, sv.length); + mu_check(sv.data == str); +} + +MU_TEST(test_sv_from_cstr_literal) { + stringv sv = sv_from_cstr("test"); + mu_assert_int_eq(4, sv.length); + mu_check(strncmp(sv.data, "test", 4) == 0); +} + +MU_TEST(test_sv_slice_normal) { + stringv sv = sv_from_cstr("hello world"); + stringv sliced = sv_slice(sv, 0, 5); + mu_assert_int_eq(5, sliced.length); + mu_check(strncmp(sliced.data, "hello", 5) == 0); +} + +MU_TEST(test_sv_slice_middle) { + stringv sv = sv_from_cstr("hello world"); + stringv sliced = sv_slice(sv, 6, 11); + mu_assert_int_eq(5, sliced.length); + mu_check(strncmp(sliced.data, "world", 5) == 0); +} + +MU_TEST(test_sv_slice_out_of_bounds) { + stringv sv = sv_from_cstr("hello"); + stringv sliced = sv_slice(sv, 0, 100); + mu_assert_int_eq(5, sliced.length); +} + +MU_TEST(test_sv_slice_invalid_range) { + stringv sv = sv_from_cstr("hello"); + stringv sliced = sv_slice(sv, 10, 5); + mu_assert_int_eq(0, sliced.length); +} + +MU_TEST(test_sv_equals_same) { + stringv a = sv_from_cstr("hello"); + stringv b = sv_from_cstr("hello"); + mu_check(sv_equals(a, b)); +} + +MU_TEST(test_sv_equals_different) { + stringv a = sv_from_cstr("hello"); + stringv b = sv_from_cstr("world"); + mu_check(!sv_equals(a, b)); +} + +MU_TEST(test_sv_equals_different_length) { + stringv a = sv_from_cstr("hello"); + stringv b = sv_from_cstr("hi"); + mu_check(!sv_equals(a, b)); +} + +MU_TEST(test_sv_equals_empty) { + stringv a = sv_from_parts(NULL, 0); + stringv b = sv_from_parts(NULL, 0); + mu_check(sv_equals(a, b)); +} + +MU_TEST(test_sv_starts_with_true) { + stringv sv = sv_from_cstr("hello world"); + stringv prefix = sv_from_cstr("hello"); + mu_check(sv_starts_with(sv, prefix)); +} + +MU_TEST(test_sv_starts_with_false) { + stringv sv = sv_from_cstr("hello world"); + stringv prefix = sv_from_cstr("world"); + mu_check(!sv_starts_with(sv, prefix)); +} + +MU_TEST(test_sv_starts_with_empty_prefix) { + stringv sv = sv_from_cstr("hello"); + stringv prefix = sv_from_parts(NULL, 0); + mu_check(sv_starts_with(sv, prefix)); +} + +MU_TEST(test_sv_starts_with_longer_prefix) { + stringv sv = sv_from_cstr("hi"); + stringv prefix = sv_from_cstr("hello"); + mu_check(!sv_starts_with(sv, prefix)); +} + +MU_TEST(test_sv_ends_with_true) { + stringv sv = sv_from_cstr("hello world"); + stringv suffix = sv_from_cstr("world"); + mu_check(sv_ends_with(sv, suffix)); +} + +MU_TEST(test_sv_ends_with_false) { + stringv sv = sv_from_cstr("hello world"); + stringv suffix = sv_from_cstr("hello"); + mu_check(!sv_ends_with(sv, suffix)); +} + +MU_TEST(test_sv_ends_with_empty_suffix) { + stringv sv = sv_from_cstr("hello"); + stringv suffix = sv_from_parts(NULL, 0); + mu_check(sv_ends_with(sv, suffix)); +} + +MU_TEST(test_sv_ends_with_longer_suffix) { + stringv sv = sv_from_cstr("hi"); + stringv suffix = sv_from_cstr("world"); + mu_check(!sv_ends_with(sv, suffix)); +} + +// Macro tests +MU_TEST(test_countof) { + int array[10]; + mu_assert_int_eq(10, countof(array)); + + char str[] = "hello"; + mu_assert_int_eq(6, countof(str)); // includes null terminator +} + +MU_TEST(test_min_max_clamp) { + mu_assert_int_eq(5, MIN(5, 10)); + mu_assert_int_eq(5, MIN(10, 5)); + + mu_assert_int_eq(10, MAX(5, 10)); + mu_assert_int_eq(10, MAX(10, 5)); + + mu_assert_int_eq(5, CLAMP(3, 5, 10)); + mu_assert_int_eq(7, CLAMP(7, 5, 10)); + mu_assert_int_eq(10, CLAMP(15, 5, 10)); +} + +MU_TEST(test_static_foreach_macro) { + int values[] = {1, 2, 3, 4, 5}; + int sum = 0; + int val; + + static_foreach(int, val, values) { sum += val; } + + mu_assert_int_eq(15, sum); +} + +MU_TEST(test_static_foreach_with_strings) { + const char *words[] = {"hello", "world", "test"}; + int count = 0; + const char *word; + + static_foreach(const char *, word, words) { + count++; + mu_check(word != NULL); + } + + mu_assert_int_eq(3, count); +} + +MU_TEST(test_static_foreach_single_element) { + int single[] = {42}; + int result = 0; + int val; + + static_foreach(int, val, single) { result = val; } + + mu_assert_int_eq(42, result); +} + +MU_TEST(test_static_foreach_modify_counter) { + u32 numbers[] = {10, 20, 30, 40}; + u32 max = 0; + u32 num; + + static_foreach(u32, num, numbers) { + if (num > max) + max = num; + } + + mu_assert_int_eq(40, max); +} + +MU_TEST(test_static_foreach_with_structs) { + struct Point { + int x, y; + }; + + struct Point pts[] = {{1, 2}, {3, 4}, {5, 6}}; + int sum_x = 0; + int sum_y = 0; + struct Point p; + + static_foreach(struct Point, p, pts) { + sum_x += p.x; + sum_y += p.y; + } + + mu_assert_int_eq(9, sum_x); // 1 + 3 + 5 + mu_assert_int_eq(12, sum_y); // 2 + 4 + 6 +} + +MU_TEST(test_alloc_and_free) { + int *ptr = ALLOC(int, 10); + mu_check(ptr != NULL); + + // Use the memory + ptr[0] = 42; + ptr[9] = 99; + mu_assert_int_eq(42, ptr[0]); + mu_assert_int_eq(99, ptr[9]); + + FREE(ptr); + mu_check(ptr == NULL); +} + +MU_TEST(test_realloc) { + int *ptr = ALLOC(int, 5); + mu_check(ptr != NULL); + + ptr[0] = 1; + ptr[4] = 5; + + ptr = REALLOC(ptr, int, 10); + mu_check(ptr != NULL); + + mu_assert_int_eq(1, ptr[0]); + mu_assert_int_eq(5, ptr[4]); + ptr[9] = 99; + mu_assert_int_eq(99, ptr[9]); + + free(ptr); +} + +MU_TEST(test_typedefs) { + // Just verify the types compile and have expected sizes + i8 a = -1; + u8 b = 255; + i16 c = -1000; + u16 d = 60000; + i32 e = -100000; + u32 f = 4000000000U; + i64 g = -1000000000LL; + u64 h = 10000000000ULL; + + mu_check(a == -1); + mu_check(b == 255); + mu_check(c == -1000); + mu_check(d == 60000); + mu_check(e == -100000); + mu_check(f == 4000000000U); + mu_check(g == -1000000000LL); + mu_check(h == 10000000000ULL); +} + +// String builder tests +MU_TEST(test_sb_init) { + stringb sb; + sb_init(&sb, 0); + mu_check(sb.data != NULL); + mu_assert_int_eq(0, sb.length); + mu_check(sb.capacity >= 16); // default capacity + mu_assert_int_eq('\0', sb.data[0]); + sb_free(&sb); +} + +MU_TEST(test_sb_init_with_capacity) { + stringb sb; + sb_init(&sb, 64); + mu_check(sb.data != NULL); + mu_assert_int_eq(0, sb.length); + mu_assert_int_eq(64, sb.capacity); + sb_free(&sb); +} + +MU_TEST(test_sb_append_cstr) { + stringb sb; + sb_init(&sb, 0); + sb_append_cstr(&sb, "hello"); + mu_assert_int_eq(5, sb.length); + mu_check(strcmp(sb.data, "hello") == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_append_cstr_multiple) { + stringb sb; + sb_init(&sb, 0); + sb_append_cstr(&sb, "hello"); + sb_append_cstr(&sb, " "); + sb_append_cstr(&sb, "world"); + mu_assert_int_eq(11, sb.length); + mu_check(strcmp(sb.data, "hello world") == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_append_cstr_null) { + stringb sb; + sb_init(&sb, 0); + sb_append_cstr(&sb, "test"); + sb_append_cstr(&sb, NULL); + mu_assert_int_eq(4, sb.length); + mu_check(strcmp(sb.data, "test") == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_append_sv) { + stringb sb; + sb_init(&sb, 0); + stringv sv = sv_from_cstr("hello"); + sb_append_sv(&sb, sv); + mu_assert_int_eq(5, sb.length); + mu_check(strcmp(sb.data, "hello") == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_append_sv_slice) { + stringb sb; + sb_init(&sb, 0); + stringv full = sv_from_cstr("hello world"); + stringv slice = sv_slice(full, 6, 11); + sb_append_sv(&sb, slice); + mu_assert_int_eq(5, sb.length); + mu_check(strcmp(sb.data, "world") == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_append_sv_empty) { + stringb sb; + sb_init(&sb, 0); + sb_append_cstr(&sb, "test"); + stringv empty = sv_from_parts(NULL, 0); + sb_append_sv(&sb, empty); + mu_assert_int_eq(4, sb.length); + mu_check(strcmp(sb.data, "test") == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_append_char) { + stringb sb; + sb_init(&sb, 0); + sb_append_char(&sb, 'a'); + sb_append_char(&sb, 'b'); + sb_append_char(&sb, 'c'); + mu_assert_int_eq(3, sb.length); + mu_check(strcmp(sb.data, "abc") == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_mixed_append) { + stringb sb; + sb_init(&sb, 0); + sb_append_cstr(&sb, "Hello"); + sb_append_char(&sb, ' '); + stringv sv = sv_from_cstr("beautiful"); + sb_append_sv(&sb, sv); + sb_append_char(&sb, ' '); + sb_append_cstr(&sb, "world!"); + mu_assert_int_eq(22, sb.length); + mu_check(strcmp(sb.data, "Hello beautiful world!") == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_as_sv) { + stringb sb; + sb_init(&sb, 0); + sb_append_cstr(&sb, "test string"); + stringv sv = sb_as_sv(&sb); + mu_assert_int_eq(11, sv.length); + mu_check(sv.data == sb.data); + mu_check(strncmp(sv.data, "test string", sv.length) == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_growth) { + stringb sb; + sb_init(&sb, 4); // very small initial capacity + mu_assert_int_eq(4, sb.capacity); + + // Append enough to trigger growth + sb_append_cstr(&sb, "this is a long string that will exceed initial capacity"); + mu_check(sb.capacity > 4); // capacity should have grown + mu_check(sb.length == strlen("this is a long string that will exceed initial capacity")); + mu_check(strcmp(sb.data, "this is a long string that will exceed initial capacity") == 0); + sb_free(&sb); +} + +MU_TEST(test_sb_free) { + stringb sb; + sb_init(&sb, 32); + sb_append_cstr(&sb, "test"); + sb_free(&sb); + mu_check(sb.data == NULL); + mu_assert_int_eq(0, sb.length); + mu_assert_int_eq(0, sb.capacity); +} + +MU_TEST(test_sb_sv_interop) { + // Test that sb can be used to build a string, then viewed with sv + stringb sb; + sb_init(&sb, 0); + + const char *words[] = {"one", "two", "three"}; + const char *word; + static_foreach(const char *, word, words) { + if (sb.length > 0) { + sb_append_char(&sb, ','); + } + sb_append_cstr(&sb, word); + } + + stringv result = sb_as_sv(&sb); + mu_check(sv_equals(result, sv_from_cstr("one,two,three"))); + + // Can use sv operations on the builder's content + mu_check(sv_starts_with(result, sv_from_cstr("one"))); + mu_check(sv_ends_with(result, sv_from_cstr("three"))); + + sb_free(&sb); +} + +MU_TEST(test_sb_append_sv_from_sb) { + // Test appending a string view of one builder to another + stringb sb1, sb2; + sb_init(&sb1, 0); + sb_init(&sb2, 0); + + sb_append_cstr(&sb1, "hello"); + sb_append_cstr(&sb2, "world"); + + stringv sv1 = sb_as_sv(&sb1); + sb_append_char(&sb2, ' '); + sb_append_sv(&sb2, sv1); + + mu_check(strcmp(sb2.data, "world hello") == 0); + + sb_free(&sb1); + sb_free(&sb2); +} + +// Array tests +MU_TEST(test_array_init) { + array(int) arr; + array_init(arr); + mu_check(arr.data == NULL); + mu_assert_int_eq(0, arr.length); + mu_assert_int_eq(0, arr.capacity); + array_free(arr); +} + +MU_TEST(test_array_init_cap) { + array(int) arr; + array_init_cap(arr, 32); + mu_check(arr.data != NULL); + mu_assert_int_eq(0, arr.length); + mu_assert_int_eq(32, arr.capacity); + array_free(arr); +} + +MU_TEST(test_array_push) { + array(int) arr; + array_init(arr); + array_push(arr, 10); + array_push(arr, 20); + array_push(arr, 30); + + mu_assert_int_eq(3, arr.length); + mu_check(arr.capacity >= 3); + mu_assert_int_eq(10, arr.data[0]); + mu_assert_int_eq(20, arr.data[1]); + mu_assert_int_eq(30, arr.data[2]); + + array_free(arr); +} + +MU_TEST(test_array_pop) { + array(int) arr; + array_init(arr); + array_push(arr, 10); + array_push(arr, 20); + + int val = array_pop(arr); + mu_assert_int_eq(20, val); + mu_assert_int_eq(1, arr.length); + + val = array_pop(arr); + mu_assert_int_eq(10, val); + mu_assert_int_eq(0, arr.length); + + array_free(arr); +} + +MU_TEST(test_array_pop_empty) { + array(int) arr; + array_init(arr); + int val = array_pop(arr); + mu_assert_int_eq(0, val); + mu_assert_int_eq(0, arr.length); + array_free(arr); +} + +MU_TEST(test_array_get_set) { + array(int) arr; + array_init(arr); + array_push(arr, 10); + array_push(arr, 20); + + mu_assert_int_eq(10, array_get(arr, 0)); + mu_assert_int_eq(20, array_get(arr, 1)); + + array_set(arr, 0, 100); + mu_assert_int_eq(100, array_get(arr, 0)); + + // Test out of bounds set (should do nothing) + array_set(arr, 5, 500); + mu_assert_int_eq(2, arr.length); + + array_free(arr); +} + +MU_TEST(test_array_insert) { + array(int) arr; + array_init(arr); + array_push(arr, 10); + array_push(arr, 30); + + array_insert(arr, 1, 20); // Insert between 10 and 30 + mu_assert_int_eq(3, arr.length); + mu_assert_int_eq(10, arr.data[0]); + mu_assert_int_eq(20, arr.data[1]); + mu_assert_int_eq(30, arr.data[2]); + + array_insert(arr, 0, 5); // Insert at start + mu_assert_int_eq(5, arr.data[0]); + mu_assert_int_eq(10, arr.data[1]); + + array_insert(arr, 4, 40); // Insert at end + mu_assert_int_eq(40, arr.data[4]); + mu_assert_int_eq(5, arr.length); + + array_free(arr); +} + +MU_TEST(test_array_remove) { + array(int) arr; + array_init(arr); + array_push(arr, 10); + array_push(arr, 20); + array_push(arr, 30); + array_push(arr, 40); + + array_remove(arr, 1); // Remove 20 + mu_assert_int_eq(3, arr.length); + mu_assert_int_eq(10, arr.data[0]); + mu_assert_int_eq(30, arr.data[1]); + mu_assert_int_eq(40, arr.data[2]); + + array_remove(arr, 0); // Remove 10 (start) + mu_assert_int_eq(30, arr.data[0]); + + array_remove(arr, 1); // Remove 40 (end) + mu_assert_int_eq(30, arr.data[0]); + mu_assert_int_eq(1, arr.length); + + array_free(arr); +} + +MU_TEST(test_array_growth) { + array(int) arr; + array_init_cap(arr, 4); + + for (int i = 0; i < 20; i++) { + array_push(arr, i); + } + + mu_assert_int_eq(20, arr.length); + mu_check(arr.capacity >= 20); + mu_check(arr.capacity > 4); + + for (int i = 0; i < 20; i++) { + mu_assert_int_eq(i, arr.data[i]); + } + + array_free(arr); +} + +MU_TEST(test_array_reserve) { + array(int) arr; + array_init(arr); + + array_reserve(arr, 100); + mu_assert_int_eq(100, arr.capacity); + mu_assert_int_eq(0, arr.length); + mu_check(arr.data != NULL); + + array_free(arr); +} + +MU_TEST(test_array_clear) { + array(int) arr; + array_init(arr); + array_push(arr, 1); + array_push(arr, 2); + + size_t cap = arr.capacity; + array_clear(arr); + + mu_assert_int_eq(0, arr.length); + mu_assert_int_eq(cap, arr.capacity); // Capacity stays + mu_check(arr.data != NULL); + + array_free(arr); +} + +MU_TEST(test_array_foreach) { + array(int) arr; + array_init(arr); + array_push(arr, 1); + array_push(arr, 2); + array_push(arr, 3); + + int sum = 0; + int val; + array_foreach(arr, val) { sum += val; } + + mu_assert_int_eq(6, sum); + array_free(arr); +} + +MU_TEST(test_array_foreach_i) { + array(int) arr; + array_init(arr); + array_push(arr, 10); + array_push(arr, 20); + array_push(arr, 30); + + int sum_val = 0; + size_t sum_idx = 0; + int val; + + array_foreach_i(arr, val, i) { + sum_val += val; + sum_idx += i; + mu_assert_int_eq(val, arr.data[i]); + } + + mu_assert_int_eq(60, sum_val); + mu_assert_int_eq(3, sum_idx); // 0+1+2 + array_free(arr); +} + +// Slice Tests +SLICE_DEF(int); + +MU_TEST(test_slice_make) { + int nums[] = {1, 2, 3, 4, 5}; + slice(int) s = make_slice(int, nums, 5); + + mu_assert_int_eq(5, s.length); + mu_check(s.data == nums); + mu_assert_int_eq(1, s.data[0]); + mu_assert_int_eq(5, s.data[4]); +} + +MU_TEST(test_slice_make_partial) { + int nums[] = {10, 20, 30, 40, 50}; + slice(int) s = make_slice(int, nums + 1, 3); // 20, 30, 40 + + mu_assert_int_eq(3, s.length); + mu_assert_int_eq(20, s.data[0]); + mu_assert_int_eq(40, s.data[2]); +} + +MU_TEST(test_slice_from_dynamic_array) { + array(int) arr; + array_init(arr); + array_push(arr, 100); + array_push(arr, 200); + + slice(int) s = array_as_slice(int, arr); + + mu_assert_int_eq(2, s.length); + mu_check(s.data == arr.data); + mu_assert_int_eq(100, s.data[0]); + + array_free(arr); +} + +MU_TEST(test_slice_modification) { + int nums[] = {1, 1, 1}; + slice(int) s = make_slice(int, nums, 3); + + s.data[1] = 99; + + mu_assert_int_eq(99, nums[1]); + mu_assert_int_eq(1, nums[0]); +} + +// Arena tests +MU_TEST(test_arena_basic) { + Arena a = arena_make(); + void *p1 = arena_alloc(&a, 10); + void *p2 = arena_alloc(&a, 20); + + mu_check(p1 != NULL); + mu_check(p2 != NULL); + mu_check(p1 != p2); + + // Basic usage check + memset(p1, 1, 10); + memset(p2, 2, 20); + + arena_free(&a); +} + +MU_TEST(test_arena_growth) { + Arena a = arena_make(); + + // Force growth by allocating more than default block size (4096) + // or by allocating many small objects. + // Let's alloc a big chunk first. + void *big = arena_alloc(&a, 5000); + mu_check(big != NULL); + mu_check(a.blocks.length >= 1); + + // Alloc another big chunk + void *big2 = arena_alloc(&a, 5000); + mu_check(big2 != NULL); + mu_check(big2 != big); + mu_check(a.blocks.length >= 2); + + arena_free(&a); +} + +MU_TEST(test_arena_alignment) { + Arena a = arena_make(); + + void *p1 = arena_alloc(&a, 1); // 1 byte + void *p2 = arena_alloc(&a, 1); // 1 byte + + uintptr_t addr1 = (uintptr_t)p1; + uintptr_t addr2 = (uintptr_t)p2; + + mu_check(addr1 % sizeof(void *) == 0); + mu_check(addr2 % sizeof(void *) == 0); + mu_check(addr2 - addr1 >= sizeof(void *)); + + arena_free(&a); +} + +// File I/O tests +MU_TEST(test_file_io_basic) { + const char *filename = "test_io_basic.txt"; + const char *content = "Hello, file!"; + size_t len = strlen(content); + + // Write + mu_check(write_entire_file(filename, content, len)); + + // Read + size_t read_len; + char *read_content = read_entire_file(filename, &read_len); + mu_check(read_content != NULL); + mu_assert_int_eq(len, read_len); + mu_check(strncmp(content, read_content, len) == 0); + + FREE(read_content); + remove(filename); +} + +MU_TEST(test_file_io_sv) { + const char *filename = "test_io_sv.txt"; + stringv sv = sv_from_cstr("Hello from sv!"); + + // Write + mu_check(write_file_sv(filename, sv)); + + // Read + stringv read_sv = read_entire_file_sv(filename); + mu_check(read_sv.data != NULL); + mu_assert_int_eq(sv.length, read_sv.length); + mu_check(sv_equals(sv, read_sv)); + + // The data returned by read_entire_file_sv is malloc'd and needs freeing + // We cast away const to free it since we know it was allocated + free((char *)read_sv.data); + remove(filename); +} + +MU_TEST(test_file_io_sb) { + const char *filename = "test_io_sb.txt"; + stringb sb; + sb_init(&sb, 0); + sb_append_cstr(&sb, "Hello from sb!"); + + // Write + mu_check(write_file_sb(filename, &sb)); + + // Read + stringb read_sb = read_entire_file_sb(filename); + mu_check(read_sb.data != NULL); + mu_assert_int_eq(sb.length, read_sb.length); + mu_check(strcmp(sb.data, read_sb.data) == 0); + + sb_free(&sb); + sb_free(&read_sb); + remove(filename); +} + +MU_TEST(test_file_io_read_missing) { + size_t len; + char *content = read_entire_file("non_existent_file.txt", &len); + mu_check(content == NULL); +} + +MU_TEST(test_file_io_read_missing_sv) { + stringv sv = read_entire_file_sv("non_existent_file.txt"); + mu_check(sv.data == NULL); + mu_assert_int_eq(0, sv.length); +} + +MU_TEST(test_file_io_read_missing_sb) { + stringb sb = read_entire_file_sb("non_existent_file.txt"); + mu_check(sb.data == NULL); + mu_assert_int_eq(0, sb.length); +} + +// Test suites +MU_TEST_SUITE(test_suite_stringv) { + printf("\n[String View Tests]\n"); + RUN_TEST_WITH_NAME(test_sv_from_cstr); + RUN_TEST_WITH_NAME(test_sv_from_cstr_null); + RUN_TEST_WITH_NAME(test_sv_from_parts); + RUN_TEST_WITH_NAME(test_sv_from_cstr_literal); + RUN_TEST_WITH_NAME(test_sv_slice_normal); + RUN_TEST_WITH_NAME(test_sv_slice_middle); + RUN_TEST_WITH_NAME(test_sv_slice_out_of_bounds); + RUN_TEST_WITH_NAME(test_sv_slice_invalid_range); + RUN_TEST_WITH_NAME(test_sv_equals_same); + RUN_TEST_WITH_NAME(test_sv_equals_different); + RUN_TEST_WITH_NAME(test_sv_equals_different_length); + RUN_TEST_WITH_NAME(test_sv_equals_empty); + RUN_TEST_WITH_NAME(test_sv_starts_with_true); + RUN_TEST_WITH_NAME(test_sv_starts_with_false); + RUN_TEST_WITH_NAME(test_sv_starts_with_empty_prefix); + RUN_TEST_WITH_NAME(test_sv_starts_with_longer_prefix); + RUN_TEST_WITH_NAME(test_sv_ends_with_true); + RUN_TEST_WITH_NAME(test_sv_ends_with_false); + RUN_TEST_WITH_NAME(test_sv_ends_with_empty_suffix); + RUN_TEST_WITH_NAME(test_sv_ends_with_longer_suffix); +} + +MU_TEST_SUITE(test_suite_stringb) { + printf("\n[String Builder Tests]\n"); + RUN_TEST_WITH_NAME(test_sb_init); + RUN_TEST_WITH_NAME(test_sb_init_with_capacity); + RUN_TEST_WITH_NAME(test_sb_append_cstr); + RUN_TEST_WITH_NAME(test_sb_append_cstr_multiple); + RUN_TEST_WITH_NAME(test_sb_append_cstr_null); + RUN_TEST_WITH_NAME(test_sb_append_sv); + RUN_TEST_WITH_NAME(test_sb_append_sv_slice); + RUN_TEST_WITH_NAME(test_sb_append_sv_empty); + RUN_TEST_WITH_NAME(test_sb_append_char); + RUN_TEST_WITH_NAME(test_sb_mixed_append); + RUN_TEST_WITH_NAME(test_sb_as_sv); + RUN_TEST_WITH_NAME(test_sb_growth); + RUN_TEST_WITH_NAME(test_sb_free); + RUN_TEST_WITH_NAME(test_sb_sv_interop); + RUN_TEST_WITH_NAME(test_sb_append_sv_from_sb); +} + +MU_TEST_SUITE(test_suite_macros) { + printf("\n[Macro Tests]\n"); + RUN_TEST_WITH_NAME(test_countof); + RUN_TEST_WITH_NAME(test_min_max_clamp); + RUN_TEST_WITH_NAME(test_static_foreach_macro); + RUN_TEST_WITH_NAME(test_static_foreach_with_strings); + RUN_TEST_WITH_NAME(test_static_foreach_single_element); + RUN_TEST_WITH_NAME(test_static_foreach_modify_counter); + RUN_TEST_WITH_NAME(test_static_foreach_with_structs); + RUN_TEST_WITH_NAME(test_alloc_and_free); + RUN_TEST_WITH_NAME(test_realloc); +} + +MU_TEST_SUITE(test_suite_array) { + printf("\n[Array Tests]\n"); + RUN_TEST_WITH_NAME(test_array_init); + RUN_TEST_WITH_NAME(test_array_init_cap); + RUN_TEST_WITH_NAME(test_array_push); + RUN_TEST_WITH_NAME(test_array_pop); + RUN_TEST_WITH_NAME(test_array_pop_empty); + RUN_TEST_WITH_NAME(test_array_get_set); + RUN_TEST_WITH_NAME(test_array_insert); + RUN_TEST_WITH_NAME(test_array_remove); + RUN_TEST_WITH_NAME(test_array_growth); + RUN_TEST_WITH_NAME(test_array_reserve); + RUN_TEST_WITH_NAME(test_array_clear); + RUN_TEST_WITH_NAME(test_array_foreach); + RUN_TEST_WITH_NAME(test_array_foreach_i); +} + +MU_TEST_SUITE(test_suite_slice) { + printf("\n[Slice Tests]\n"); + RUN_TEST_WITH_NAME(test_slice_make); + RUN_TEST_WITH_NAME(test_slice_make_partial); + RUN_TEST_WITH_NAME(test_slice_from_dynamic_array); + RUN_TEST_WITH_NAME(test_slice_modification); +} + +MU_TEST_SUITE(test_suite_types) { + printf("\n[Type Tests]\n"); + RUN_TEST_WITH_NAME(test_typedefs); +} + +MU_TEST_SUITE(test_suite_arena) { + printf("\n[Arena Tests]\n"); + RUN_TEST_WITH_NAME(test_arena_basic); + RUN_TEST_WITH_NAME(test_arena_growth); + RUN_TEST_WITH_NAME(test_arena_alignment); +} + +MU_TEST_SUITE(test_suite_files) { + printf("\n[File I/O Tests]\n"); + RUN_TEST_WITH_NAME(test_file_io_basic); + RUN_TEST_WITH_NAME(test_file_io_sv); + RUN_TEST_WITH_NAME(test_file_io_sb); + RUN_TEST_WITH_NAME(test_file_io_read_missing); + RUN_TEST_WITH_NAME(test_file_io_read_missing_sv); + RUN_TEST_WITH_NAME(test_file_io_read_missing_sb); +} + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + + MU_RUN_SUITE(test_suite_stringv); + MU_RUN_SUITE(test_suite_stringb); + MU_RUN_SUITE(test_suite_macros); + MU_RUN_SUITE(test_suite_array); + MU_RUN_SUITE(test_suite_slice); + MU_RUN_SUITE(test_suite_types); + MU_RUN_SUITE(test_suite_arena); + MU_RUN_SUITE(test_suite_files); + + MU_REPORT(); + + return MU_EXIT_CODE; +} |
