diff --git a/src/main.c b/src/main.c index 11b4a48..7e84fe9 100644 --- a/src/main.c +++ b/src/main.c @@ -126,7 +126,7 @@ at(const Vec8_t* vec, const int idx) // - Result: a b \0 \0 g h i j (size=8, should be 7) __attribute__((overloadable)) Vec8_t* -erase(Vec8_t* vec, const int iter) { +erase(Vec8_t* vec, const size_t iter) { if(vec == nullptr) return nullptr; if(vec->arr == nullptr) return nullptr; if(iter >= vec->size) return nullptr; @@ -137,13 +137,14 @@ erase(Vec8_t* vec, const int iter) { } __attribute__((overloadable)) Vec8_t* -erase(Vec8_t* vec, const int iter_start, const int iter_end) { +erase(Vec8_t* vec, const size_t iter_start, const size_t iter_end) { if(vec == nullptr) return nullptr; if(vec->arr == nullptr) return nullptr; - if(iter_start < 0 || iter_end > vec->size) return nullptr; - int diff = iter_end - iter_start; + if(iter_start < 0 || iter_end >= vec->size) return nullptr; + if(iter_start >= iter_end) return nullptr; + size_t diff = iter_end - iter_start; memmove(&vec->arr[iter_start], &vec->arr[iter_end], (vec->size - iter_end) * sizeof(char)); - for(size_t i = vec->size; i > iter_end; i--) { + for(size_t i = vec->size - diff; i < vec->size; i++) { vec->arr[i] = 0; } vec->size -= diff; diff --git a/tests/erase_stress_test b/tests/erase_stress_test new file mode 100755 index 0000000..1d1b3d0 Binary files /dev/null and b/tests/erase_stress_test differ diff --git a/tests/erase_stress_test.c b/tests/erase_stress_test.c new file mode 100644 index 0000000..e84d283 --- /dev/null +++ b/tests/erase_stress_test.c @@ -0,0 +1,418 @@ +#include +#include +#include +#include +#include + +#define CAPACITY 1024 +#define nullptr ((void*)0) + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +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; } +} + +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; +} + +// Exact copy of src/main.c single erase (lines 128-137) +__attribute__((overloadable)) Vec8_t* +erase(Vec8_t* vec, const int iter) { + if(vec == nullptr) return nullptr; + if(vec->arr == nullptr) return nullptr; + if(iter >= vec->size) return nullptr; + memmove(&vec->arr[iter], &vec->arr[iter + 1], (vec->size - iter - 1) * sizeof(char)); + vec->arr[vec->size - 1] = 0; + vec->size--; + return vec; +} + +// Exact copy of src/main.c range erase (lines 139-152) +__attribute__((overloadable)) Vec8_t* +erase(Vec8_t* vec, const int iter_start, const int iter_end) { + if(vec == nullptr) return nullptr; + if(vec->arr == nullptr) return nullptr; + if(iter_start < 0 || iter_end >= vec->size) return nullptr; + if(iter_start >= iter_end) return nullptr; + size_t diff = iter_end - iter_start; + memmove(&vec->arr[iter_start], &vec->arr[iter_end], (vec->size - iter_end) * sizeof(char)); + for(size_t i = vec->size - 1; i > iter_end; i--) { + vec->arr[i] = 0; + } + vec->size -= diff; + return vec; +} + +void print_vec(const Vec8_t* vec) { + for (int i = 0; i < vec->size; i++) printf("%c ", vec->arr[i]); + printf("(size=%zu)\n", vec->size); +} + +// Test 1: Basic single erase +void test_single_erase_basic() { + printf("Test: Single erase basic\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i); + + erase(&vec, 2); // Erase 'c' + + assert(vec.size == 9); + assert(vec.arr[0] == 'a'); + assert(vec.arr[1] == 'b'); + assert(vec.arr[2] == 'd'); // Shifted correctly + assert(vec.arr[8] == 'j'); // Last element correct + printf("PASS\n\n"); + delete(&vec); +} + +// Test 2: Single erase at boundaries +void test_single_erase_boundaries() { + printf("Test: Single erase at boundaries\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 5; i++) add_back(&vec, 'a' + i); + + // Erase first element + erase(&vec, 0); + assert(vec.size == 4); + assert(vec.arr[0] == 'b'); + printf("Erase first: PASS\n"); + + // Reset + delete(&vec); + vec = create(nullptr); + for (int i = 0; i < 5; i++) add_back(&vec, 'a' + i); + + // Erase last element + erase(&vec, 4); + assert(vec.size == 4); + assert(vec.arr[3] == 'd'); + printf("Erase last: PASS\n"); + + delete(&vec); + printf("\n"); +} + +// Test 3: Single erase invalid inputs +void test_single_erase_invalid() { + printf("Test: Single erase invalid inputs\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 5; i++) add_back(&vec, 'a' + i); + + // Erase with negative index + assert(erase(&vec, -1) == nullptr); + + // Erase with out-of-bounds index + assert(erase(&vec, 10) == nullptr); + assert(erase(&vec, 5) == nullptr); + + // Erase on null vector + assert(erase(nullptr, 0) == nullptr); + + // Erase on vector with null arr + Vec8_t vec2 = { .arr = nullptr, .size = 0, .capacity = 0 }; + assert(erase(&vec2, 0) == nullptr); + + printf("PASS\n\n"); + delete(&vec); +} + +// Test 4: Range erase basic +void test_range_erase_basic() { + printf("Test: Range erase basic\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i); + + erase(&vec, 2, 4); // Erase [2,4) -> 'c','d' + + printf("After erase(2,4): "); + print_vec(&vec); + + assert(vec.size == 8); + assert(vec.arr[0] == 'a'); + assert(vec.arr[1] == 'b'); + assert(vec.arr[2] == 'e'); // Shifted correctly + assert(vec.arr[7] == 'j'); // Last element correct + + // Check that valid data is not zeroed incorrectly + for (int i = 0; i < vec.size; i++) { + assert(vec.arr[i] != 0); // Valid positions should not be zero + } + + printf("PASS\n\n"); + delete(&vec); +} + +// Test 5: Range erase - verify zeroing works correctly now +void test_range_erase_zeroing_fixed() { + printf("Test: Range erase zeroing verification\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i); + + erase(&vec, 2, 4); + + printf("After erase(2,4): "); + print_vec(&vec); + + // Verify valid data is not zeroed + for (int i = 0; i < vec.size; i++) { + assert(vec.arr[i] != 0); // Valid positions should not be zero + } + + // Verify that positions beyond new size are zeroed + // (The zeroing loop should zero from vec.size-1 down to iter_end) + printf("Zeroing verification: "); + int all_valid = 1; + for (int i = 0; i < vec.size; i++) { + if (vec.arr[i] == 0) { + printf("BUG: arr[%d] is zero but should be valid! ", i); + all_valid = 0; + } + } + if (all_valid) printf("PASS"); + + printf("\n\n"); + delete(&vec); +} + +// Test 6: Range erase to end +void test_range_erase_to_end() { + printf("Test: Range erase to end\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i); + + Vec8_t* res = erase(&vec, 2, 10); // Erase [2,10) + assert(res != nullptr); + assert(vec.size == 2); + assert(vec.arr[0] == 'a'); + assert(vec.arr[1] == 'b'); + + printf("PASS\n\n"); + delete(&vec); +} + +// Test 7: Range erase invalid inputs +void test_range_erase_invalid() { + printf("Test: Range erase invalid inputs\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 5; i++) add_back(&vec, 'a' + i); + + // Invalid start + assert(erase(&vec, -1, 3) == nullptr); + + // Invalid end (>= size now, not just >) + assert(erase(&vec, 0, 5) == nullptr); // 5 >= size (5) + + // Start >= end now returns nullptr + assert(erase(&vec, 3, 2) == nullptr); // start >= end + assert(erase(&vec, 2, 2) == nullptr); // start == end + + // Null vector + assert(erase(nullptr, 0, 1) == nullptr); + + printf("PASS\n\n"); + delete(&vec); +} + +// Test 8: Large vector single erase +void test_large_single_erase() { + printf("Test: Large vector single erase (100k elements)\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 100000; i++) add_back(&vec, (char)(i % 256)); + + erase(&vec, 0); // Erase front + assert(vec.size == 99999); + assert(vec.arr[0] == 1); + + erase(&vec, 50000); // Erase middle + assert(vec.size == 99998); + assert(vec.arr[50000] == 2); // After erasing index 1 (value 1), index 50000 is now value 2 + + printf("PASS\n\n"); + delete(&vec); +} + +// Test 9: Large vector range erase +void test_large_range_erase() { + printf("Test: Large vector range erase (100k elements, erase 10k)\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 100000; i++) add_back(&vec, (char)(i % 256)); + + erase(&vec, 10000, 20000); // Erase 10k elements + assert(vec.size == 90000); + assert(vec.arr[10000] == (char)(20000 % 256)); // First element after erased range + + printf("PASS\n\n"); + delete(&vec); +} + +// Test 10: Repeated single erasures +void test_repeated_single_erase() { + printf("Test: Repeated single erasures until empty\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 100; i++) add_back(&vec, 'a' + (i % 26)); + + size_t initial_size = vec.size; + for (int i = 0; i < initial_size; i++) { + erase(&vec, 0); // Always erase first element + } + + assert(vec.size == 0); + printf("PASS\n\n"); + delete(&vec); +} + +// Test 11: Stress - random erasures +void test_random_erasures() { + printf("Test: Random erasures (1000 rounds)\n"); + srand((unsigned int)time(NULL)); + + for (int round = 0; round < 1000; round++) { + Vec8_t vec = create(nullptr); + int num_elements = rand() % 1000 + 10; + for (int i = 0; i < num_elements; i++) add_back(&vec, (char)(rand() % 256)); + + int num_erasures = rand() % 50; + for (int j = 0; j < num_erasures && vec.size > 0; j++) { + int idx = rand() % vec.size; + erase(&vec, idx); + } + + // Verify integrity + for (int i = 0; i < vec.size; i++) { + // Just check that we can access without crashing + char val = vec.arr[i]; + (void)val; + } + + delete(&vec); + } + + printf("PASS\n\n"); +} + +// Test 12: Stress - random range erasures +void test_random_range_erasures() { + printf("Test: Random range erasures (1000 rounds)\n"); + srand((unsigned int)time(NULL)); + + for (int round = 0; round < 1000; round++) { + Vec8_t vec = create(nullptr); + int num_elements = rand() % 1000 + 10; + for (int i = 0; i < num_elements; i++) add_back(&vec, (char)(rand() % 256)); + + int num_erasures = rand() % 20; + for (int j = 0; j < num_erasures && vec.size > 1; j++) { + int start = rand() % (vec.size - 1); + int end = start + rand() % (vec.size - start) + 1; + if (end > vec.size) end = vec.size; + erase(&vec, start, end); + } + + // Verify integrity + for (int i = 0; i < vec.size; i++) { + char val = vec.arr[i]; + (void)val; + } + + delete(&vec); + } + + printf("PASS\n\n"); +} + +// Test 13: Erase all elements one by one +void test_erase_all_single() { + printf("Test: Erase all elements one by one\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 1000; i++) add_back(&vec, 'a' + (i % 26)); + + while (vec.size > 0) { + erase(&vec, 0); + } + + assert(vec.size == 0); + printf("PASS\n\n"); + delete(&vec); +} + +// Test 14: Erase all elements with range erase +void test_erase_all_range() { + printf("Test: Erase all elements with range erase\n"); + Vec8_t vec = create(nullptr); + for (int i = 0; i < 1000; i++) add_back(&vec, 'a' + (i % 26)); + + erase(&vec, 0, vec.size); + + assert(vec.size == 0); + printf("PASS\n\n"); + delete(&vec); +} + +// Test 15: Memory stress - large vector, erase in middle repeatedly +void test_memory_stress() { + printf("Test: Memory stress - large vector, repeated middle erasure\n"); + Vec8_t vec = create(nullptr); + + // Add 1 million elements + for (int i = 0; i < 1000000; i++) { + add_back(&vec, (char)(i % 256)); + } + + printf(" Created vector with %zu elements\n", vec.size); + + // Erase from middle repeatedly + for (int i = 0; i < 10000; i++) { + if (vec.size == 0) break; + int idx = vec.size / 2; + erase(&vec, idx); + } + + printf(" After 10k middle erasures, size = %zu\n", vec.size); + + delete(&vec); + printf("PASS\n\n"); +} + + int main() { + printf("=== ERASE STRESS TEST SUITE ===\n\n"); + + test_single_erase_basic(); + test_single_erase_boundaries(); + test_single_erase_invalid(); + test_range_erase_basic(); + test_range_erase_zeroing_fixed(); + test_range_erase_to_end(); + test_range_erase_invalid(); + test_large_single_erase(); + test_large_range_erase(); + test_repeated_single_erase(); + test_random_erasures(); + test_random_range_erasures(); + test_erase_all_single(); + test_erase_all_range(); + test_memory_stress(); + + printf("=== ALL TESTS COMPLETED ===\n"); + return 0; +} diff --git a/tests/quick_test b/tests/quick_test new file mode 100755 index 0000000..200cb5f Binary files /dev/null and b/tests/quick_test differ diff --git a/tests/quick_test.c b/tests/quick_test.c new file mode 100644 index 0000000..07add8d --- /dev/null +++ b/tests/quick_test.c @@ -0,0 +1,69 @@ +#include +#include +#include + +#define CAPACITY 1024 +#define nullptr ((void*)0) + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +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; +} + +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; +} + +// Your current implementation +__attribute__((overloadable)) Vec8_t* +erase(Vec8_t* vec, const int iter_start, const int iter_end) { + if(vec == nullptr) return nullptr; + if(vec->arr == nullptr) return nullptr; + if(iter_start < 0 || iter_end >= vec->size) return nullptr; + if(iter_start >= iter_end) return nullptr; + size_t diff = iter_end - iter_start; + memmove(&vec->arr[iter_start], &vec->arr[iter_end], (vec->size - iter_end) * sizeof(char)); + for(size_t i = vec->size - 1; i > iter_end; i--) { + vec->arr[i] = 0; + } + vec->size -= diff; + return vec; +} + +int main() { + Vec8_t vec = create(nullptr); + for (int i = 0; i < 10; i++) add_back(&vec, 'a' + i); + + printf("Before erase: "); + for (int i = 0; i < 10; i++) printf("%c ", vec.arr[i]); + printf("(size=%zu)\n", vec.size); + + erase(&vec, 2, 4); + + printf("After erase(2,4): "); + for (int i = 0; i < 10; i++) printf("%c ", vec.arr[i] == 0 ? '0' : vec.arr[i]); + printf("(size=%zu)\n", vec.size); + + printf("\nExpected: a b e f g h i j (size=8)\n"); + printf("Got: "); + for (int i = 0; i < vec.size; i++) printf("%c ", vec.arr[i] == 0 ? '0' : vec.arr[i]); + printf("(size=%zu)\n", vec.size); + + return 0; +}