// Tests for buffer.h - dynamic buffer allocation and resizing #define BUFFER_IMPLEMENTATION #include "../include/buffer.h" #include #include #include #define ASSERT(cond, msg) \ do { \ if (!(cond)) { \ fprintf(stderr, "FAIL: %s (test_buffer.c:%d)\n", msg, __LINE__); \ failures++; \ } \ } while (0) static int failures = 0; void test_malloc_and_free() { void *buf = buffer_malloc(10, sizeof(int)); ASSERT(buf != NULL, "buffer_malloc returns non-NULL"); buffer_free(buf); } void test_capacity() { void *buf = buffer_malloc(10, sizeof(int)); ASSERT(buffer_capacity(buf) == 10, "initial capacity"); buffer_free(buf); } void test_count() { void *buf = buffer_malloc(10, sizeof(int)); ASSERT(buffer_count(buf) == 0, "initial count is 0"); buffer_free(buf); } void test_resize_grow() { void *buf = buffer_malloc(10, sizeof(int)); ASSERT(buf != NULL, "buffer_malloc returns non-NULL"); if (!buf) return; buffer_meta_t *meta = (buffer_meta_t *)_buffer_to_meta(buf); meta->i = 9; void *new_buf = buffer_resize(buf); meta = (buffer_meta_t *)_buffer_to_meta(new_buf); ASSERT(meta->n == 20, "capacity doubles when ratio > 0.8"); buffer_free(new_buf); } void test_resize_shrink() { void *buf = buffer_malloc(100, sizeof(int)); ASSERT(buf != NULL, "buffer_malloc returns non-NULL"); if (!buf) return; buffer_meta_t *meta = (buffer_meta_t *)_buffer_to_meta(buf); meta->i = 5; void *new_buf = buffer_resize(buf); meta = (buffer_meta_t *)_buffer_to_meta(new_buf); ASSERT(meta->n == 50, "capacity halves when ratio < 0.2 and n > 32"); buffer_free(new_buf); } void test_resize_no_change() { void *buf = buffer_malloc(32, sizeof(int)); ASSERT(buf != NULL, "buffer_malloc returns non-NULL"); if (!buf) return; buffer_meta_t *meta = (buffer_meta_t *)_buffer_to_meta(buf); meta->i = 10; void *new_buf = buffer_resize(buf); ASSERT(new_buf == buf, "no realloc when capacity unchanged"); buffer_free(buf); } void test_resize_small_no_shrink() { void *buf = buffer_malloc(30, sizeof(int)); ASSERT(buf != NULL, "buffer_malloc returns non-NULL"); if (!buf) return; buffer_meta_t *meta = (buffer_meta_t *)_buffer_to_meta(buf); meta->i = 1; void *new_buf = buffer_resize(buf); meta = (buffer_meta_t *)_buffer_to_meta(new_buf); ASSERT(meta->n == 30, "does not shrink below 32"); buffer_free(new_buf); } void test_data_integrity() { int *buf = (int *)buffer_malloc(10, sizeof(int)); for (int i = 0; i < 10; i++) { buf[i] = i * 100; } buffer_meta_t *meta = (buffer_meta_t *)_buffer_to_meta(buf); meta->i = 9; int *new_buf = (int *)buffer_resize(buf); for (int i = 0; i < 10; i++) { ASSERT(new_buf[i] == i * 100, "data preserved after resize"); } buffer_free(new_buf); } void test_different_sizes() { void *buf1 = buffer_malloc(5, sizeof(char)); void *buf2 = buffer_malloc(5, sizeof(int)); void *buf3 = buffer_malloc(5, sizeof(double)); ASSERT(buffer_capacity(buf1) == 5, "char capacity"); ASSERT(buffer_capacity(buf2) == 5, "int capacity"); ASSERT(buffer_capacity(buf3) == 5, "double capacity"); buffer_free(buf1); buffer_free(buf2); buffer_free(buf3); } int main() { test_malloc_and_free(); test_capacity(); test_count(); test_resize_grow(); test_resize_shrink(); test_resize_no_change(); test_resize_small_no_shrink(); test_data_integrity(); test_different_sizes(); printf("test_buffer: %d failures\n", failures); return failures; }