diff options
Diffstat (limited to 'test/test_ring.c')
-rw-r--r-- | test/test_ring.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/test/test_ring.c b/test/test_ring.c new file mode 100644 index 0000000..79aa0f1 --- /dev/null +++ b/test/test_ring.c @@ -0,0 +1,195 @@ +// Copyright 2011-2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#undef NDEBUG + +#include "failing_allocator.h" + +#include "zix/attributes.h" +#include "zix/ring.h" +#include "zix/thread.h" + +#include <assert.h> +#include <limits.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#define MSG_SIZE 20U + +static ZixRing* ring = 0; +static unsigned n_writes = 0; +static bool read_error = false; + +static int +gen_msg(int* const msg, int start) +{ + for (unsigned i = 0U; i < MSG_SIZE; ++i) { + msg[i] = start; + start = (start + 1) % INT_MAX; + } + return start; +} + +ZIX_PURE_FUNC +static int +cmp_msg(const int* const msg1, const int* const msg2) +{ + for (unsigned i = 0U; i < MSG_SIZE; ++i) { + assert(msg1[i] == msg2[i]); + } + + return 1; +} + +static void* +reader(void* ZIX_UNUSED(arg)) +{ + printf("Reader starting\n"); + + int ref_msg[MSG_SIZE]; // Reference generated for comparison + int read_msg[MSG_SIZE]; // Read from ring + unsigned count = 0; + int start = gen_msg(ref_msg, 0); + for (unsigned i = 0; i < n_writes; ++i) { + if (zix_ring_read_space(ring) >= MSG_SIZE * sizeof(int)) { + if (zix_ring_read(ring, read_msg, MSG_SIZE * sizeof(int))) { + assert(cmp_msg(ref_msg, read_msg)); + start = gen_msg(ref_msg, start); + ++count; + } + } + } + + printf("Reader finished\n"); + return NULL; +} + +static void* +writer(void* ZIX_UNUSED(arg)) +{ + printf("Writer starting\n"); + + int write_msg[MSG_SIZE]; // Written to ring + int start = gen_msg(write_msg, 0); + for (unsigned i = 0; i < n_writes; ++i) { + if (zix_ring_write_space(ring) >= MSG_SIZE * sizeof(int)) { + if (zix_ring_write(ring, write_msg, MSG_SIZE * sizeof(int))) { + start = gen_msg(write_msg, start); + } + } + } + + printf("Writer finished\n"); + return NULL; +} + +static int +test_ring(const unsigned size) +{ + zix_ring_free(NULL); + + printf("Testing %u writes of %u ints to a %u int ring...\n", + n_writes, + MSG_SIZE, + size); + + ring = zix_ring_new(NULL, size); + assert(ring); + assert(zix_ring_read_space(ring) == 0); + assert(zix_ring_write_space(ring) == zix_ring_capacity(ring)); + + zix_ring_mlock(ring); + + ZixThread reader_thread; // NOLINT + assert(!zix_thread_create(&reader_thread, MSG_SIZE * 4UL, reader, NULL)); + + ZixThread writer_thread; // NOLINT + assert(!zix_thread_create(&writer_thread, MSG_SIZE * 4UL, writer, NULL)); + + zix_thread_join(reader_thread, NULL); + zix_thread_join(writer_thread, NULL); + + assert(!read_error); + assert(ring); + zix_ring_reset(ring); + assert(zix_ring_read_space(ring) == 0); + assert(zix_ring_write_space(ring) == zix_ring_capacity(ring)); + + zix_ring_write(ring, "a", 1); + zix_ring_write(ring, "b", 1); + + char buf = 0; + uint32_t n = zix_ring_peek(ring, &buf, 1); + assert(n == 1); + assert(buf == 'a'); + + n = zix_ring_skip(ring, 1); + assert(n == 1); + + assert(zix_ring_read_space(ring) == 1); + + n = zix_ring_read(ring, &buf, 1); + assert(n == 1); + assert(buf == 'b'); + + assert(zix_ring_read_space(ring) == 0); + + n = zix_ring_peek(ring, &buf, 1); + assert(n == 0); + + n = zix_ring_read(ring, &buf, 1); + assert(n == 0); + + n = zix_ring_skip(ring, 1); + assert(n == 0); + + char* big_buf = (char*)calloc(size, 1); + n = zix_ring_write(ring, big_buf, size - 1); + assert(n == (uint32_t)size - 1); + + n = zix_ring_write(ring, big_buf, size); + assert(n == 0); + + free(big_buf); + zix_ring_free(ring); + return 0; +} + +static void +test_failed_alloc(void) +{ + ZixFailingAllocator allocator = zix_failing_allocator(); + + // Successfully allocate a ring to count the number of allocations + ring = zix_ring_new(&allocator.base, 512); + assert(ring); + + // Test that each allocation failing is handled gracefully + const size_t n_new_allocs = allocator.n_allocations; + for (size_t i = 0U; i < n_new_allocs; ++i) { + allocator.n_remaining = i; + assert(!zix_ring_new(&allocator.base, 512)); + } + + zix_ring_free(ring); +} + +int +main(int argc, char** argv) +{ + if (argc > 1 && argv[1][0] == '-') { + printf("Usage: %s SIZE N_WRITES\n", argv[0]); + return 1; + } + + const unsigned size = + (argc > 1) ? (unsigned)strtoul(argv[1], NULL, 10) : 1024; + + n_writes = (argc > 2) ? (unsigned)strtoul(argv[2], NULL, 10) : size * 1024; + + test_failed_alloc(); + test_ring(size); + return 0; +} |