#include #include #include #include "ring_buffer.h" #define BUFFER_SIZE 32 static u8 buffer[BUFFER_SIZE]; static u8 output[BUFFER_SIZE]; static u8 half_buffer[BUFFER_SIZE / 2] = { 0 }; static u8 bigger_buffer[BUFFER_SIZE + 16] = { 0 }; static bool ring_buffer_test_init(void) { AL_TEST_START("ring_buffer_init"); struct al_ring_buffer buf; al_ring_buffer_init(&buf, buffer, BUFFER_SIZE); AL_TEST_EQ(buf.start, buffer, ptr); AL_TEST_EQ(buf.end, buffer + BUFFER_SIZE, ptr); AL_TEST_EQ(al_atomic_load(void)(&buf.read, AL_ATOMIC_RELAXED), buffer, ptr); AL_TEST_EQ(al_atomic_load(void)(&buf.write, AL_ATOMIC_RELAXED), buffer, ptr); AL_TEST_END(); } static bool ring_buffer_test_space(void) { AL_TEST_START("ring_buffer_space"); struct al_ring_buffer buf; al_ring_buffer_init(&buf, buffer, BUFFER_SIZE); AL_TEST_EQ(al_ring_buffer_space(&buf), BUFFER_SIZE - 1, ptrdiff_t); AL_TEST_END(); } static bool ring_buffer_test_occupied(void) { AL_TEST_START("ring_buffer_occupied"); struct al_ring_buffer buf; al_ring_buffer_init(&buf, buffer, BUFFER_SIZE); AL_TEST_EQ(al_ring_buffer_occupied(&buf), 0, ptrdiff_t); AL_TEST_END(); } static bool ring_buffer_test_read_and_write_chunk(void) { AL_TEST_START("ring_buffer_read_and_write_chunk"); struct al_ring_buffer buf; al_ring_buffer_init(&buf, buffer, BUFFER_SIZE); char *data = "TestTEST"; ptrdiff_t data_size = (ptrdiff_t)(al_strlen(data) + 1); ptrdiff_t size; u8 *ptr = al_ring_buffer_write_chunk(&buf, &size); AL_TEST_EQ(size, BUFFER_SIZE - 1, ptrdiff_t); al_memcpy(ptr, data, (size_t)data_size); al_ring_buffer_append(&buf, ptr, data_size); AL_TEST_EQ(al_ring_buffer_occupied(&buf), data_size, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_space(&buf), (BUFFER_SIZE - 1) - data_size, ptrdiff_t); ptr = al_ring_buffer_read_chunk(&buf, &size); AL_TEST_EQ(size, data_size, ptrdiff_t); AL_TEST_TRUE(al_strncmp((char *)ptr, data, data_size) == 0); al_ring_buffer_consume(&buf, ptr, size); AL_TEST_EQ(al_ring_buffer_occupied(&buf), 0, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_space(&buf), BUFFER_SIZE - 1, ptrdiff_t); AL_TEST_END(); } static bool ring_buffer_test_read_and_write(void) { AL_TEST_START("ring_buffer_read_and_write"); struct al_ring_buffer buf; al_ring_buffer_init(&buf, buffer, BUFFER_SIZE); char *data = "TestTEST"; ptrdiff_t data_size = (ptrdiff_t)(al_strlen(data) + 1); al_ring_buffer_write(&buf, (u8 *)data, data_size); AL_TEST_EQ(al_ring_buffer_occupied(&buf), data_size, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_space(&buf), (BUFFER_SIZE - 1) - data_size, ptrdiff_t); al_ring_buffer_read(&buf, (u8 *)output, data_size); AL_TEST_TRUE(al_strncmp((char *)output, data, data_size) == 0); AL_TEST_EQ(al_ring_buffer_occupied(&buf), 0, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_space(&buf), BUFFER_SIZE - 1, ptrdiff_t); al_memset(half_buffer, 'd', sizeof(half_buffer)); AL_TEST_EQ(al_ring_buffer_write(&buf, half_buffer, sizeof(half_buffer)), sizeof(half_buffer), ptrdiff_t); AL_TEST_EQ(al_ring_buffer_occupied(&buf), sizeof(half_buffer), ptrdiff_t); AL_TEST_EQ(al_ring_buffer_space(&buf), (BUFFER_SIZE - 1) - sizeof(half_buffer), ptrdiff_t); // Arbitrarily read data_size from what was written above. AL_TEST_EQ(al_ring_buffer_read(&buf, (u8 *)output, data_size), data_size, ptrdiff_t); AL_TEST_TRUE(al_memcmp(output, "ddddddddd", (size_t)data_size) == 0); AL_TEST_EQ(al_ring_buffer_write(&buf, half_buffer, sizeof(half_buffer)), sizeof(half_buffer), ptrdiff_t); AL_TEST_EQ(al_ring_buffer_occupied(&buf), BUFFER_SIZE - data_size, ptrdiff_t); // Test that we wrapped. AL_TEST_LT(al_atomic_load(void)(&buf.write, AL_ATOMIC_RELAXED), al_atomic_load(void)(&buf.read, AL_ATOMIC_RELAXED), ptr); ptrdiff_t space = al_ring_buffer_space(&buf); // Maximum space is BUFFER_SIZE - 1. AL_TEST_EQ(space, data_size - 1, ptrdiff_t); al_memset(bigger_buffer, 'r', sizeof(bigger_buffer)); // Test impartial write because we're out of space. AL_TEST_EQ(al_ring_buffer_write(&buf, bigger_buffer, sizeof(bigger_buffer)), space, ptrdiff_t); // Test we can read everything. AL_TEST_EQ(al_ring_buffer_read(&buf, output, sizeof(bigger_buffer)), BUFFER_SIZE - 1, ptrdiff_t); AL_TEST_TRUE(al_memcmp(output, half_buffer, sizeof(half_buffer)) == 0); AL_TEST_TRUE(al_memcmp(output + ((BUFFER_SIZE - 1) - space), bigger_buffer, (size_t)space) == 0); AL_TEST_END(); } static bool ring_buffer_test_peek(void) { AL_TEST_START("ring_buffer_peek"); struct al_ring_buffer buf; al_ring_buffer_init(&buf, buffer, BUFFER_SIZE); char *data = "aBcDeFgHiJkLmNoPqRsTuVwXyZ12345"; ptrdiff_t data_size = (ptrdiff_t)al_strlen(data); AL_TEST_EQ(data_size, BUFFER_SIZE - 1, ptrdiff_t); al_ring_buffer_write(&buf, (u8 *)data, data_size); // Peek everything. al_ring_buffer_peek(&buf, output, 0, data_size); AL_TEST_TRUE(al_memcmp(output, data, (size_t)data_size) == 0); // Peek from an offset of 3. al_ring_buffer_peek(&buf, output, 3, data_size); AL_TEST_TRUE(al_memcmp(output, data + 3, (size_t)(data_size - 3)) == 0); // Read 3 bytes and peek the remaining al_ring_buffer_read(&buf, output, 3); AL_TEST_TRUE(al_memcmp(output, data, 3) == 0); al_ring_buffer_write(&buf, (u8 *)data, data_size); ptrdiff_t occupied = al_ring_buffer_occupied(&buf); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 3, data_size), occupied - 3, ptrdiff_t); AL_TEST_TRUE(al_memcmp(output, data + 6, (size_t)(data_size - 6)) == 0); // Peek everything again. al_ring_buffer_peek(&buf, output, 0, data_size); AL_TEST_TRUE(al_memcmp(output, "DeFgHiJkLmNoPqRsTuVwXyZ12345aBc", (size_t)data_size) == 0); // Read up to the last 4 bytes. al_ring_buffer_read(&buf, output, (BUFFER_SIZE - 1) - 4); al_ring_buffer_peek(&buf, output, 0, data_size); AL_TEST_TRUE(al_memcmp(output, "5aBc", 4) == 0); // Test peek truncating the offset. AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 10, data_size), 0, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 3, data_size), 1, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 4, data_size), 0, ptrdiff_t); // Incrementally read the rest of the buffer. al_ring_buffer_peek(&buf, output, 1, data_size); AL_TEST_TRUE(al_memcmp(output, "aBc", 3) == 0); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 2, data_size), 2, ptrdiff_t); AL_TEST_TRUE(al_memcmp(output, "Bc", 2) == 0); al_ring_buffer_read(&buf, output, 1); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 0, data_size), 3, ptrdiff_t); AL_TEST_TRUE(al_memcmp(output, "aBc", 3) == 0); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 3, data_size), 0, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 4, data_size), 0, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_read(&buf, output, 4), 3, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 0, data_size), 0, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 1, data_size), 0, ptrdiff_t); AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 999, data_size), 0, ptrdiff_t); AL_TEST_END(); } bool ring_buffer_tests_run(void) { AL_TEST_START_GROUP("ring_buffer"); AL_TEST_RUN(ring_buffer_test_init); AL_TEST_RUN(ring_buffer_test_space); AL_TEST_RUN(ring_buffer_test_occupied); AL_TEST_RUN(ring_buffer_test_read_and_write_chunk); AL_TEST_RUN(ring_buffer_test_read_and_write); AL_TEST_RUN(ring_buffer_test_peek); AL_TEST_END_GROUP(); }