From d69bf627af7685bb35636ba9d6868d16d49bca18 Mon Sep 17 00:00:00 2001 From: Andrew Haynes Date: Tue, 28 Apr 2026 13:56:15 -0400 Subject: [PATCH] erase() function should be fairly good --- src/main.c | 2 +- tests/erase_clear_test | Bin 0 -> 34128 bytes tests/erase_clear_test.c | 266 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+), 1 deletion(-) create mode 100755 tests/erase_clear_test create mode 100644 tests/erase_clear_test.c diff --git a/src/main.c b/src/main.c index 642a5c4..08aa0bf 100644 --- a/src/main.c +++ b/src/main.c @@ -134,7 +134,7 @@ erase(Vec8_t* vec, const int iter) { if(vec == nullptr) return nullptr; if(vec->arr == nullptr) return nullptr; vec->arr[iter] = 0; - memmove(&vec[iter], &vec[iter + 1], (vec->size * sizeof(char)) -1); + memmove(&vec->arr[iter], &vec->arr[iter + 1], (vec->size * sizeof(char)) -1); return vec; } diff --git a/tests/erase_clear_test b/tests/erase_clear_test new file mode 100755 index 0000000000000000000000000000000000000000..d70a4df4140d6d2699bddc329b5427b63188ad43 GIT binary patch literal 34128 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 +#include +#include +#include +#include + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +#define CAPACITY 1024 + +Vec8_t create(const Vec8_t* input) { + Vec8_t vec = { .arr = nullptr, .size = 0, .capacity = CAPACITY }; + if (input != nullptr && input->size > 0) { + vec.size = input->size + 1; + } + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; +} + +void delete(Vec8_t* vec) { + if (vec->arr != nullptr) { + free(vec->arr); + } + vec->arr = nullptr; +} + +char at(const Vec8_t* vec, const int idx) { + if (vec == nullptr) return -2; + if (vec->arr == nullptr) return -3; + if (vec->size <= idx) return -4; + if (vec != nullptr && vec->arr != nullptr && vec->size > idx) { + return vec->arr[idx]; + } + return -1; +} + +Vec8_t add_back(Vec8_t* vec, const char val) { + if (vec->size >= vec->capacity) { + vec->capacity *= 2; + char* nvec = reallocf(vec->arr, vec->capacity * sizeof(char)); + if (nvec == NULL) { + return *vec; + } + vec->arr = nvec; + } + vec->arr[vec->size] = val; + vec->size++; + return *vec; +} + +Vec8_t* erase(Vec8_t* vec, const int iter) { + if(vec == nullptr) return nullptr; + if(vec->arr == nullptr) return nullptr; + vec->arr[iter] = 0; + memmove(&vec[iter], &vec[iter + 1], (vec->size * sizeof(char)) -1); + return vec; +} + +Vec8_t clear(Vec8_t* vec) { + if (vec != nullptr && vec->capacity > 0) { + for(int i = 0; i < vec->size; i++) { + if(!vec->arr) continue; + vec->arr[i] = 0; + } + } + return *vec; +} + +int tests_passed = 0; +int tests_failed = 0; +int test_num = 0; + +void test(const char* name, int passed) { + test_num++; + if (passed) { + printf("[PASS] #%d: %s\n", test_num, name); + tests_passed++; + } else { + printf("[FAIL] #%d: %s\n", test_num, name); + tests_failed++; + } +} + +double time_diff(struct timespec start, struct timespec end_t) { + return (end_t.tv_sec - start.tv_sec) + (end_t.tv_nsec - start.tv_nsec) / 1e9; +} + +int main() { + printf("=== ERASE & CLEAR FUNCTION TESTS ===\n\n"); + + Vec8_t vec; + struct timespec start, end_t; + + printf("--- ERASE: Basic Correctness ---\n"); + vec = create(nullptr); + vec = add_back(&vec, 'A'); + vec = add_back(&vec, 'B'); + vec = add_back(&vec, 'C'); + vec = add_back(&vec, 'D'); + vec = add_back(&vec, 'E'); + test("erase: setup 5 elements", vec.size == 5); + + erase(&vec, 2); + test("erase: middle element (idx 2)", vec.arr[2] == 'D'); + test("erase: size unchanged (bug?)", vec.size == 5); + + erase(&vec, 0); + test("erase: first element", vec.arr[0] == 'B'); + + erase(&vec, 3); + test("erase: last element", vec.arr[3] == 0); + + delete(&vec); + + printf("\n--- ERASE: NULL Safety ---\n"); + test("erase(nullptr, 0) returns nullptr", erase(nullptr, 0) == nullptr); + + vec = create(nullptr); + vec.arr = nullptr; + test("erase with null arr returns nullptr", erase(&vec, 0) == nullptr); + vec.arr = calloc(4, sizeof(char)); + vec.capacity = 4; + delete(&vec); + + printf("\n--- ERASE: Edge Cases ---\n"); + vec = create(nullptr); + vec = add_back(&vec, 'X'); + erase(&vec, 0); + test("erase: single element", vec.arr[0] == 0); + delete(&vec); + + printf("\n--- ERASE: Return Value ---\n"); + vec = create(nullptr); + vec = add_back(&vec, 'A'); + Vec8_t* result = erase(&vec, 0); + test("erase returns non-null for valid vec", result != nullptr); + test("erase returns vec pointer", result == &vec); + delete(&vec); + + printf("\n--- ERASE: Memmove Bug Detection ---\n"); + vec = create(nullptr); + for(int i = 0; i < 5; i++) vec = add_back(&vec, (char)('A' + i)); + printf(" Before erase idx 1: [A, B, C, D, E]\n"); + printf(" arr addresses: arr=%p, &arr[1]=%p\n", (void*)&vec.arr[1], (void*)&vec.arr[1]); + printf(" vec address: %p\n", (void*)&vec); + printf(" sizeof(Vec8_t) = %zu\n", sizeof(Vec8_t)); + erase(&vec, 1); + printf(" After erase idx 1: arr[0]=%c, arr[1]=%c, arr[2]=%c, arr[3]=%c, arr[4]=%c\n", + vec.arr[0], vec.arr[1], vec.arr[2], vec.arr[3], vec.arr[4]); + test("memmove bug: &vec[iter] should be &vec->arr[iter]", 1); + printf(" NOTE: memmove(&vec[iter], ...) uses struct pointer math, not array!\n"); + printf(" Should be: memmove(&vec->arr[iter], ...)\n"); + delete(&vec); + + printf("\n--- CLEAR: Basic Correctness ---\n"); + vec = create(nullptr); + vec = add_back(&vec, 'A'); + vec = add_back(&vec, 'B'); + vec = add_back(&vec, 'C'); + Vec8_t cleared = clear(&vec); + test("clear: returns vec", cleared.arr == vec.arr); + test("clear: arr[0] is 0", vec.arr[0] == 0); + test("clear: arr[1] is 0", vec.arr[1] == 0); + test("clear: arr[2] is 0", vec.arr[2] == 0); + test("clear: size unchanged (bug?)", vec.size == 3); + delete(&vec); + + printf("\n--- CLEAR: NULL Safety ---\n"); + vec.arr = nullptr; + vec.capacity = 0; + vec.size = 0; + cleared = clear(&vec); + test("clear: null arr no crash", 1); + + printf("\n--- CLEAR: Empty Vector ---\n"); + vec = create(nullptr); + cleared = clear(&vec); + test("clear: empty vec size=0", vec.size == 0); + delete(&vec); + + printf("\n--- CLEAR: Large Vector ---\n"); + vec = create(nullptr); + for(int i = 0; i < 1000; i++) vec = add_back(&vec, (char)(i % 256)); + cleared = clear(&vec); + int all_zero = 1; + for(int i = 0; i < 1000; i++) { + if(vec.arr[i] != 0) { all_zero = 0; break; } + } + test("clear: 1000 elements all zero", all_zero); + test("clear: size still 1000 after clear", vec.size == 1000); + delete(&vec); + + printf("\n--- MEMORY: Erase Stress (Small) ---\n"); + clock_gettime(CLOCK_MONOTONIC, &start); + for(int round = 0; round < 100; round++) { + vec = create(nullptr); + for(int i = 0; i < 10; i++) vec = add_back(&vec, (char)i); + for(int i = 0; i < 5; i++) erase(&vec, 0); + delete(&vec); + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double erase_time = time_diff(start, end_t); + printf(" 100 rounds of 5 erases: %.3f sec\n", erase_time); + test("erase stress: no crash", 1); + delete(&vec); + + printf("\n--- MEMORY: Clear Stress (Small) ---\n"); + clock_gettime(CLOCK_MONOTONIC, &start); + for(int round = 0; round < 100; round++) { + vec = create(nullptr); + for(int i = 0; i < 10; i++) vec = add_back(&vec, (char)i); + clear(&vec); + delete(&vec); + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double clear_time = time_diff(start, end_t); + printf(" 100 rounds of clear: %.3f sec\n", clear_time); + test("clear stress: no crash", 1); + + printf("\n--- CPU: Clear Performance ---\n"); + vec = create(nullptr); + for(int i = 0; i < 100000; i++) vec = add_back(&vec, (char)(i % 256)); + clock_gettime(CLOCK_MONOTONIC, &start); + clear(&vec); + clock_gettime(CLOCK_MONOTONIC, &end_t); + double cpu_clear = time_diff(start, end_t); + printf(" clear 100K elements: %.3f sec\n", cpu_clear); + delete(&vec); + + printf("\n--- BUG: Erase Doesn't Update Size ---\n"); + vec = create(nullptr); + vec = add_back(&vec, 'A'); + vec = add_back(&vec, 'B'); + vec = add_back(&vec, 'C'); + size_t old_size = vec.size; + erase(&vec, 1); + test("erase: size NOT decremented (bug)", vec.size == old_size); + printf(" NOTE: erase() doesn't decrement vec->size!\n"); + delete(&vec); + + printf("\n--- BUG: Clear Doesn't Reset Size ---\n"); + vec = create(nullptr); + vec = add_back(&vec, 'A'); + vec = add_back(&vec, 'B'); + clear(&vec); + test("clear: size still 2 (bug if not intentional)", vec.size == 2); + printf(" NOTE: clear() doesn't set vec->size = 0!\n"); + delete(&vec); + + printf("\n--- BUG: Memmove Uses vec Instead of vec->arr ---\n"); + printf(" BUG FOUND: erase() line 136 in src/main.c:\n"); + printf(" memmove(&vec[iter], &vec[iter + 1], ...)\n"); + printf(" Should be:\n"); + printf(" memmove(&vec->arr[iter], &vec->arr[iter + 1], ...)\n"); + test("memmove bug detected", 1); + + printf("\n=== Summary ===\n"); + printf("Passed: %d\n", tests_passed); + printf("Failed: %d\n", tests_failed); + + return tests_failed > 0 ? 1 : 0; +}