#include "test_framework.h" #include "../src/types.h" #include "../src/buffer.h" void test_buffer_init(void) { TEST_SUITE_BEGIN("Buffer Initialization"); buffer_t buf; int result = buffer_init(&buf, 1024); TEST_ASSERT_EQ(0, result, "Buffer init returns 0"); TEST_ASSERT(buf.data != NULL, "Buffer data is not NULL"); TEST_ASSERT_EQ(1024, buf.capacity, "Buffer capacity is 1024"); TEST_ASSERT_EQ(0, buf.head, "Buffer head is 0"); TEST_ASSERT_EQ(0, buf.tail, "Buffer tail is 0"); buffer_free(&buf); TEST_ASSERT(buf.data == NULL, "Buffer data is NULL after free"); TEST_SUITE_END(); } void test_buffer_read_write(void) { TEST_SUITE_BEGIN("Buffer Read/Write Operations"); buffer_t buf; buffer_init(&buf, 1024); TEST_ASSERT_EQ(1024, buffer_available_write(&buf), "Initial write capacity is 1024"); TEST_ASSERT_EQ(0, buffer_available_read(&buf), "Initial read capacity is 0"); const char *test_data = "Hello, World!"; size_t len = strlen(test_data); memcpy(buf.data + buf.tail, test_data, len); buf.tail += len; TEST_ASSERT_EQ(len, buffer_available_read(&buf), "Read capacity equals written data"); TEST_ASSERT_EQ(1024 - len, buffer_available_write(&buf), "Write capacity reduced"); buffer_free(&buf); TEST_SUITE_END(); } void test_buffer_consume(void) { TEST_SUITE_BEGIN("Buffer Consume Operations"); buffer_t buf; buffer_init(&buf, 1024); const char *test_data = "0123456789"; size_t len = strlen(test_data); memcpy(buf.data + buf.tail, test_data, len); buf.tail += len; buffer_consume(&buf, 5); TEST_ASSERT_EQ(5, buffer_available_read(&buf), "5 bytes remaining after consume"); TEST_ASSERT(memcmp(buf.data + buf.head, "56789", 5) == 0, "Correct data after consume"); buffer_consume(&buf, 5); TEST_ASSERT_EQ(0, buffer_available_read(&buf), "Buffer empty after full consume"); TEST_ASSERT_EQ(0, buf.head, "Head reset to 0"); TEST_ASSERT_EQ(0, buf.tail, "Tail reset to 0"); buffer_free(&buf); TEST_SUITE_END(); } void test_buffer_compact(void) { TEST_SUITE_BEGIN("Buffer Compact Operations"); buffer_t buf; buffer_init(&buf, 1024); const char *test_data = "ABCDEFGHIJ"; size_t len = strlen(test_data); memcpy(buf.data + buf.tail, test_data, len); buf.tail += len; buffer_consume(&buf, 5); TEST_ASSERT_EQ(5, buf.head, "Head moved to 5"); buffer_compact(&buf); TEST_ASSERT_EQ(0, buf.head, "Head is 0 after compact"); TEST_ASSERT_EQ(5, buf.tail, "Tail is 5 after compact"); TEST_ASSERT(memcmp(buf.data, "FGHIJ", 5) == 0, "Data moved to beginning"); buffer_free(&buf); TEST_SUITE_END(); } void test_buffer_ensure_capacity(void) { TEST_SUITE_BEGIN("Buffer Ensure Capacity"); buffer_t buf; buffer_init(&buf, 64); int result = buffer_ensure_capacity(&buf, 128); TEST_ASSERT_EQ(0, result, "Capacity increase successful"); TEST_ASSERT(buf.capacity >= 128, "Capacity at least 128"); result = buffer_ensure_capacity(&buf, 512); TEST_ASSERT_EQ(0, result, "Second capacity increase successful"); TEST_ASSERT(buf.capacity >= 512, "Capacity at least 512"); result = buffer_ensure_capacity(&buf, 64); TEST_ASSERT_EQ(0, result, "No change when capacity already sufficient"); buffer_free(&buf); TEST_SUITE_END(); } void test_buffer_multiple_operations(void) { TEST_SUITE_BEGIN("Buffer Multiple Operations"); buffer_t buf; buffer_init(&buf, 128); for (int i = 0; i < 10; i++) { char data[10]; snprintf(data, sizeof(data), "MSG%d", i); size_t len = strlen(data); if (buffer_available_write(&buf) < len) { buffer_compact(&buf); } memcpy(buf.data + buf.tail, data, len); buf.tail += len; } TEST_ASSERT(buffer_available_read(&buf) > 0, "Buffer has data after multiple writes"); size_t total_read = 0; while (buffer_available_read(&buf) > 0) { size_t to_consume = buffer_available_read(&buf) > 5 ? 5 : buffer_available_read(&buf); buffer_consume(&buf, to_consume); total_read += to_consume; } TEST_ASSERT(total_read > 0, "All data was consumed"); TEST_ASSERT_EQ(0, buffer_available_read(&buf), "Buffer is empty"); buffer_free(&buf); TEST_SUITE_END(); } void test_buffer_null_safety(void) { TEST_SUITE_BEGIN("Buffer NULL Safety"); TEST_ASSERT_EQ(-1, buffer_init(NULL, 1024), "NULL buffer init returns -1"); buffer_free(NULL); TEST_ASSERT(1, "NULL buffer free doesn't crash"); TEST_ASSERT_EQ(0, buffer_available_read(NULL), "NULL buffer read returns 0"); TEST_ASSERT_EQ(0, buffer_available_write(NULL), "NULL buffer write returns 0"); TEST_ASSERT_EQ(-1, buffer_ensure_capacity(NULL, 1024), "NULL buffer ensure capacity returns -1"); buffer_compact(NULL); TEST_ASSERT(1, "NULL buffer compact doesn't crash"); buffer_consume(NULL, 100); TEST_ASSERT(1, "NULL buffer consume doesn't crash"); TEST_SUITE_END(); } void test_buffer_consume_overflow(void) { TEST_SUITE_BEGIN("Buffer Consume Overflow"); buffer_t buf; buffer_init(&buf, 64); memcpy(buf.data, "TEST", 4); buf.tail = 4; buffer_consume(&buf, 100); TEST_ASSERT_EQ(0, buf.head, "Head reset after over-consume"); TEST_ASSERT_EQ(0, buf.tail, "Tail reset after over-consume"); TEST_ASSERT_EQ(0, buffer_available_read(&buf), "No data after over-consume"); buffer_free(&buf); TEST_SUITE_END(); } void test_buffer_compact_edge_cases(void) { TEST_SUITE_BEGIN("Buffer Compact Edge Cases"); buffer_t buf; buffer_init(&buf, 64); buffer_compact(&buf); TEST_ASSERT_EQ(0, buf.head, "Compact empty buffer - head is 0"); TEST_ASSERT_EQ(0, buf.tail, "Compact empty buffer - tail is 0"); memcpy(buf.data, "TEST", 4); buf.tail = 4; buf.head = 0; buffer_compact(&buf); TEST_ASSERT_EQ(0, buf.head, "Compact with head=0 unchanged"); buffer_free(&buf); TEST_SUITE_END(); } void test_buffer_capacity_limits(void) { TEST_SUITE_BEGIN("Buffer Capacity Limits"); buffer_t buf; buffer_init(&buf, 64); int result = buffer_ensure_capacity(&buf, MAX_BUFFER_SIZE + 1); TEST_ASSERT_EQ(-1, result, "Exceeding MAX_BUFFER_SIZE returns -1"); buffer_free(&buf); TEST_SUITE_END(); } void test_buffer_large_growth(void) { TEST_SUITE_BEGIN("Buffer Large Growth"); buffer_t buf; buffer_init(&buf, 64); int result = buffer_ensure_capacity(&buf, 1024); TEST_ASSERT_EQ(0, result, "Grow to 1024 succeeds"); TEST_ASSERT(buf.capacity >= 1024, "Capacity at least 1024"); result = buffer_ensure_capacity(&buf, 4096); TEST_ASSERT_EQ(0, result, "Grow to 4096 succeeds"); TEST_ASSERT(buf.capacity >= 4096, "Capacity at least 4096"); result = buffer_ensure_capacity(&buf, 65536); TEST_ASSERT_EQ(0, result, "Grow to 65536 succeeds"); TEST_ASSERT(buf.capacity >= 65536, "Capacity at least 65536"); buffer_free(&buf); TEST_SUITE_END(); } void test_buffer_near_max_capacity(void) { TEST_SUITE_BEGIN("Buffer Near Max Capacity"); buffer_t buf; buffer_init(&buf, 1024); int result = buffer_ensure_capacity(&buf, MAX_BUFFER_SIZE - 1024); TEST_ASSERT_EQ(0, result, "Grow to near max succeeds"); result = buffer_ensure_capacity(&buf, MAX_BUFFER_SIZE); TEST_ASSERT_EQ(0, result, "Grow to exactly max succeeds"); TEST_ASSERT(buf.capacity <= MAX_BUFFER_SIZE, "Capacity at max"); buffer_free(&buf); TEST_SUITE_END(); } void run_buffer_tests(void) { test_buffer_init(); test_buffer_read_write(); test_buffer_consume(); test_buffer_compact(); test_buffer_ensure_capacity(); test_buffer_multiple_operations(); test_buffer_null_safety(); test_buffer_consume_overflow(); test_buffer_compact_edge_cases(); test_buffer_capacity_limits(); test_buffer_large_growth(); test_buffer_near_max_capacity(); }