/*
* test-ringbuf.c - unit tests for C ring buffer implementation.
*
* Written in 2011 by Drew Hess <dhess-src@bothan.net>.
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to
* the public domain worldwide. This software is distributed without
* any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <assert.h>
#include "ringbuf.h"
/*
* Fill a buffer with a test pattern.
*/
void *
fill_buffer(void *buf, size_t buf_size, const char *test_pattern)
{
size_t pattern_size = strlen(test_pattern);
size_t nblocks = buf_size / pattern_size;
uint8_t *p = buf;
size_t n;
for (n = 0; n != nblocks; ++n, p += pattern_size)
memcpy(p, (const void *) test_pattern, pattern_size);
memcpy(p, (const void *) test_pattern, buf_size % pattern_size);
return buf;
}
int rdfd = -1;
int wrfd = -1;
char rd_template[] = "/tmp/tmpXXXXXXringbuf";
char wr_template[] = "/tmp/tmpXXXXXXringbuf-wr";
void
cleanup()
{
if (rdfd != -1) {
close(rdfd);
unlink(rd_template);
}
if (wrfd != -1) {
close(wrfd);
unlink(wr_template);
}
}
void
sigabort(int unused)
{
cleanup();
exit(1);
}
#define START_NEW_TEST(test_num) \
fprintf(stderr, "Test %d...", (++test_num));
#define END_TEST(test_num) \
fprintf(stderr, "pass.\n");
/* Default size for these tests. */
#define RINGBUF_SIZE 4096
int
main(int argc, char **argv)
{
if (atexit(cleanup) == -1) {
fprintf(stderr, "Can't install atexit handler, exiting.\n");
exit(98);
}
/*
* catch SIGABRT when asserts fail for proper test file
* cleanup.
*/
struct sigaction sa, osa;
sa.sa_handler = sigabort;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGABRT, &sa, &osa) == -1) {
fprintf(stderr, "Can't install SIGABRT handler, exiting.\n");
exit(99);
}
ringbuf_t rb1 = ringbuf_new(RINGBUF_SIZE - 1);
int test_num = 0;
/*
* N.B.: these tests check both the ringbuf_t interface *and* a
* particular implementation. They are not black-box tests. If you
* make changes to the ringbuf_t implementation, some of these
* tests may break.
*/
/* We use the base pointer for some implementation testing. */
const uint8_t *rb1_base = ringbuf_head(rb1);
/* Initial conditions */
START_NEW_TEST(test_num);
assert(ringbuf_buffer_size(rb1) == RINGBUF_SIZE);
assert(ringbuf_capacity(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_bytes_free(rb1) == ringbuf_capacity(rb1));
assert(ringbuf_bytes_used(rb1) == 0);
assert(!ringbuf_is_full(rb1));
assert(ringbuf_is_empty(rb1));
assert(ringbuf_tail(rb1) == ringbuf_head(rb1));
assert(ringbuf_tail(rb1) == rb1_base);
END_TEST(test_num);
/* freeing a ring buffer sets the pointer to 0 */
START_NEW_TEST(test_num);
ringbuf_free(&rb1);
assert(!rb1);
END_TEST(test_num);
/* Different sizes */
rb1 = ringbuf_new(24);
rb1_base = ringbuf_head(rb1);
START_NEW_TEST(test_num);
assert(ringbuf_buffer_size(rb1) == 25);
assert(ringbuf_capacity(rb1) == 24);
assert(ringbuf_bytes_free(rb1) == ringbuf_capacity(rb1));
assert(ringbuf_bytes_used(rb1) == 0);
assert(!ringbuf_is_full(rb1));
assert(ringbuf_is_empty(rb1));
assert(ringbuf_tail(rb1) == ringbuf_head(rb1));
assert(ringbuf_tail(rb1) == rb1_base);
ringbuf_free(&rb1);
assert(!rb1);
END_TEST(test_num);
rb1 = ringbuf_new(RINGBUF_SIZE - 1);
rb1_base = ringbuf_head(rb1);
/* ringbuf_reset tests */
START_NEW_TEST(test_num);
ringbuf_memset(rb1, 1, 8);
ringbuf_reset(rb1);
assert(ringbuf_buffer_size(rb1) == RINGBUF_SIZE);
assert(ringbuf_capacity(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_bytes_free(rb1) == ringbuf_capacity(rb1));
assert(ringbuf_bytes_used(rb1) == 0);
assert(!ringbuf_is_full(rb1));
assert(ringbuf_is_empty(rb1));
assert(ringbuf_tail(rb1) == ringbuf_head(rb1));
assert(ringbuf_tail(rb1) == rb1_base);
END_TEST(test_num);
START_NEW_TEST(test_num);
ringbuf_memset(rb1, 1, ringbuf_buffer_size(rb1)); /* overflow */
ringbuf_reset(rb1);
assert(ringbuf_buffer_size(rb1) == RINGBUF_SIZE);
assert(ringbuf_capacity(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_bytes_free(rb1) == ringbuf_capacity(rb1));
assert(ringbuf_bytes_used(rb1) == 0);
assert(!ringbuf_is_full(rb1));
assert(ringbuf_is_empty(rb1));
assert(ringbuf_tail(rb1) == ringbuf_head(rb1));
assert(ringbuf_tail(rb1) == rb1_base);
END_TEST(test_num);
/* ringbuf_memset with zero count */
START_NEW_TEST(test_num);
ringbuf_reset(rb1);
assert(ringbuf_memset(rb1, 1, 0) == 0);
assert(ringbuf_capacity(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_bytes_free(rb1) == ringbuf_capacity(rb1));
assert(ringbuf_bytes_used(rb1) == 0);
assert(!ringbuf_is_full(rb1));
assert(ringbuf_is_empty(rb1));
assert(ringbuf_tail(rb1) == ringbuf_head(rb1));
END_TEST(test_num);
uint8_t *buf = malloc(RINGBUF_SIZE * 2);
memset(buf, 57, RINGBUF_SIZE);
memset(buf + RINGBUF_SIZE, 58, RINGBUF_SIZE);
/* ringbuf_memset a few bytes of data */
START_NEW_TEST(test_num);
ringbuf_reset(rb1);
assert(ringbuf_memset(rb1, 57, 7) == 7);
assert(ringbuf_capacity(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_bytes_free(rb1) == ringbuf_capacity(rb1) - 7);
assert(ringbuf_bytes_used(rb1) == 7);
assert(!ringbuf_is_full(rb1));
assert(!ringbuf_is_empty(rb1));
assert(strncmp((const char *) buf, ringbuf_tail(rb1), 7) == 0);
END_TEST(test_num);
/* ringbuf_memset full capacity */
START_NEW_TEST(test_num);
ringbuf_reset(rb1);
assert(ringbuf_memset(rb1, 57, RINGBUF_SIZE - 1) == RINGBUF_SIZE - 1);
assert(ringbuf_capacity(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_bytes_free(rb1) == 0);
assert(ringbuf_bytes_used(rb1) == ringbuf_capacity(rb1));
assert(ringbuf_is_full(rb1));
assert(!ringbuf_is_empty(rb1));
assert(strncmp(ringbuf_tail(rb1), (const char *) buf, RINGBUF_SIZE - 1) == 0);
END_TEST(test_num);
/* ringbuf_memset, twice */
START_NEW_TEST(test_num);
ringbuf_reset(rb1);
assert(ringbuf_memset(rb1, 57, 7) == 7);
assert(ringbuf_memset(rb1, 57, 15) == 15);
assert(ringbuf_capacity(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_bytes_used(rb1) == 7 + 15);
assert(ringbuf_bytes_free(rb1) == ringbuf_capacity(rb1) - (7 + 15));
assert(!ringbuf_is_full(rb1));
assert(!ringbuf_is_empty(rb1));
assert(strncmp((const char *) buf, ringbuf_tail(rb1), 7 + 15) == 0);
END_TEST(test_num);
/* ringbuf_memset, twice (to full capacity) */
START_NEW_TEST(test_num);
ringbuf_reset(rb1);
assert(ringbuf_memset(rb1, 57, RINGBUF_SIZE - 2) == RINGBUF_SIZE - 2);
assert(ringbuf_memset(rb1, 57, 1) == 1);
assert(ringbuf_capacity(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_bytes_free(rb1) == 0);
assert(ringbuf_bytes_used(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_is_full(rb1));
assert(!ringbuf_is_empty(rb1));
assert(strncmp((const char *) buf, ringbuf_tail(rb1), RINGBUF_SIZE - 1) == 0);
END_TEST(test_num);
/* ringbuf_memset, overflow by 1 byte */
START_NEW_TEST(test_num);
ringbuf_reset(rb1);
assert(ringbuf_memset(rb1, 57, RINGBUF_SIZE) == RINGBUF_SIZE);
assert(ringbuf_capacity(rb1) == RINGBUF_SIZE - 1);
assert(ringbuf_bytes_free(rb1) == 0);
assert(ringbuf_bytes_used(rb1) == ringbuf_capacity(rb1));
assert(ringbuf_is_full(rb1));
assert(!ringbuf_is_empty(rb1));
/* head sho