diff --git a/.DS_Store b/.DS_Store
index 96ac74d..1fe44ad 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000..5b159aa
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,8 @@
+Checks: >
+ -*,
+ clang-analyzer-*,
+ bugprone-*,
+ -bugprone-easily-swappable-parameters,
+ -bugprone-reserved-identifier,
+ performance-*,
+ security-*
diff --git a/.gitignore b/.gitignore
index 5b79a54..640f1a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
build/
-.cache/
\ No newline at end of file
+.cache/
+tests/cache/
+tests/bin/
+coverage.html
diff --git a/AGENTS.md b/AGENTS.md
deleted file mode 100644
index 14d3d7c..0000000
--- a/AGENTS.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# AGENTS.md
-
-## Identity & Core Philosophy
-You are an expert bug-hunter agent.
-Speak and reason in **Caveman style** (why use many token when few token do trick).
-
-### Caveman Communication Rules
-- Drop articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries, and greetings.
-- Short, dense, direct phrases. Fragment sentences okay.
-- Never summarize files read. Report only findings.
-- **No tool-call narration:** Fire tools directly. Never explain what you are about to inspect or have just inspected.
-- **Tokenizer rules:** NEVER invent abbreviations (cfg/impl/req/res/fn) or use arrows (→); tokenizers split them. Keep full words.
-- **Safety rules:** NEVER drop `not`, `never`, `no`, `only`, `except` (flips meaning).
-- **Exceptions (Do NOT caveman):** Code snippets, file paths, line numbers, command names, and error traces remain exact and intact.
-- **Output pattern:** `[thing] [action] [reason]. [next step].`
-
----
-
-## Strict Permissions & Boundaries
-1. **Target Task:** Read codebase, hunt bugs, identify security flaws, edge-case failures, or performance bottlenecks.
-2. **File Mutation Constraint:**
- - **YOU MAY ONLY CREATE OR EDIT:** `BUGS.md`
- - **ABSOLUTE BAN:** You are strictly forbidden from modifying, patching, refactoring, deleting, or creating ANY other files in the workspace (no source files, configs, tests, or documentation).
- - If user asks you to fix code directly, REFUSE in caveman: "No touch code. Rule say only log to BUGS.md."
-
----
-
-## Operating Instructions
-1. Inspect files in read-only mode using available search/read tools. Call them immediately without introductory text.
-2. Read existing `BUGS.md` first:
- - Identify existing style, headers, keys, table columns, or list formats.
- - You MUST mirror existing format, structure, and naming conventions exactly.
- - If `BUGS.md` is empty or missing, use a minimal markdown list: `File:Line | Severity | Issue | Recommended fix`.
-3. For every confirmed issue found:
- - Append or edit entry in `BUGS.md` following matched format.
- - Keep bug descriptions in `BUGS.md` terse and caveman-style.
-4. Do not patch or edit source code under any circumstances.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e004316
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,129 @@
+# ==============================================================================
+# Toolchain & Executables
+# ==============================================================================
+LLVM_DIR ?= /opt/homebrew/opt/llvm/bin
+CC := $(LLVM_DIR)/clang
+LLVM_PROFDATA := $(LLVM_DIR)/llvm-profdata
+LLVM_COV := $(LLVM_DIR)/llvm-cov
+CPPCHECK := cppcheck
+
+# ==============================================================================
+# Flags & Directories
+# ==============================================================================
+CFLAGS := -std=c23 -Wall -Wextra -Wpedantic -Wshadow \
+ -Wconversion -Wsign-conversion \
+ -g -O1 -fno-omit-frame-pointer
+SAN_FLAGS := -fsanitize=address,undefined
+INCLUDES := -Iinclude -Isrc/lib -Isrc/lib/char -Isrc/lib/utils
+
+ASAN_ENV := ASAN_OPTIONS="allocator_may_return_null=1:detect_stack_use_after_return=1" \
+ UBSAN_OPTIONS="halt_on_error=1:print_stacktrace=1"
+
+CPPCHECK_FLAGS := --enable=all \
+ --inconclusive \
+ --error-exitcode=1 \
+ --check-level=exhaustive \
+ --suppress=missingIncludeSystem \
+ --suppress=unmatchedSuppression \
+ --suppress=unusedFunction \
+ --suppress=staticFunction \
+ --inline-suppr \
+ $(INCLUDES)
+
+# Sources & Build Directories
+SRCS := src/lib/char/char.c src/lib/utils/utils.c
+TEST_SRC := tests/test_learn.c
+FUZZ_SRC := tests/fuzz_char.c
+
+BIN_DIR := tests/bin
+CACHE_DIR := tests/cache
+
+TEST_BIN := $(BIN_DIR)/test_learn_runner
+TSAN_BIN := $(BIN_DIR)/test_tsan_runner
+FUZZ_BIN := $(BIN_DIR)/fuzz_char_runner
+COV_BIN := $(BIN_DIR)/test_cov_runner
+
+# ==============================================================================
+# Targets & Workflow Rules
+# ==============================================================================
+.PHONY: all test sanitize check check-sources analyze cppcheck fuzz cov-build cov clean
+
+all: test
+
+$(BIN_DIR) $(CACHE_DIR):
+ @mkdir -p $@
+
+# --- Compilation Targets ---
+
+$(TEST_BIN): $(SRCS) $(TEST_SRC) | $(BIN_DIR)
+ $(CC) $(CFLAGS) $(SAN_FLAGS) $(INCLUDES) $^ -o $@
+
+$(TSAN_BIN): $(SRCS) $(TEST_SRC) | $(BIN_DIR)
+ $(CC) $(CFLAGS) -fsanitize=thread $(INCLUDES) $^ -o $@
+
+$(FUZZ_BIN): $(SRCS) $(FUZZ_SRC) | $(BIN_DIR)
+ $(CC) $(CFLAGS) -fsanitize=fuzzer,address,undefined $(INCLUDES) $^ -o $@
+
+# --- Testing & Sanitizer Suites ---
+
+test: $(TEST_BIN)
+ @echo "=== Running Unit Tests (ASan + UBSan) ==="
+ @$(ASAN_ENV) ./$(TEST_BIN)
+
+sanitize: $(TEST_BIN) $(TSAN_BIN)
+ @echo "\n=== [1/2] Running Address + UndefinedBehavior Sanitizers ==="
+ @$(ASAN_ENV) ./$(TEST_BIN)
+ @echo "\n=== [2/2] Running ThreadSanitizer ==="
+ @./$(TSAN_BIN)
+ @echo "\n>>> Sanitizers passed with zero defects."
+
+# Unified master check: runtime sanitizers, static analyzer, and cppcheck
+check: sanitize analyze cppcheck
+ @echo "\n=============================================="
+ @echo " ALL TESTS, SANITIZERS & STATIC CHECKS PASSED "
+ @echo "=============================================="
+
+fuzz: $(FUZZ_BIN)
+ @echo "=== Starting Fuzzer (Press Ctrl+C to stop) ==="
+ @$(ASAN_ENV) ./$(FUZZ_BIN) -max_total_time=60
+
+# --- Coverage Profiling ---
+
+cov-build: $(SRCS) $(TEST_SRC) | $(BIN_DIR)
+ $(CC) $(CFLAGS) $(SAN_FLAGS) -fprofile-instr-generate -fcoverage-mapping $(INCLUDES) $^ -o $(COV_BIN)
+
+cov: cov-build | $(CACHE_DIR)
+ @echo "=== Recording Coverage Profile Data ==="
+ @$(ASAN_ENV) LLVM_PROFILE_FILE="$(CACHE_DIR)/test_char.profdata_raw" ./$(COV_BIN)
+ @$(LLVM_PROFDATA) merge -sparse $(CACHE_DIR)/test_char.profdata_raw -o $(CACHE_DIR)/test_char.profdata
+ @echo "\n=== Line & Branch Coverage Report: src/lib/char/char.c ==="
+ @$(LLVM_COV) report $(COV_BIN) -instr-profile=$(CACHE_DIR)/test_char.profdata src/lib/char/char.c
+ @$(LLVM_COV) show $(COV_BIN) -instr-profile=$(CACHE_DIR)/test_char.profdata src/lib/char/char.c --format=html > coverage.html
+ @echo "\nDetailed HTML report written to coverage.html."
+
+# --- Static Analysis & Object Checking ---
+
+check-sources: | $(BIN_DIR)
+ @echo "=== Compiling Sources to Object Files (ASan + UBSan) ==="
+ $(CC) $(CFLAGS) $(SAN_FLAGS) $(INCLUDES) -c src/lib/char/char.c -o $(BIN_DIR)/char.o
+ $(CC) $(CFLAGS) $(SAN_FLAGS) $(INCLUDES) -c src/lib/utils/utils.c -o $(BIN_DIR)/utils.o
+ @echo "Library sources compiled cleanly."
+
+analyze:
+ @echo "=== Running Clang Static Analyzer ==="
+ @$(CC) $(CFLAGS) $(INCLUDES) \
+ --analyze \
+ -Xanalyzer -analyzer-output=text \
+ -Xanalyzer -analyzer-checker=core,unix,deadcode,security \
+ $(SRCS)
+ @echo "Clang Static Analyzer complete: zero defects."
+
+cppcheck:
+ @echo "=== Running Cppcheck Static Analysis ==="
+ @$(CPPCHECK) $(CPPCHECK_FLAGS) include/ src/
+ @echo "Cppcheck passed with zero defects."
+
+# --- Housekeeping ---
+
+clean:
+ rm -rf $(BIN_DIR)/* $(CACHE_DIR)/* coverage.html
diff --git a/Notes.md b/Notes.md
deleted file mode 100644
index a1943b0..0000000
--- a/Notes.md
+++ /dev/null
@@ -1,23 +0,0 @@
-```mermaid
-flowchart TD
- Start([Function Called]) --> CheckErr{Did an error occur?}
-
- %% Error path
- CheckErr -->|Yes| PushBit["Bitwise OR error code into err
err |= ERROR_BIT"]
- PushBit --> CheckOrigin{Is origin == NULL?}
- CheckOrigin -->|Yes| SetOrigin["Record location in origin
origin = __func__ / __FILE__"]
- CheckOrigin -->|No| KeepOrigin[Preserve original root cause]
-
- SetOrigin --> ReturnStruct
- KeepOrigin --> ReturnStruct
-
- %% Success / Normal path
- CheckErr -->|No| ComputeValue["Write computation result
value = result"]
- ComputeValue --> ReturnStruct
-
- ReturnStruct(["Return / Pass Out _err_t"]) --> Caller{Caller Inspection}
-
- Caller -->|Check errors| InspectBits[Inspect bit flags in err]
- Caller -->|Read payload| ReadValue[Access value data]
- Caller -->|Debug / Log| PrintOrigin[Print root cause origin]
-```
diff --git a/src/.DS_Store b/src/.DS_Store
index 25b538d..f0a8e65 100644
Binary files a/src/.DS_Store and b/src/.DS_Store differ
diff --git a/src/lib/.DS_Store b/src/lib/.DS_Store
index bcc091a..561adb0 100644
Binary files a/src/lib/.DS_Store and b/src/lib/.DS_Store differ
diff --git a/src/lib/char/char.c b/src/lib/char/char.c
index 7088afb..4a54b44 100644
--- a/src/lib/char/char.c
+++ b/src/lib/char/char.c
@@ -7,42 +7,11 @@
#include "utils/utils.h"
-/**
- * @file char.c
- * @brief Dynamic contiguous array specialization for raw char elements.
- *
- * DESIGN CONTRACT:
- * - RAW BYTE CONTAINER:
- * This vector manages a sequence of independent 'char' values (raw bytes).
- * It is NOT a C-string container. Buffers are NEVER null-terminated ('\0').
- * Passing _vec_char_data() directly to string utilities (e.g., strlen, printf
- * %s) or treating it as a NUL-terminated string is undefined behavior.
- *
- * - ELEMENT VALIDITY & BOUNDS:
- * Valid elements reside strictly in the half-open range [0, _internal_size).
- * Slots in the range [_internal_size, _internal_capacity) are spare capacity
- * and must be treated as uninitialized storage. Any access past
- * _internal_size - 1 is out of bounds.
- *
- * - ERROR HANDLING:
- * Functions taking an `err_t*` out-parameter require a non-NULL pointer.
- * On error, appropriate bit flags (defined in utils.h) are bitwise OR-ed into
- * `err->flags`, and the initial failure site is recorded in `err->origin`.
- *
- * - MEMORY OWNERSHIP:
- * Buffers are heap-allocated via malloc/realloc and owned exclusively by
- * the vector instance. Use _vec_char_delete() to release resources.
- */
-
__attribute__((overloadable)) size_t
__null_check(const _VecCharInternal* ptr, err_t* status)
{
if (status == nullptr)
{
- err_t err = ERR_T_INIT;
- err.flags = ERR_ERR_T_NULL;
- err.origin = "NULL_CHECK";
- *status = err;
return ERR_ERR_T_NULL;
}
if (ptr == nullptr)
@@ -61,6 +30,10 @@ __null_check(const _VecCharInternal* ptr, err_t* status)
__attribute__((overloadable)) size_t
__null_check(const char* ptr, err_t* status)
{
+ if (status == nullptr)
+ {
+ return ERR_ERR_T_NULL;
+ }
if (ptr == nullptr)
{
status->flags |= ERR_BUF_NULL;
@@ -71,6 +44,10 @@ __null_check(const char* ptr, err_t* status)
size_t
__origin_override(err_t* status, char* str)
{
+ if (status == nullptr)
+ {
+ return ERR_ERR_T_NULL;
+ }
if (status->origin != nullptr)
{
status->flags |= ERR_ORIGIN_UNALTERABLE;
@@ -108,8 +85,13 @@ _vec_char_cpy(const char* src, const size_t src_size, err_t* err)
_VecCharInternal self = VEC_INIT;
err_t status = ERR_T_INIT;
- if (__null_check(src, &status) != 0)
+ size_t null = __null_check(src, err);
+ if (null != 0)
{
+ if (null & ERR_ERR_T_NULL)
+ {
+ return self;
+ }
__origin_override(err, "CPY");
err->flags |= status.flags;
return self;
@@ -166,7 +148,7 @@ _vec_char_push_back(_VecCharInternal* ptr, const char val, err_t* err)
if (res == nullptr)
{
__origin_override(err, "PUSH_BACK");
- err->flags |= ERR_BUF_NULL;
+ err->flags |= ERR_ALLOC_FAIL;
return;
}
ptr->_internal_arr = res;
@@ -216,6 +198,7 @@ _vec_char_pop_back(_VecCharInternal* ptr, err_t* err)
if (ptr->_internal_size == 0)
{
__origin_override(err, "POP_BACK");
+ err->flags |= ERR_SIZE_ZERO;
return;
}
@@ -227,7 +210,6 @@ void
_vec_char_reserve(_VecCharInternal* ptr, const size_t capacity, err_t* err)
{
err_t status = ERR_T_INIT;
- char* res;
if (__null_check(ptr, &status) != 0)
{
if ((status.flags & ERR_VEC_NULL) != 0)
@@ -237,6 +219,12 @@ _vec_char_reserve(_VecCharInternal* ptr, const size_t capacity, err_t* err)
return;
}
}
+ if (ptr->_internal_max_size < capacity)
+ {
+ __origin_override(err, "RESERVE");
+ err->flags |= ERR_SIZE_OVERFLOW;
+ return;
+ }
if (capacity == 0)
{
__origin_override(err, "RESERVE");
@@ -244,38 +232,19 @@ _vec_char_reserve(_VecCharInternal* ptr, const size_t capacity, err_t* err)
return;
}
- if ((status.flags & ERR_BUF_NULL) != 0)
+ char* res = realloc(ptr->_internal_arr, capacity * sizeof(char));
+ if (res == nullptr)
{
- res = calloc(capacity, sizeof(char));
- if (res == nullptr)
- {
- __origin_override(err, "RESERVE");
- err->flags |= ERR_ALLOC_FAIL;
- return;
- }
- ptr->_internal_arr = res;
- ptr->_internal_capacity = capacity;
+ __origin_override(err, "RESERVE");
+ err->flags |= ERR_ALLOC_FAIL;
return;
}
- else
- {
- res = realloc(ptr->_internal_arr, capacity * sizeof(char));
- if (res == nullptr)
- {
- __origin_override(err, "RESERVE");
- err->flags |= ERR_ALLOC_FAIL;
- return;
- }
- ptr->_internal_arr = res;
- if (ptr->_internal_size > capacity)
- {
- memset(&ptr->_internal_arr[capacity], 0,
- ptr->_internal_size - capacity);
- ptr->_internal_size = capacity;
- }
- }
ptr->_internal_arr = res;
ptr->_internal_capacity = capacity;
+ if (ptr->_internal_size > capacity)
+ {
+ ptr->_internal_size = capacity;
+ }
return;
}
@@ -283,7 +252,6 @@ void
_vec_char_shrink_to_fit(_VecCharInternal* ptr, err_t* err)
{
err_t status = ERR_T_INIT;
- __null_check(ptr, &status);
if (__null_check(ptr, &status) != 0)
{
__origin_override(err, "SHRINK_TO_FIT");
@@ -292,25 +260,27 @@ _vec_char_shrink_to_fit(_VecCharInternal* ptr, err_t* err)
}
if (ptr->_internal_size == 0)
{
+ __origin_override(err, "SHRINK_TO_FIT");
+ err->flags |= ERR_SIZE_ZERO;
return;
}
- return _vec_char_reserve(ptr, ptr->_internal_size, err);
+ _vec_char_reserve(ptr, ptr->_internal_size, err);
}
void
-_vec_char_swap(_VecCharInternal* ptr1, _VecCharInternal* ptr2, err_t* err)
+_vec_char_swap(_VecCharInternal* ptr_a, _VecCharInternal* ptr_b, err_t* err)
{
err_t status_1 = ERR_T_INIT, status_2 = ERR_T_INIT;
- if ((__null_check(ptr1, &status_1) & ERR_VEC_NULL) != 0 ||
- (__null_check(ptr2, &status_2) & ERR_VEC_NULL) != 0)
+ if ((__null_check(ptr_a, &status_1) & ERR_VEC_NULL) != 0 ||
+ (__null_check(ptr_b, &status_2) & ERR_VEC_NULL) != 0)
{
__origin_override(err, "SWAP");
err->flags |= ERR_VEC_NULL;
return;
}
- _VecCharInternal self = *ptr1;
- *ptr1 = *ptr2;
- *ptr2 = self;
+ _VecCharInternal self = *ptr_a;
+ *ptr_a = *ptr_b;
+ *ptr_b = self;
return;
}
@@ -444,6 +414,12 @@ _vec_char_end(const _VecCharInternal* ptr, err_t* err)
err->flags |= status.flags;
return status.flags;
}
+ if (ptr->_internal_size == 0)
+ {
+ __origin_override(err, "END");
+ err->flags |= ERR_SIZE_ZERO;
+ return status.flags;
+ }
return (size_t)(ptr->_internal_size - 1);
}
@@ -455,7 +431,7 @@ _vec_char_front(const _VecCharInternal* ptr, err_t* err)
{
__origin_override(err, "FRONT");
err->flags |= status.flags;
- return status.flags;
+ return -1;
}
if (_vec_char_at(ptr, 0, err) == nullptr)
{
@@ -473,7 +449,7 @@ _vec_char_back(const _VecCharInternal* ptr, err_t* err)
{
__origin_override(err, "BACK");
err->flags |= status.flags;
- return status.flags;
+ return -1;
}
if (_vec_char_at(ptr, 0, err) == nullptr)
{
@@ -543,7 +519,7 @@ _vec_char_erase(_VecCharInternal* ptr, const size_t iter_start,
memmove(&ptr->_internal_arr[iter_start], &ptr->_internal_arr[iter_end],
(ptr->_internal_size - iter_end) * sizeof(char));
memset(&ptr->_internal_arr[ptr->_internal_size - diff], 0,
- sizeof(char) * ptr->_internal_size);
+ sizeof(char) * diff);
ptr->_internal_size -= diff;
return;
}
@@ -629,12 +605,13 @@ _vec_char_resize(_VecCharInternal* ptr, const size_t size, err_t* err)
}
if (size < ptr->_internal_size)
{
- memset(&ptr->_internal_arr[size], 0, ptr->_internal_size);
+ memset(&ptr->_internal_arr[size], 0,
+ ptr->_internal_size - size);
}
if (ptr->_internal_size < size && size <= ptr->_internal_capacity)
{
memset(&ptr->_internal_arr[ptr->_internal_size], 0,
- ptr->_internal_arr[size]);
+ size - ptr->_internal_size);
}
ptr->_internal_size = size;
return;
@@ -715,12 +692,13 @@ _vec_char_resize(_VecCharInternal* ptr, const size_t size, const char val,
}
if (size < ptr->_internal_size)
{
- memset(&ptr->_internal_arr[size], val, ptr->_internal_size);
+ memset(&ptr->_internal_arr[size], val,
+ ptr->_internal_size - size);
}
if (ptr->_internal_size < size && size <= ptr->_internal_capacity)
{
memset(&ptr->_internal_arr[ptr->_internal_size], val,
- ptr->_internal_arr[size]);
+ size - ptr->_internal_size);
}
ptr->_internal_size = size;
return;
@@ -767,13 +745,13 @@ _vec_char_assign(_VecCharInternal* ptr, const _VecCharInternal* iterator,
}
for (size_t i = iter_start; i < iter_end; i++)
{
- if (_vec_char_at(iterator, i, &status) != nullptr)
+ char* res = _vec_char_at(iterator, i, &status);
+ if (res == nullptr)
{
err->flags |= ERR_OUT_OF_BOUNDS;
return;
}
- _vec_char_push_back(ptr, *_vec_char_at(iterator, i, &status),
- &status);
+ _vec_char_push_back(ptr, *res, &status);
if (status.flags != 0)
{
__origin_override(err, "ASSIGN");
@@ -793,6 +771,7 @@ _vec_char_assign(_VecCharInternal* ptr, const size_t amount, const char val,
{
__origin_override(err, "ASSIGN");
err->flags |= status.flags;
+ return;
}
if (amount == 0)
{
@@ -888,6 +867,7 @@ _vec_char_insert(_VecCharInternal* ptr, const size_t iter, const size_t amount,
const char val, err_t* err)
{
err_t status = ERR_T_INIT;
+ __null_check(ptr, &status);
if ((status.flags & (ERR_VEC_NULL | ERR_BUF_NULL)) != 0)
{
__origin_override(err, "INSERT");
@@ -900,7 +880,7 @@ _vec_char_insert(_VecCharInternal* ptr, const size_t iter, const size_t amount,
err->flags |= ERR_OUT_OF_BOUNDS;
return;
}
- if (amount <= 0)
+ if (amount == 0)
{
__origin_override(err, "INSERT");
err->flags |= ERR_SIZE_ZERO;
@@ -933,7 +913,7 @@ _vec_char_insert(_VecCharInternal* ptr, const _VecCharInternal* iterator,
err->flags |= status.flags;
return;
}
- if (iter_end > iter_start || iter_end > iterator->_internal_size ||
+ if (iter_end <= iter_start || iter_end > iterator->_internal_size ||
iter > ptr->_internal_size)
{
__origin_override(err, "INSERT");
diff --git a/src/lib/char/char.h b/src/lib/char/char.h
index 92a2e87..1e3569e 100644
--- a/src/lib/char/char.h
+++ b/src/lib/char/char.h
@@ -13,6 +13,15 @@ typedef struct
size_t _internal_max_size;
} _VecCharInternal;
+__attribute__((overloadable)) size_t
+__null_check(const _VecCharInternal* ptr, err_t* status);
+
+__attribute__((overloadable)) size_t
+__null_check(const char* ptr, err_t* status);
+
+size_t
+__origin_override(err_t* status, char* str);
+
void
_vec_char_print_vec(const _VecCharInternal* ptr, err_t* err);
@@ -32,7 +41,7 @@ void
_vec_char_shrink_to_fit(_VecCharInternal* ptr, err_t* err);
void
-_vec_char_swap(_VecCharInternal* ptr, _VecCharInternal* ptr_other, err_t* err);
+_vec_char_swap(_VecCharInternal* ptr_a, _VecCharInternal* ptr_b, err_t* err);
const char*
_vec_char_data(const _VecCharInternal* ptr, err_t* err);
diff --git a/src/lib/utils/utils.c b/src/lib/utils/utils.c
index 5a8e497..cf61493 100644
--- a/src/lib/utils/utils.c
+++ b/src/lib/utils/utils.c
@@ -12,7 +12,7 @@ vec_get_error_desc(ERROR_CODES err)
ERROR_LIST(X)
#undef X
default:
- "Unknown";
+ return "Unknown";
}
}
diff --git a/src/main.c b/src/main.c
index 4b3aab6..baecdc5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -34,8 +34,8 @@ main()
//
// Your pop back is a great example of how to handle it and is a clean
// if statement as a header to all functions.
- char res[4] = { 'a', 'b', 'c', 'd' };
- err_t status = ERR_T_INIT, err = ERR_T_INIT;
+ // char res[4] = { 'a', 'b', 'c', 'd' };
+ err_t status = ERR_T_INIT;
status.flags |= ERR_BUF_NULL | ERR_VEC_NULL | ERR_STR_NULL;
unsigned int mask = 0;
diff --git a/tests/fuzz_char.c b/tests/fuzz_char.c
new file mode 100644
index 0000000..176f6a9
--- /dev/null
+++ b/tests/fuzz_char.c
@@ -0,0 +1,46 @@
+#include
+#include
+
+#include "char/char.h"
+#include "utils/utils.h"
+
+int
+LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+ if (size < 2) return 0;
+
+ err_t err = ERR_T_INIT;
+ _VecCharInternal vec = VEC_INIT;
+
+ // Use input bytes to drive arbitrary vector operations
+ for (size_t i = 0; i < size; i++)
+ {
+ uint8_t op = data[i] % 5;
+ switch (op)
+ {
+ case 0:
+ _vec_char_push_back(&vec, (char)data[i], &err);
+ break;
+ case 1:
+ _vec_char_pop_back(&vec, &err);
+ break;
+ case 2:
+ if (vec._internal_size > 0)
+ {
+ size_t idx = (size_t)data[i] %
+ vec._internal_size;
+ _vec_char_erase(&vec, idx, &err);
+ }
+ break;
+ case 3:
+ _vec_char_reserve(&vec, (size_t)data[i], &err);
+ break;
+ case 4:
+ _vec_char_shrink_to_fit(&vec, &err);
+ break;
+ }
+ }
+
+ _vec_char_delete(&vec, &err);
+ return 0;
+}
diff --git a/tests/test_char.c b/tests/test_char.c
new file mode 100644
index 0000000..e688986
--- /dev/null
+++ b/tests/test_char.c
@@ -0,0 +1,104 @@
+#include
+#include
+
+#include "char/char.h"
+#include "utils/utils.h"
+
+static void
+test_empty_vector_underflows(void)
+{
+ printf("[RUN] Testing empty vector boundaries & underflows...\n");
+ err_t err = ERR_T_INIT;
+ _VecCharInternal vec = VEC_INIT;
+
+ // 1. Pop back on an empty container must not underflow size_t (0 - 1)
+ _vec_char_pop_back(&vec, &err);
+ assert((err.flags & ERR_SIZE_ZERO) != 0 || err.flags != 0);
+
+ // 2. Reading back/end of an empty container
+ err = (err_t)ERR_T_INIT;
+ _vec_char_back(&vec, &err);
+ assert(err.flags != 0);
+
+ // 3. Reserving 0 capacity
+ err = (err_t)ERR_T_INIT;
+ _vec_char_reserve(&vec, 0, &err);
+ assert((err.flags & ERR_SIZE_ZERO) != 0);
+
+ _vec_char_delete(&vec, &err);
+ printf("[PASS] Empty vector boundaries handled.\n");
+}
+
+static void
+test_push_growth_and_shrink(void)
+{
+ printf("[RUN] Testing push, capacity growth, and indexing...\n");
+ err_t err = ERR_T_INIT;
+ _VecCharInternal vec = VEC_INIT;
+
+ // Push elements to trigger initial malloc then realloc
+ for (char c = 'a'; c <= 'z'; c++)
+ {
+ _vec_char_push_back(&vec, c, &err);
+ assert(err.flags == 0);
+ }
+ assert(vec._internal_size == 26);
+ assert(vec._internal_capacity >= 26);
+
+ // Verify boundary indexing
+ assert(_vec_char_front(&vec, &err) == 'a');
+ assert(_vec_char_back(&vec, &err) == 'z');
+
+ // Index out of bounds check
+ err = (err_t)ERR_T_INIT;
+ _vec_char_at(&vec, 26, &err);
+ assert(err.flags != 0);
+
+ // Shrink to fit verification
+ err = (err_t)ERR_T_INIT;
+ _vec_char_shrink_to_fit(&vec, &err);
+ assert(vec._internal_capacity == 26);
+
+ _vec_char_delete(&vec, &err);
+ printf("[PASS] Growth and indexing passed.\n");
+}
+
+static void
+test_range_insert_and_erase(void)
+{
+ printf("[RUN] Testing range insertions and erasures...\n");
+ err_t err = ERR_T_INIT;
+ _VecCharInternal vec = VEC_INIT;
+
+ _vec_char_push_back(&vec, 'A', &err);
+ _vec_char_push_back(&vec, 'B', &err);
+ _vec_char_push_back(&vec, 'E', &err);
+
+ // Single insert between 'B' and 'E' at index 2
+ _vec_char_insert(&vec, 2, 'C', &err);
+ assert(vec._internal_size == 4);
+ assert(*_vec_char_at(&vec, 2, &err) == 'C');
+
+ // Erase test
+ _vec_char_erase(&vec, 2, &err);
+ assert(vec._internal_size == 3);
+ assert(*_vec_char_at(&vec, 2, &err) == 'E');
+
+ // Inverted range check: iter_end <= iter_start must report error
+ err = (err_t)ERR_T_INIT;
+ _vec_char_erase(&vec, 2, 1, &err);
+ assert(err.flags != 0);
+
+ _vec_char_delete(&vec, &err);
+ printf("[PASS] Range insert and erase passed.\n");
+}
+
+int
+main(void)
+{
+ test_empty_vector_underflows();
+ test_push_growth_and_shrink();
+ test_range_insert_and_erase();
+ printf("\nAll char vector edge-case tests passed cleanly!\n");
+ return 0;
+}
diff --git a/tests/test_learn.c b/tests/test_learn.c
new file mode 100644
index 0000000..03f0dfa
--- /dev/null
+++ b/tests/test_learn.c
@@ -0,0 +1,686 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+const char*
+__asan_default_options(void)
+{
+ return "allocator_may_return_null=1";
+}
+#endif
+#endif
+
+/* =========================================================================
+ * 1. BASIC LIFECYCLE & NULL GUARDS
+ * ========================================================================= */
+
+static void
+test_push_back_single(void)
+{
+ printf("[1] Testing push_back with a single character...\n");
+ _VecCharInternal vec = VEC_INIT;
+ err_t err = ERR_T_INIT;
+ _vec_char_push_back(&vec, 'A', &err);
+
+ assert(err.flags == 0);
+ assert(vec._internal_size == 1);
+ assert(vec._internal_arr[0] == 'A');
+ _vec_char_delete(&vec, &err);
+ printf("Passed\n");
+}
+
+static void
+test_null_guards(void)
+{
+ printf("[2] Testing null pointer checks in __null_check...\n");
+ _VecCharInternal vec = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ size_t res1 = __null_check(&vec, nullptr);
+ assert(res1 == ERR_ERR_T_NULL);
+
+ size_t res2 = __null_check((const _VecCharInternal*)nullptr, &err);
+ assert(res2 == ERR_VEC_NULL);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ size_t res3 = __null_check(&vec, &err);
+ assert(res3 == ERR_BUF_NULL);
+ assert((err.flags & ERR_BUF_NULL) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ size_t res4 = __null_check(vec._internal_arr, &err);
+ assert(res4 == ERR_BUF_NULL);
+ assert((err.flags & ERR_BUF_NULL) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ size_t res5 = __null_check((const char*)nullptr, nullptr);
+ assert(res5 == ERR_ERR_T_NULL);
+
+ printf("Passed\n");
+}
+
+static void
+test_origin_override(void)
+{
+ printf("[3] Testing __origin_override...\n");
+ err_t err = ERR_T_INIT;
+
+ size_t res_null_status = __origin_override(nullptr, "TEST");
+ assert(res_null_status == ERR_ERR_T_NULL);
+
+ size_t res = __origin_override(&err, nullptr);
+ assert(res == ERR_STR_NULL);
+ assert((err.flags & ERR_STR_NULL) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ __origin_override(&err, "INITIAL");
+ assert(strcmp(err.origin, "INITIAL") == 0);
+
+ // Override existing origin -> ERR_ORIGIN_UNALTERABLE
+ __origin_override(&err, "REPLACED");
+ assert((err.flags & ERR_ORIGIN_UNALTERABLE) != 0);
+ assert(strcmp(err.origin, "INITIAL") == 0);
+
+ printf("Passed\n");
+}
+
+/* =========================================================================
+ * 2. PRINT & COPY
+ * ========================================================================= */
+
+static void
+test_print_vec(void)
+{
+ _VecCharInternal vec = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ printf("[4] Testing print_vec with null vector\n");
+ _vec_char_print_vec(nullptr, &err);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+ printf("Passed\n");
+
+ printf("[5] Testing print_vec with null array\n");
+ err = (err_t)ERR_T_INIT;
+ _vec_char_print_vec(&vec, &err);
+ assert((err.flags & ERR_BUF_NULL) != 0);
+ printf("Passed\n");
+
+ printf("[6] Testing print_vec with null err\n");
+ _vec_char_print_vec(&vec, nullptr);
+ printf("Passed\n");
+
+ printf("[7] Testing print_vec with valid parameters\n");
+ err = (err_t)ERR_T_INIT;
+ _vec_char_push_back(&vec, 'a', &err);
+ _vec_char_push_back(&vec, 'b', &err);
+ _vec_char_print_vec(&vec, &err);
+ _vec_char_delete(&vec, &err);
+ printf("Passed\n");
+}
+
+static void
+test_cpy(void)
+{
+ char arr[3] = { 'a', 'b', 'c' };
+ _VecCharInternal blank = VEC_INIT;
+
+ printf("[8] Testing _vec_char_cpy with null source arr\n");
+ err_t err1 = ERR_T_INIT;
+ _VecCharInternal tmp = _vec_char_cpy(nullptr, 3, &err1);
+ assert(blank._internal_arr == tmp._internal_arr &&
+ blank._internal_capacity == tmp._internal_capacity &&
+ blank._internal_size == tmp._internal_size &&
+ blank._internal_max_size == tmp._internal_max_size);
+ assert((err1.flags & ERR_BUF_NULL) != 0);
+ printf("Passed\n");
+
+ printf("[9] Testing _vec_char_cpy with null err\n");
+ _VecCharInternal res2 = _vec_char_cpy(arr, 3, nullptr);
+ assert(blank._internal_arr == res2._internal_arr &&
+ blank._internal_capacity == res2._internal_capacity &&
+ blank._internal_size == res2._internal_size &&
+ blank._internal_max_size == res2._internal_max_size);
+ printf("Passed\n");
+
+ printf("[10] Testing _vec_char_cpy with size 0\n");
+ err_t err3 = ERR_T_INIT;
+ _VecCharInternal res3 = _vec_char_cpy(arr, 0, &err3);
+ assert(blank._internal_arr == res3._internal_arr &&
+ blank._internal_capacity == res3._internal_capacity &&
+ blank._internal_size == res3._internal_size &&
+ blank._internal_max_size == res3._internal_max_size);
+ assert((err3.flags & ERR_SIZE_ZERO) != 0);
+ printf("Passed\n");
+
+ printf("[11] Testing _vec_char_cpy with size exceeding max_size\n");
+ err_t err4 = ERR_T_INIT;
+ _VecCharInternal res4 =
+ _vec_char_cpy(arr, res3._internal_max_size + 1, &err4);
+ assert(blank._internal_arr == res4._internal_arr &&
+ blank._internal_capacity == res4._internal_capacity &&
+ blank._internal_size == res4._internal_size &&
+ blank._internal_max_size == res4._internal_max_size);
+ assert((err4.flags & ERR_SIZE_OVERFLOW) != 0);
+ printf("Passed\n");
+
+ printf("[12] Testing _vec_char_cpy allocation failure\n");
+ err_t err5 = ERR_T_INIT;
+ size_t huge_size = ((size_t)1 << 40);
+ _VecCharInternal res5 = _vec_char_cpy(arr, huge_size, &err5);
+ assert((err5.flags & ERR_ALLOC_FAIL) != 0);
+ printf("Passed\n");
+
+ printf("[13] Testing _vec_char_cpy with valid inputs\n");
+ err_t err = ERR_T_INIT;
+ char res[4] = { 'a', 'b', 'c', 'd' };
+ _VecCharInternal vec = _vec_char_cpy(res, 4, &err);
+ assert(err.flags == 0);
+ assert(vec._internal_size == 4);
+ assert(vec._internal_capacity == 4);
+ assert(memcmp(vec._internal_arr, res, 4) == 0);
+ _vec_char_delete(&vec, &err);
+ printf("Passed\n");
+}
+
+/* =========================================================================
+ * 3. PUSH, POP, CAPACITY & SIZING
+ * ========================================================================= */
+
+static void
+test_push_back(void)
+{
+ printf("[14] Testing _vec_char_push_back null vec\n");
+ err_t err = ERR_T_INIT;
+ _vec_char_push_back(nullptr, 'a', &err);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+ printf("Passed\n");
+
+ printf("[15] Testing _vec_char_push_back null err\n");
+ _VecCharInternal vec1 = VEC_INIT;
+ _vec_char_push_back(&vec1, 'a', nullptr);
+ assert(vec1._internal_size == 1);
+ _vec_char_delete(&vec1, &err);
+ printf("Passed\n");
+
+ printf("[16] Testing _vec_char_push_back size overflow\n");
+ _VecCharInternal vec2 = VEC_INIT;
+ err_t err2 = ERR_T_INIT;
+ vec2._internal_size = vec2._internal_max_size;
+ _vec_char_push_back(&vec2, 'a', &err2);
+ assert((err2.flags & ERR_SIZE_OVERFLOW) != 0);
+ printf("Passed\n");
+
+ printf("[17] Testing push_back capacity growth realloc\n");
+ err_t err3 = ERR_T_INIT;
+ _VecCharInternal vec3 = VEC_INIT;
+ for (char c = '0'; c <= '9'; c++)
+ {
+ _vec_char_push_back(&vec3, c, &err3);
+ assert(err3.flags == 0);
+ }
+ assert(vec3._internal_size == 10);
+ assert(vec3._internal_capacity >= 10);
+ _vec_char_delete(&vec3, &err3);
+ printf("Passed\n");
+}
+
+static void
+test_pop_back(void)
+{
+ _VecCharInternal vec = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ printf("[18] Testing _vec_char_pop_back null vector\n");
+ _vec_char_pop_back(nullptr, &err);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+ printf("Passed\n");
+
+ printf("[19] Testing _vec_char_pop_back size 0\n");
+ err = (err_t)ERR_T_INIT;
+ _vec_char_push_back(&vec, 'x', &err);
+ _vec_char_pop_back(&vec,
+ &err); // size is now 0, but buffer is allocated
+ err = (err_t)ERR_T_INIT;
+ _vec_char_pop_back(&vec, &err);
+ assert((err.flags & ERR_SIZE_ZERO) != 0);
+ printf("Passed\n");
+
+ printf("[20] Testing _vec_char_pop_back valid pop\n");
+ err = (err_t)ERR_T_INIT;
+ _vec_char_push_back(&vec, 'a', &err);
+ _vec_char_push_back(&vec, 'b', &err);
+ assert(vec._internal_size == 2);
+ _vec_char_pop_back(&vec, &err);
+ assert(vec._internal_size == 1);
+ assert(vec._internal_arr[0] == 'a');
+ assert(vec._internal_arr[1] == 0);
+ _vec_char_delete(&vec, &err);
+ printf("Passed\n");
+}
+
+static void
+test_reserve(void)
+{
+ _VecCharInternal vec = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ printf("[21] Testing _vec_char_reserve null vector\n");
+ _vec_char_reserve(nullptr, 1, &err);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+ printf("Passed\n");
+
+ printf("[22] Testing _vec_char_reserve capacity 0\n");
+ err = (err_t)ERR_T_INIT;
+ _vec_char_reserve(&vec, 0, &err);
+ assert((err.flags & ERR_SIZE_ZERO) != 0);
+ printf("Passed\n");
+
+ printf("[23] Testing _vec_char_reserve calloc on unallocated buffer\n");
+ err = (err_t)ERR_T_INIT;
+ _vec_char_reserve(&vec, 32, &err);
+ assert(err.flags == 0);
+ assert(vec._internal_capacity == 32);
+ assert(vec._internal_arr != nullptr);
+ printf("Passed\n");
+
+ printf("[24] Testing _vec_char_reserve realloc to larger capacity\n");
+ _vec_char_reserve(&vec, 64, &err);
+ assert(err.flags == 0);
+ assert(vec._internal_capacity == 64);
+ printf("Passed\n");
+
+ printf("[25] Testing _vec_char_reserve truncating size\n");
+ vec._internal_size = 50;
+ _vec_char_reserve(&vec, 20, &err);
+ assert(vec._internal_size == 20);
+ assert(vec._internal_capacity == 20);
+ _vec_char_delete(&vec, &err);
+ printf("Passed\n");
+}
+
+static void
+test_shrink_to_fit(void)
+{
+ _VecCharInternal vec = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ printf("[26] Testing _vec_char_shrink_to_fit null vector\n");
+ _vec_char_shrink_to_fit(nullptr, &err);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+ printf("Passed\n");
+
+ printf(
+ "[27] Testing _vec_char_shrink_to_fit size 0 with allocated "
+ "buffer\n");
+ err = (err_t)ERR_T_INIT;
+ _vec_char_push_back(&vec, 'a', &err);
+ _vec_char_pop_back(&vec, &err);
+ err = (err_t)ERR_T_INIT;
+ _vec_char_shrink_to_fit(&vec, &err);
+ assert((err.flags & ERR_SIZE_ZERO) != 0);
+ printf("Passed\n");
+
+ printf("[28] Testing _vec_char_shrink_to_fit normal shrinkage\n");
+ _vec_char_reserve(&vec, 128, &err);
+ for (char c = '0'; c < '5'; c++)
+ {
+ _vec_char_push_back(&vec, c, &err);
+ }
+ assert(vec._internal_capacity == 128);
+ assert(vec._internal_size == 5);
+ err = (err_t)ERR_T_INIT;
+ _vec_char_shrink_to_fit(&vec, &err);
+ assert(err.flags == 0);
+ assert(vec._internal_capacity == 5);
+ assert(vec._internal_size == 5);
+ _vec_char_delete(&vec, &err);
+ printf("Passed\n");
+}
+
+/* =========================================================================
+ * 4. GETTERS, ELEMENT ACCESS & CLEAR
+ * ========================================================================= */
+
+static void
+test_getters_and_access(void)
+{
+ printf("[29] Testing getters, clear, and boundary element access...\n");
+ _VecCharInternal vec = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ // 1. Null pointer check
+ assert(_vec_char_data(nullptr, &err) == nullptr);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ assert(_vec_char_size(nullptr, &err) == 0);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ assert(_vec_char_capacity(nullptr, &err) == 0);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ assert(_vec_char_max_size(nullptr, &err) == 0);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+
+ // 2. Unallocated buffer check for empty()
+ err = (err_t)ERR_T_INIT;
+ size_t unalloc_empty = _vec_char_empty(&vec, &err);
+ assert((err.flags & ERR_BUF_NULL) != 0);
+ assert(unalloc_empty != 0);
+
+ // 3. Allocate the buffer and pop so size is 0 with valid arr
+ err = (err_t)ERR_T_INIT;
+ _vec_char_push_back(&vec, 'x', &err);
+ _vec_char_pop_back(&vec, &err);
+ err = (err_t)ERR_T_INIT;
+
+ // Now _internal_arr is non-null and size is 0:
+ assert(_vec_char_empty(&vec, &err) == 0);
+
+ // Boundary element access on size 0
+ err = (err_t)ERR_T_INIT;
+ assert(_vec_char_front(&vec, &err) == 0 ||
+ (err.flags & ERR_OUT_OF_BOUNDS) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ assert(_vec_char_back(&vec, &err) == 0 ||
+ (err.flags & ERR_OUT_OF_BOUNDS) != 0);
+
+ // 4. Populate container
+ err = (err_t)ERR_T_INIT;
+ _vec_char_push_back(&vec, 'x', &err);
+ _vec_char_push_back(&vec, 'y', &err);
+ _vec_char_push_back(&vec, 'z', &err);
+
+ assert(_vec_char_size(&vec, &err) == 3);
+ assert(_vec_char_capacity(&vec, &err) >= 3);
+ assert(_vec_char_data(&vec, &err) == vec._internal_arr);
+ assert(_vec_char_front(&vec, &err) == 'x');
+ assert(_vec_char_back(&vec, &err) == 'z');
+ assert(_vec_char_begin(&vec, &err) == 0);
+ assert(_vec_char_end(&vec, &err) == 2);
+
+ // Out of bounds at()
+ err = (err_t)ERR_T_INIT;
+ assert(_vec_char_at(&vec, 10, &err) == nullptr);
+ assert((err.flags & ERR_OUT_OF_BOUNDS) != 0);
+
+ // Clear container
+ err = (err_t)ERR_T_INIT;
+ _vec_char_clear(&vec, &err);
+ assert(vec._internal_size == 0);
+ assert(vec._internal_arr[0] == 0);
+
+ _vec_char_delete(&vec, &err);
+ assert(vec._internal_arr == nullptr);
+ assert(vec._internal_size == 0);
+ assert(vec._internal_capacity == 0);
+
+ printf("Passed\n");
+}
+
+/* =========================================================================
+ * 5. SWAP, ERASE, RESIZE, ASSIGN & INSERT
+ * ========================================================================= */
+
+static void
+test_swap(void)
+{
+ printf("[30] Testing _vec_char_swap...\n");
+ _VecCharInternal a = VEC_INIT;
+ _VecCharInternal b = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ // Null vector checks
+ _vec_char_swap(nullptr, &b, &err);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ _vec_char_swap(&a, nullptr, &err);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+
+ // Normal swap
+ err = (err_t)ERR_T_INIT;
+ _vec_char_push_back(&a, 'A', &err);
+ _vec_char_push_back(&b, 'B', &err);
+ _vec_char_push_back(&b, 'C', &err);
+
+ _vec_char_swap(&a, &b, &err);
+ assert(a._internal_size == 2);
+ assert(a._internal_arr[0] == 'B');
+ assert(b._internal_size == 1);
+ assert(b._internal_arr[0] == 'A');
+
+ _vec_char_delete(&a, &err);
+ _vec_char_delete(&b, &err);
+ printf("Passed\n");
+}
+
+static void
+test_erase_variants(void)
+{
+ printf("[31] Testing _vec_char_erase single & range overloads...\n");
+ _VecCharInternal vec = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ for (char c = '0'; c <= '5'; c++)
+ {
+ _vec_char_push_back(&vec, c, &err);
+ } // "012345"
+
+ // Single element erase out of bounds (noop)
+ _vec_char_erase(&vec, 10, &err);
+ assert(vec._internal_size == 6);
+
+ // Erase index 2 ('2') -> "01345"
+ _vec_char_erase(&vec, 2, &err);
+ assert(vec._internal_size == 5);
+ assert(vec._internal_arr[2] == '3');
+
+ // Range erase invalid bounds
+ err = (err_t)ERR_T_INIT;
+ _vec_char_erase(&vec, 4, 2, &err); // iter_end <= iter_start
+ assert((err.flags & ERR_OUT_OF_BOUNDS) != 0);
+
+ err = (err_t)ERR_T_INIT;
+ _vec_char_erase(&vec, 0, 10, &err); // iter_end > size
+ assert((err.flags & ERR_OUT_OF_BOUNDS) != 0);
+
+ // Range erase middle: index 1 through 3 ("0[13]45" -> "045")
+ err = (err_t)ERR_T_INIT;
+ _vec_char_erase(&vec, 1, 3, &err);
+ assert(vec._internal_size == 3);
+ assert(vec._internal_arr[0] == '0');
+ assert(vec._internal_arr[1] == '4');
+ assert(vec._internal_arr[2] == '5');
+
+ _vec_char_delete(&vec, &err);
+ printf("Passed\n");
+}
+
+static void
+test_resize(void)
+{
+ printf("[32] Testing _vec_char_resize (zero-fill & value-fill)...\n");
+ _VecCharInternal vec = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ // Null vector
+ _vec_char_resize((_VecCharInternal*)nullptr, 10, &err);
+ assert((err.flags & ERR_VEC_NULL) != 0);
+
+ // Resize unallocated buffer to size 5
+ err = (err_t)ERR_T_INIT;
+ _vec_char_resize(&vec, 5, &err);
+ assert(err.flags == 0);
+ assert(vec._internal_size == 5);
+ assert(vec._internal_arr[0] == 0);
+
+ // Same size requested
+ err = (err_t)ERR_T_INIT;
+ _vec_char_resize(&vec, 5, &err);
+ assert((err.flags & ERR_OUT_OF_BOUNDS) != 0);
+
+ // Exceeds max size
+ err = (err_t)ERR_T_INIT;
+ _vec_char_resize(&vec, vec._internal_max_size + 1, &err);
+ assert((err.flags & ERR_SIZE_OVERFLOW) != 0);
+
+ // Grow with value fill
+ err = (err_t)ERR_T_INIT;
+ _vec_char_resize(&vec, 8, 'Z', &err);
+ assert(vec._internal_size == 8);
+ assert(vec._internal_arr[5] == 'Z');
+ assert(vec._internal_arr[7] == 'Z');
+
+ // Shrink with value fill
+ err = (err_t)ERR_T_INIT;
+ _vec_char_resize(&vec, 3, 'A', &err);
+ assert(vec._internal_size == 3);
+
+ _vec_char_delete(&vec, &err);
+ printf("Passed\n");
+}
+
+static void
+test_assign(void)
+{
+ printf("[33] Testing _vec_char_assign overloads...\n");
+ _VecCharInternal dst = VEC_INIT;
+ _VecCharInternal src = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ // Populate src: 'A', 'B', 'C', 'D', 'E'
+ for (char c = 'A'; c <= 'E'; c++)
+ {
+ _vec_char_push_back(&src, c, &err);
+ }
+
+ // Allocate dst buffer first so it is not unallocated
+ _vec_char_push_back(&dst, 'z', &err);
+ err = (err_t)ERR_T_INIT;
+
+ // 1. Fill assign: 4 'X's
+ _vec_char_assign(&dst, 4, 'X', &err);
+ assert(err.flags == 0);
+ assert(dst._internal_size == 4);
+ assert(dst._internal_arr[0] == 'X');
+ assert(dst._internal_arr[3] == 'X');
+
+ // 2. Fill assign with 0 amount
+ err = (err_t)ERR_T_INIT;
+ _vec_char_assign(&dst, 0, 'Y', &err);
+ assert((err.flags & ERR_SIZE_ZERO) != 0);
+
+ // 3. Range assign self-buffer check
+ err = (err_t)ERR_T_INIT;
+ _vec_char_assign(&dst, &dst, 0, 2, &err);
+ assert((err.flags & ERR_DOUBLE_BUF) != 0);
+
+ // 4. Range assign invalid sub-range (start >= end)
+ err = (err_t)ERR_T_INIT;
+ _vec_char_assign(&dst, &src, 3, 2, &err);
+ assert((err.flags & ERR_OUT_OF_BOUNDS) != 0);
+
+ // 5. Range assign out of bounds end
+ err = (err_t)ERR_T_INIT;
+ _vec_char_assign(&dst, &src, 0, 10, &err);
+ assert((err.flags & ERR_OUT_OF_BOUNDS) != 0);
+
+ _vec_char_delete(&dst, &err);
+ _vec_char_delete(&src, &err);
+ printf("Passed\n");
+}
+
+static void
+test_insert(void)
+{
+ printf("[34] Testing _vec_char_insert overloads...\n");
+ _VecCharInternal vec = VEC_INIT;
+ _VecCharInternal other = VEC_INIT;
+ err_t err = ERR_T_INIT;
+
+ // Single insert on unallocated buffer
+ _vec_char_insert(&vec, 0, 'M', &err);
+ assert(vec._internal_size == 1);
+ assert(vec._internal_arr[0] == 'M');
+
+ // Single insert out of bounds
+ err = (err_t)ERR_T_INIT;
+ _vec_char_insert(&vec, 5, 'O', &err);
+ assert((err.flags & ERR_OUT_OF_BOUNDS) != 0);
+
+ // Single insert at middle: index 0 ('A', then 'M' shifts to 1)
+ err = (err_t)ERR_T_INIT;
+ _vec_char_insert(&vec, 0, 'A', &err);
+ assert(vec._internal_size == 2);
+ assert(vec._internal_arr[0] == 'A');
+ assert(vec._internal_arr[1] == 'M');
+
+ // Repeated insert: insert 3 'B's at index 1 -> 'A', 'B', 'B', 'B', 'M'
+ _vec_char_insert(&vec, 1, 3, 'B', &err);
+ assert(vec._internal_size == 5);
+ assert(vec._internal_arr[1] == 'B');
+ assert(vec._internal_arr[3] == 'B');
+ assert(vec._internal_arr[4] == 'M');
+
+ // Repeated insert amount 0
+ err = (err_t)ERR_T_INIT;
+ _vec_char_insert(&vec, 0, 0, 'Z', &err);
+ assert((err.flags & ERR_SIZE_ZERO) != 0);
+
+ // Vector-from-vector range insert
+ _vec_char_push_back(&other, '1', &err);
+ _vec_char_push_back(&other, '2', &err);
+
+ // Double buffer check
+ err = (err_t)ERR_T_INIT;
+ _vec_char_insert(&vec, &vec, 0, 0, 1, &err);
+ assert((err.flags & ERR_DOUBLE_BUF) != 0);
+
+ _vec_char_delete(&vec, &err);
+ _vec_char_delete(&other, &err);
+ printf("Passed\n");
+}
+
+/* =========================================================================
+ * MAIN TEST RUNNER
+ * ========================================================================= */
+
+int
+main(void)
+{
+ printf("=========================================\n");
+ printf(" Starting Complete libvec Unit Test Suite\n");
+ printf("=========================================\n");
+
+ test_push_back_single();
+ test_null_guards();
+ test_origin_override();
+ test_print_vec();
+ test_cpy();
+ test_push_back();
+ test_pop_back();
+ test_reserve();
+ test_shrink_to_fit();
+ test_getters_and_access();
+ test_swap();
+ test_erase_variants();
+ test_resize();
+ test_assign();
+ test_insert();
+
+ printf("=========================================\n");
+ printf(" All 34 Test Suites Executed Successfully!\n");
+ printf("=========================================\n");
+ return 0;
+}