CHORE: Bug fixing. Major changes to bugs and also unit testing
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
Checks: >
|
||||||
|
-*,
|
||||||
|
clang-analyzer-*,
|
||||||
|
bugprone-*,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
-bugprone-reserved-identifier,
|
||||||
|
performance-*,
|
||||||
|
security-*
|
||||||
+4
-1
@@ -1,2 +1,5 @@
|
|||||||
build/
|
build/
|
||||||
.cache/
|
.cache/
|
||||||
|
tests/cache/
|
||||||
|
tests/bin/
|
||||||
|
coverage.html
|
||||||
|
|||||||
@@ -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.
|
|
||||||
@@ -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
|
||||||
@@ -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<br/>err |= ERROR_BIT"]
|
|
||||||
PushBit --> CheckOrigin{Is origin == NULL?}
|
|
||||||
CheckOrigin -->|Yes| SetOrigin["Record location in origin<br/>origin = __func__ / __FILE__"]
|
|
||||||
CheckOrigin -->|No| KeepOrigin[Preserve original root cause]
|
|
||||||
|
|
||||||
SetOrigin --> ReturnStruct
|
|
||||||
KeepOrigin --> ReturnStruct
|
|
||||||
|
|
||||||
%% Success / Normal path
|
|
||||||
CheckErr -->|No| ComputeValue["Write computation result<br/>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]
|
|
||||||
```
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
+61
-81
@@ -7,42 +7,11 @@
|
|||||||
|
|
||||||
#include "utils/utils.h"
|
#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
|
__attribute__((overloadable)) size_t
|
||||||
__null_check(const _VecCharInternal* ptr, err_t* status)
|
__null_check(const _VecCharInternal* ptr, err_t* status)
|
||||||
{
|
{
|
||||||
if (status == nullptr)
|
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;
|
return ERR_ERR_T_NULL;
|
||||||
}
|
}
|
||||||
if (ptr == nullptr)
|
if (ptr == nullptr)
|
||||||
@@ -61,6 +30,10 @@ __null_check(const _VecCharInternal* ptr, err_t* status)
|
|||||||
__attribute__((overloadable)) size_t
|
__attribute__((overloadable)) size_t
|
||||||
__null_check(const char* ptr, err_t* status)
|
__null_check(const char* ptr, err_t* status)
|
||||||
{
|
{
|
||||||
|
if (status == nullptr)
|
||||||
|
{
|
||||||
|
return ERR_ERR_T_NULL;
|
||||||
|
}
|
||||||
if (ptr == nullptr)
|
if (ptr == nullptr)
|
||||||
{
|
{
|
||||||
status->flags |= ERR_BUF_NULL;
|
status->flags |= ERR_BUF_NULL;
|
||||||
@@ -71,6 +44,10 @@ __null_check(const char* ptr, err_t* status)
|
|||||||
size_t
|
size_t
|
||||||
__origin_override(err_t* status, char* str)
|
__origin_override(err_t* status, char* str)
|
||||||
{
|
{
|
||||||
|
if (status == nullptr)
|
||||||
|
{
|
||||||
|
return ERR_ERR_T_NULL;
|
||||||
|
}
|
||||||
if (status->origin != nullptr)
|
if (status->origin != nullptr)
|
||||||
{
|
{
|
||||||
status->flags |= ERR_ORIGIN_UNALTERABLE;
|
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;
|
_VecCharInternal self = VEC_INIT;
|
||||||
err_t status = ERR_T_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");
|
__origin_override(err, "CPY");
|
||||||
err->flags |= status.flags;
|
err->flags |= status.flags;
|
||||||
return self;
|
return self;
|
||||||
@@ -166,7 +148,7 @@ _vec_char_push_back(_VecCharInternal* ptr, const char val, err_t* err)
|
|||||||
if (res == nullptr)
|
if (res == nullptr)
|
||||||
{
|
{
|
||||||
__origin_override(err, "PUSH_BACK");
|
__origin_override(err, "PUSH_BACK");
|
||||||
err->flags |= ERR_BUF_NULL;
|
err->flags |= ERR_ALLOC_FAIL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ptr->_internal_arr = res;
|
ptr->_internal_arr = res;
|
||||||
@@ -216,6 +198,7 @@ _vec_char_pop_back(_VecCharInternal* ptr, err_t* err)
|
|||||||
if (ptr->_internal_size == 0)
|
if (ptr->_internal_size == 0)
|
||||||
{
|
{
|
||||||
__origin_override(err, "POP_BACK");
|
__origin_override(err, "POP_BACK");
|
||||||
|
err->flags |= ERR_SIZE_ZERO;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +210,6 @@ void
|
|||||||
_vec_char_reserve(_VecCharInternal* ptr, const size_t capacity, err_t* err)
|
_vec_char_reserve(_VecCharInternal* ptr, const size_t capacity, err_t* err)
|
||||||
{
|
{
|
||||||
err_t status = ERR_T_INIT;
|
err_t status = ERR_T_INIT;
|
||||||
char* res;
|
|
||||||
if (__null_check(ptr, &status) != 0)
|
if (__null_check(ptr, &status) != 0)
|
||||||
{
|
{
|
||||||
if ((status.flags & ERR_VEC_NULL) != 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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ptr->_internal_max_size < capacity)
|
||||||
|
{
|
||||||
|
__origin_override(err, "RESERVE");
|
||||||
|
err->flags |= ERR_SIZE_OVERFLOW;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (capacity == 0)
|
if (capacity == 0)
|
||||||
{
|
{
|
||||||
__origin_override(err, "RESERVE");
|
__origin_override(err, "RESERVE");
|
||||||
@@ -244,38 +232,19 @@ _vec_char_reserve(_VecCharInternal* ptr, const size_t capacity, err_t* err)
|
|||||||
return;
|
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));
|
__origin_override(err, "RESERVE");
|
||||||
if (res == nullptr)
|
err->flags |= ERR_ALLOC_FAIL;
|
||||||
{
|
|
||||||
__origin_override(err, "RESERVE");
|
|
||||||
err->flags |= ERR_ALLOC_FAIL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ptr->_internal_arr = res;
|
|
||||||
ptr->_internal_capacity = capacity;
|
|
||||||
return;
|
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_arr = res;
|
||||||
ptr->_internal_capacity = capacity;
|
ptr->_internal_capacity = capacity;
|
||||||
|
if (ptr->_internal_size > capacity)
|
||||||
|
{
|
||||||
|
ptr->_internal_size = capacity;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +252,6 @@ void
|
|||||||
_vec_char_shrink_to_fit(_VecCharInternal* ptr, err_t* err)
|
_vec_char_shrink_to_fit(_VecCharInternal* ptr, err_t* err)
|
||||||
{
|
{
|
||||||
err_t status = ERR_T_INIT;
|
err_t status = ERR_T_INIT;
|
||||||
__null_check(ptr, &status);
|
|
||||||
if (__null_check(ptr, &status) != 0)
|
if (__null_check(ptr, &status) != 0)
|
||||||
{
|
{
|
||||||
__origin_override(err, "SHRINK_TO_FIT");
|
__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)
|
if (ptr->_internal_size == 0)
|
||||||
{
|
{
|
||||||
|
__origin_override(err, "SHRINK_TO_FIT");
|
||||||
|
err->flags |= ERR_SIZE_ZERO;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return _vec_char_reserve(ptr, ptr->_internal_size, err);
|
_vec_char_reserve(ptr, ptr->_internal_size, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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;
|
err_t status_1 = ERR_T_INIT, status_2 = ERR_T_INIT;
|
||||||
if ((__null_check(ptr1, &status_1) & ERR_VEC_NULL) != 0 ||
|
if ((__null_check(ptr_a, &status_1) & ERR_VEC_NULL) != 0 ||
|
||||||
(__null_check(ptr2, &status_2) & ERR_VEC_NULL) != 0)
|
(__null_check(ptr_b, &status_2) & ERR_VEC_NULL) != 0)
|
||||||
{
|
{
|
||||||
__origin_override(err, "SWAP");
|
__origin_override(err, "SWAP");
|
||||||
err->flags |= ERR_VEC_NULL;
|
err->flags |= ERR_VEC_NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_VecCharInternal self = *ptr1;
|
_VecCharInternal self = *ptr_a;
|
||||||
*ptr1 = *ptr2;
|
*ptr_a = *ptr_b;
|
||||||
*ptr2 = self;
|
*ptr_b = self;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,6 +414,12 @@ _vec_char_end(const _VecCharInternal* ptr, err_t* err)
|
|||||||
err->flags |= status.flags;
|
err->flags |= status.flags;
|
||||||
return 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);
|
return (size_t)(ptr->_internal_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,7 +431,7 @@ _vec_char_front(const _VecCharInternal* ptr, err_t* err)
|
|||||||
{
|
{
|
||||||
__origin_override(err, "FRONT");
|
__origin_override(err, "FRONT");
|
||||||
err->flags |= status.flags;
|
err->flags |= status.flags;
|
||||||
return status.flags;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_vec_char_at(ptr, 0, err) == nullptr)
|
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");
|
__origin_override(err, "BACK");
|
||||||
err->flags |= status.flags;
|
err->flags |= status.flags;
|
||||||
return status.flags;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_vec_char_at(ptr, 0, err) == nullptr)
|
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],
|
memmove(&ptr->_internal_arr[iter_start], &ptr->_internal_arr[iter_end],
|
||||||
(ptr->_internal_size - iter_end) * sizeof(char));
|
(ptr->_internal_size - iter_end) * sizeof(char));
|
||||||
memset(&ptr->_internal_arr[ptr->_internal_size - diff], 0,
|
memset(&ptr->_internal_arr[ptr->_internal_size - diff], 0,
|
||||||
sizeof(char) * ptr->_internal_size);
|
sizeof(char) * diff);
|
||||||
ptr->_internal_size -= diff;
|
ptr->_internal_size -= diff;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -629,12 +605,13 @@ _vec_char_resize(_VecCharInternal* ptr, const size_t size, err_t* err)
|
|||||||
}
|
}
|
||||||
if (size < ptr->_internal_size)
|
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)
|
if (ptr->_internal_size < size && size <= ptr->_internal_capacity)
|
||||||
{
|
{
|
||||||
memset(&ptr->_internal_arr[ptr->_internal_size], 0,
|
memset(&ptr->_internal_arr[ptr->_internal_size], 0,
|
||||||
ptr->_internal_arr[size]);
|
size - ptr->_internal_size);
|
||||||
}
|
}
|
||||||
ptr->_internal_size = size;
|
ptr->_internal_size = size;
|
||||||
return;
|
return;
|
||||||
@@ -715,12 +692,13 @@ _vec_char_resize(_VecCharInternal* ptr, const size_t size, const char val,
|
|||||||
}
|
}
|
||||||
if (size < ptr->_internal_size)
|
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)
|
if (ptr->_internal_size < size && size <= ptr->_internal_capacity)
|
||||||
{
|
{
|
||||||
memset(&ptr->_internal_arr[ptr->_internal_size], val,
|
memset(&ptr->_internal_arr[ptr->_internal_size], val,
|
||||||
ptr->_internal_arr[size]);
|
size - ptr->_internal_size);
|
||||||
}
|
}
|
||||||
ptr->_internal_size = size;
|
ptr->_internal_size = size;
|
||||||
return;
|
return;
|
||||||
@@ -767,13 +745,13 @@ _vec_char_assign(_VecCharInternal* ptr, const _VecCharInternal* iterator,
|
|||||||
}
|
}
|
||||||
for (size_t i = iter_start; i < iter_end; i++)
|
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;
|
err->flags |= ERR_OUT_OF_BOUNDS;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_vec_char_push_back(ptr, *_vec_char_at(iterator, i, &status),
|
_vec_char_push_back(ptr, *res, &status);
|
||||||
&status);
|
|
||||||
if (status.flags != 0)
|
if (status.flags != 0)
|
||||||
{
|
{
|
||||||
__origin_override(err, "ASSIGN");
|
__origin_override(err, "ASSIGN");
|
||||||
@@ -793,6 +771,7 @@ _vec_char_assign(_VecCharInternal* ptr, const size_t amount, const char val,
|
|||||||
{
|
{
|
||||||
__origin_override(err, "ASSIGN");
|
__origin_override(err, "ASSIGN");
|
||||||
err->flags |= status.flags;
|
err->flags |= status.flags;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (amount == 0)
|
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)
|
const char val, err_t* err)
|
||||||
{
|
{
|
||||||
err_t status = ERR_T_INIT;
|
err_t status = ERR_T_INIT;
|
||||||
|
__null_check(ptr, &status);
|
||||||
if ((status.flags & (ERR_VEC_NULL | ERR_BUF_NULL)) != 0)
|
if ((status.flags & (ERR_VEC_NULL | ERR_BUF_NULL)) != 0)
|
||||||
{
|
{
|
||||||
__origin_override(err, "INSERT");
|
__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;
|
err->flags |= ERR_OUT_OF_BOUNDS;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (amount <= 0)
|
if (amount == 0)
|
||||||
{
|
{
|
||||||
__origin_override(err, "INSERT");
|
__origin_override(err, "INSERT");
|
||||||
err->flags |= ERR_SIZE_ZERO;
|
err->flags |= ERR_SIZE_ZERO;
|
||||||
@@ -933,7 +913,7 @@ _vec_char_insert(_VecCharInternal* ptr, const _VecCharInternal* iterator,
|
|||||||
err->flags |= status.flags;
|
err->flags |= status.flags;
|
||||||
return;
|
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)
|
iter > ptr->_internal_size)
|
||||||
{
|
{
|
||||||
__origin_override(err, "INSERT");
|
__origin_override(err, "INSERT");
|
||||||
|
|||||||
+10
-1
@@ -13,6 +13,15 @@ typedef struct
|
|||||||
size_t _internal_max_size;
|
size_t _internal_max_size;
|
||||||
} _VecCharInternal;
|
} _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
|
void
|
||||||
_vec_char_print_vec(const _VecCharInternal* ptr, err_t* err);
|
_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);
|
_vec_char_shrink_to_fit(_VecCharInternal* ptr, err_t* err);
|
||||||
|
|
||||||
void
|
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*
|
const char*
|
||||||
_vec_char_data(const _VecCharInternal* ptr, err_t* err);
|
_vec_char_data(const _VecCharInternal* ptr, err_t* err);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ vec_get_error_desc(ERROR_CODES err)
|
|||||||
ERROR_LIST(X)
|
ERROR_LIST(X)
|
||||||
#undef X
|
#undef X
|
||||||
default:
|
default:
|
||||||
"Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -34,8 +34,8 @@ main()
|
|||||||
//
|
//
|
||||||
// Your pop back is a great example of how to handle it and is a clean
|
// Your pop back is a great example of how to handle it and is a clean
|
||||||
// if statement as a header to all functions.
|
// if statement as a header to all functions.
|
||||||
char res[4] = { 'a', 'b', 'c', 'd' };
|
// char res[4] = { 'a', 'b', 'c', 'd' };
|
||||||
err_t status = ERR_T_INIT, err = ERR_T_INIT;
|
err_t status = ERR_T_INIT;
|
||||||
status.flags |= ERR_BUF_NULL | ERR_VEC_NULL | ERR_STR_NULL;
|
status.flags |= ERR_BUF_NULL | ERR_VEC_NULL | ERR_STR_NULL;
|
||||||
|
|
||||||
unsigned int mask = 0;
|
unsigned int mask = 0;
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,686 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <char/char.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <utils/utils.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user