Mercurial > libjeffpc
view tests/test_buffer.c @ 800:299dffade145
buffer: use the common buffer test string for read-only tests
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Fri, 03 Apr 2020 15:11:57 -0400 |
parents | 6371fb111e27 |
children | 4e86cf312d6c |
line wrap: on
line source
/* * Copyright (c) 2017-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <jeffpc/buffer.h> #include <jeffpc/error.h> #include <jeffpc/rand.h> #include "test.c" #define COMMON_TEST_STRING \ "759f7e2d-67ec-4e72-8f61-86a3fd93b1be" \ "60e9149e-d039-e32b-b25d-c995b28bf890" \ "40f0fddc-ddca-4ff5-cd81-b0ae4c7d6123" /* allocate a heap buffer - either on the heap or on the stack */ static inline struct buffer *alloc_heap_buffer(struct buffer *buf, size_t size) { if (buf) { int ret; ret = buffer_init_heap(buf, size); if (ret) fail("buffer_init_heap(%zu) failed: %s", size, xstrerror(ret)); } else { buf = buffer_alloc(size); if (IS_ERR(buf)) fail("buffer_alloc(%zu) failed: %s", size, xstrerror(PTR_ERR(buf))); } return buf; } static inline void check_data_zeroes(struct buffer *buffer, size_t startoff) { const uint8_t *data; size_t len; size_t i; data = buffer_data(buffer); len = buffer_size(buffer); if (startoff > len) fail("%s startoff > len (%zu > %zu)", __func__, startoff, len); for (i = startoff; i < len; i++) { if (data[i] == '\0') continue; fail("buffer contains %#02x @ offset %zu (should be '\\0')", data[i], i); } } static inline void check_data(struct buffer *buffer) { const void *ptr; ptr = buffer_data(buffer); if (ptr == NULL) fail("buffer_data() returned NULL"); if (IS_ERR(ptr)) fail("buffer_data() returned error: %s", xstrerror(PTR_ERR(ptr))); } static inline void check_data_ptr(struct buffer *buffer, const void *expected) { const void *ptr; ptr = buffer_data(buffer); if (ptr == expected) return; if (IS_ERR(ptr)) fail("buffer_data() returned error: %s (%p expected)", xstrerror(PTR_ERR(ptr)), expected); fail("buffer_data() returned %p, but %p was expected", ptr, expected); } static inline void check_data_null(struct buffer *buffer) { check_data_ptr(buffer, NULL); } static inline void check_used(struct buffer *buffer, size_t expected) { size_t got; got = buffer_size(buffer); if (got != expected) fail("buffer_size() == %zu, should be %zu", got, expected); } static inline void check_append_err(struct buffer *buffer, const void *ptr, size_t len, int expected_ret) { int ret; ret = buffer_append(buffer, ptr, len); if (ret == expected_ret) return; if (ret && expected_ret) fail("buffer_append(..., %p, %zu) failed with wrong error: " "got %s, expected %s", ptr, len, xstrerror(ret), xstrerror(expected_ret)); if (ret && !expected_ret) fail("buffer_append(..., %p, %zu) failed but it wasn't " "supposed to: %s", ptr, len, xstrerror(ret)); if (!ret && expected_ret) fail("buffer_append(..., %p, %zu) succeeded but it wasn't " "supposed to. Expected error: %s", ptr, len, xstrerror(expected_ret)); fail("impossible condition occured"); } static inline void check_append(struct buffer *buffer, const void *ptr, size_t len) { check_append_err(buffer, ptr, len, 0); } static inline void check_truncate_err(struct buffer *buffer, size_t newsize, int expected_ret) { int ret; ret = buffer_truncate(buffer, newsize); if (ret == expected_ret) return; if (ret && expected_ret) fail("buffer_truncate(..., %zu) failed with wrong error: " "got %s, expected %s", newsize, xstrerror(ret), xstrerror(expected_ret)); if (ret && !expected_ret) fail("buffer_truncate(..., %zu) failed but it wasn't " "supposed to: %s", newsize, xstrerror(ret)); if (!ret && expected_ret) fail("buffer_truncate(..., %zu) succeeded but it wasn't " "supposed to. Expected error: %s", newsize, xstrerror(expected_ret)); fail("impossible condition occured"); } static inline void check_truncate(struct buffer *buffer, size_t newsize) { check_truncate_err(buffer, newsize, 0); } static void test_alloc_free(struct buffer *_buffer) { struct buffer *buffer; size_t i; for (i = 0; i < 10; i++) { fprintf(stderr, "%s(%p): iter = %zu...", __func__, _buffer, i); buffer = alloc_heap_buffer(_buffer, i); check_data(buffer); check_used(buffer, 0); buffer_free(buffer); fprintf(stderr, "\n"); } } static void inner_loop(size_t niter, struct buffer *buffer, uint8_t *data, void (*check)(struct buffer *)) { size_t i; for (i = 0; i < niter; i++) { uint8_t byte = i; if (data) data[i] = i; check(buffer); check_used(buffer, i); check_append(buffer, &byte, 1); check(buffer); check_used(buffer, i + 1); /* truncate to same size */ check_truncate(buffer, buffer_size(buffer)); check(buffer); check_used(buffer, i + 1); } check(buffer); check_used(buffer, i); } static void test_append(struct buffer *_buffer) { struct buffer *buffer; size_t startsize; for (startsize = 0; startsize < 300; startsize++) { uint8_t data[256]; fprintf(stderr, "%s(%p): iter = %3zu...", __func__, _buffer, startsize); buffer = alloc_heap_buffer(_buffer, startsize); inner_loop(256, buffer, data, check_data); if (memcmp(data, buffer_data(buffer), sizeof(data))) fail("buffered data mismatches expectations"); buffer_free(buffer); memset(data, 0, sizeof(data)); fprintf(stderr, "ok.\n"); } } static void test_truncate_grow(struct buffer *_buffer) { struct buffer *buffer; size_t i; buffer = alloc_heap_buffer(_buffer, 0); for (i = 0; i < 50000; i += 13) { fprintf(stderr, "%s: iter = %3zu...", __func__, i); check_truncate(buffer, i); check_used(buffer, i); check_data_zeroes(buffer, 0); fprintf(stderr, "ok.\n"); } buffer_free(buffer); } static void test_truncate_shrink(struct buffer *_buffer) { const size_t maxsize = 5000 * sizeof(uint64_t); struct buffer *buffer; size_t i; buffer = alloc_heap_buffer(_buffer, maxsize); /* append some random data */ for (i = 0; i < maxsize; i += sizeof(uint64_t)) { uint64_t tmp; tmp = rand64(); check_append(buffer, &tmp, sizeof(tmp)); } /* sanity check the size */ check_used(buffer, maxsize); for (i = maxsize; i > 0; i -= sizeof(uint64_t)) { fprintf(stderr, "%s: iter = %3zu...", __func__, i); check_truncate(buffer, i); check_used(buffer, i); fprintf(stderr, "ok.\n"); } buffer_free(buffer); } static void test_sink(void) { struct buffer buffer; size_t maxsize; for (maxsize = 0; maxsize < 270; maxsize++) { buffer_init_sink(&buffer); fprintf(stderr, "%s: iter = %3zu...", __func__, maxsize); inner_loop(256, &buffer, NULL, check_data_null); memset(&buffer, 0, sizeof(struct buffer)); fprintf(stderr, "ok.\n"); } for (maxsize = 300; maxsize < 300000; maxsize += 10000) { buffer_init_sink(&buffer); fprintf(stderr, "%s: iter = %3zu...", __func__, maxsize); inner_loop(256, &buffer, NULL, check_data_null); memset(&buffer, 0, sizeof(struct buffer)); fprintf(stderr, "ok.\n"); } } void test_static_const_arg(void) { const char const_data[] = "abc"; struct buffer buffer; /* (statically) check for passing in const pointer being ok */ buffer_init_static(&buffer, const_data, strlen(const_data), strlen(const_data), false); } void test_static_ro(void) { const char rawdata[] = COMMON_TEST_STRING; struct buffer buffer; int i; buffer_init_static(&buffer, rawdata, strlen(rawdata), strlen(rawdata), false); check_used(&buffer, strlen(rawdata)); check_data_ptr(&buffer, rawdata); for (i = 0; i < 10; i++) { fprintf(stderr, "%s: iter = %d...", __func__, i); check_append_err(&buffer, "abc", 3, -EROFS); check_used(&buffer, strlen(rawdata)); check_data_ptr(&buffer, rawdata); check_truncate_err(&buffer, i * strlen(rawdata) / 5, -EROFS); check_used(&buffer, strlen(rawdata)); check_data_ptr(&buffer, rawdata); fprintf(stderr, "ok.\n"); } } void test_static_rw(void) { char rawdata[] = COMMON_TEST_STRING; const size_t rawlen = strlen(rawdata); struct buffer buffer; size_t size; for (size = 0; size <= rawlen; size++) { buffer_init_static(&buffer, rawdata, size, rawlen, true); fprintf(stderr, "%s(%zu): initial sanity check...", __func__, size); check_used(&buffer, size); check_data_ptr(&buffer, rawdata); fprintf(stderr, "ok.\n"); fprintf(stderr, "%s(%zu): append to a buffer without enough " "space...", __func__, size); check_append_err(&buffer, COMMON_TEST_STRING, rawlen + 1, -ENOSPC); check_used(&buffer, size); check_data_ptr(&buffer, rawdata); fprintf(stderr, "ok.\n"); fprintf(stderr, "%s(%zu): truncate to a larger than buffer " "size...", __func__, size); check_truncate_err(&buffer, rawlen + 1, -ENOSPC); check_used(&buffer, size); check_data_ptr(&buffer, rawdata); fprintf(stderr, "ok.\n"); if (size >= 5) { fprintf(stderr, "%s(%zu): truncate to a smaller than " "initial size...", __func__, size); check_truncate_err(&buffer, size - 5, 0); check_used(&buffer, size - 5); check_data_ptr(&buffer, rawdata); fprintf(stderr, "ok.\n"); fprintf(stderr, "%s(%zu): append too much...", __func__, size); check_append_err(&buffer, COMMON_TEST_STRING COMMON_TEST_STRING, rawlen - size + 11, -ENOSPC); check_used(&buffer, size - 5); check_data_ptr(&buffer, rawdata); fprintf(stderr, "ok.\n"); fprintf(stderr, "%s(%zu): append a little...", __func__, size); check_append_err(&buffer, COMMON_TEST_STRING, 5, 0); check_used(&buffer, size); check_data_ptr(&buffer, rawdata); fprintf(stderr, "ok.\n"); } } } void test(void) { struct buffer stack_buf; /* stack allocated buffer struct */ test_alloc_free(&stack_buf); test_append(&stack_buf); test_truncate_grow(&stack_buf); test_truncate_shrink(&stack_buf); /* heap allocated buffer struct */ test_alloc_free(NULL); test_append(NULL); test_truncate_grow(NULL); test_truncate_shrink(NULL); test_sink(); test_static_const_arg(); test_static_ro(); test_static_rw(); }