diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 02:57:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 02:57:58 +0000 |
commit | be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97 (patch) | |
tree | 9754ff1ca740f6346cf8483ec915d4054bc5da2d /mqtt_websockets/c-rbuf/tests/ringbuffer_test.c | |
parent | Initial commit. (diff) | |
download | netdata-be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97.tar.xz netdata-be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97.zip |
Adding upstream version 1.44.3.upstream/1.44.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mqtt_websockets/c-rbuf/tests/ringbuffer_test.c')
-rw-r--r-- | mqtt_websockets/c-rbuf/tests/ringbuffer_test.c | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/mqtt_websockets/c-rbuf/tests/ringbuffer_test.c b/mqtt_websockets/c-rbuf/tests/ringbuffer_test.c new file mode 100644 index 00000000..d810ea5a --- /dev/null +++ b/mqtt_websockets/c-rbuf/tests/ringbuffer_test.c @@ -0,0 +1,491 @@ +/* + * + * Copyright: SPDX-License-Identifier: LGPL-3.0-only + * + * Author: Timotej Šiškovič <timotejs@gmail.com> + * + */ + +#include "ringbuffer.h" + +// to be able to access internals +// never do this from app +#include "../src/ringbuffer_internal.h" + +#include <stdio.h> +#include <string.h> + +#define KNRM "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KYEL "\x1B[33m" +#define KBLU "\x1B[34m" +#define KMAG "\x1B[35m" +#define KCYN "\x1B[36m" +#define KWHT "\x1B[37m" + +#define UNUSED(x) (void)(x) + +int total_fails = 0; +int total_tests = 0; +int total_checks = 0; + +#define CHECK_EQ_RESULT(x, y) \ + while (s_len--) \ + putchar('.'); \ + printf("%s%s " KNRM "\n", (((x) == (y)) ? KGRN : KRED), (((x) == (y)) ? " PASS " : " FAIL ")); \ + if ((x) != (y)) \ + total_fails++; \ + total_checks++; + +#define CHECK_EQ_PREFIX(x, y, prefix, subtest_name, ...) \ + { \ + int s_len = \ + 100 - \ + printf(("Checking: " KWHT "%s %s%2d " subtest_name " " KNRM), __func__, prefix, subtest_no, ##__VA_ARGS__); \ + CHECK_EQ_RESULT(x, y) \ + } + +#define CHECK_EQ(x, y, subtest_name, ...) \ + { \ + int s_len = \ + 100 - printf(("Checking: " KWHT "%s %2d " subtest_name " " KNRM), __func__, subtest_no, ##__VA_ARGS__); \ + CHECK_EQ_RESULT(x, y) \ + } + +#define TEST_DECL() \ + int subtest_no = 0; \ + printf(KYEL "TEST SUITE: %s\n" KNRM, __func__); \ + total_tests++; + +static void test_rbuf_get_linear_insert_range() +{ + TEST_DECL(); + + // check empty buffer behaviour + rbuf_t buff = rbuf_create(5); + char *to_write; + size_t ret; + to_write = rbuf_get_linear_insert_range(buff, &ret); + CHECK_EQ(ret, 5, "empty size"); + CHECK_EQ(to_write, buff->head, "empty write ptr"); + rbuf_free(buff); + + // check full buffer behaviour + subtest_no++; + buff = rbuf_create(5); + ret = rbuf_bump_head(buff, 5); + CHECK_EQ(ret, 1, "ret"); + to_write = rbuf_get_linear_insert_range(buff, &ret); + CHECK_EQ(to_write, NULL, "writable NULL"); + CHECK_EQ(ret, 0, "writable count = 0"); + + // check buffer flush + subtest_no++; + rbuf_flush(buff); + CHECK_EQ(rbuf_bytes_free(buff), 5, "size_free"); + CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail"); + CHECK_EQ(buff->head, buff->data, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + // check behaviour head > tail + subtest_no++; + rbuf_flush(buff); + rbuf_bump_head(buff, 3); + to_write = rbuf_get_linear_insert_range(buff, &ret); + CHECK_EQ(to_write, buff->head, "write location"); + CHECK_EQ(ret, 2, "availible to linear write"); + + // check behaviour tail > head + subtest_no++; + rbuf_flush(buff); + rbuf_bump_head(buff, 5); + rbuf_bump_tail(buff, 3); + CHECK_EQ(buff->head, buff->data, "head_ptr"); + CHECK_EQ(buff->tail, buff->data + 3, "tail_ptr"); + to_write = rbuf_get_linear_insert_range(buff, &ret); + CHECK_EQ(to_write, buff->head, "write location"); + CHECK_EQ(ret, 3, "availible to linear write"); + +/* // check behaviour tail and head at last element + subtest_no++; + rbuf_flush(buff); + rbuf_bump_head(buff, 4); + rbuf_bump_tail(buff, 4); + CHECK_EQ(buff->head, buff->end - 1, "head_ptr"); + CHECK_EQ(buff->tail, buff->end - 1, "tail_ptr"); + to_write = rbuf_get_linear_insert_range(buff, &ret); + CHECK_EQ(to_write, buff->head, "write location"); + CHECK_EQ(ret, 1, "availible to linear write");*/ + + // check behaviour tail and head at last element + // after rbuf_bump_tail optimisation that restarts buffer + // in case tail catches up with head + subtest_no++; + rbuf_flush(buff); + rbuf_bump_head(buff, 4); + rbuf_bump_tail(buff, 4); + CHECK_EQ(buff->head, buff->data, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + to_write = rbuf_get_linear_insert_range(buff, &ret); + CHECK_EQ(to_write, buff->head, "write location"); + CHECK_EQ(ret, 5, "availible to linear write"); +} + +#define _CHECK_EQ(x, y, subtest_name, ...) CHECK_EQ_PREFIX(x, y, prefix, subtest_name, ##__VA_ARGS__) +#define _PREFX "(size = %5zu) " +static void test_rbuf_bump_head_bsize(size_t size) +{ + char prefix[16]; + snprintf(prefix, 16, _PREFX, size); + int subtest_no = 0; + rbuf_t buff = rbuf_create(size); + _CHECK_EQ(rbuf_bytes_free(buff), size, "size_free"); + + subtest_no++; + int ret = rbuf_bump_head(buff, size); + _CHECK_EQ(buff->data, buff->head, "loc"); + _CHECK_EQ(ret, 1, "ret"); + _CHECK_EQ(buff->size_data, buff->size, "size"); + _CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free"); + + subtest_no++; + ret = rbuf_bump_head(buff, 1); + _CHECK_EQ(buff->data, buff->head, "loc no move"); + _CHECK_EQ(ret, 0, "ret error"); + _CHECK_EQ(buff->size_data, buff->size, "size"); + _CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free"); + rbuf_free(buff); + + subtest_no++; + buff = rbuf_create(size); + ret = rbuf_bump_head(buff, size - 1); + _CHECK_EQ(buff->head, buff->end-1, "loc end"); + rbuf_free(buff); +} +#undef _CHECK_EQ + +static void test_rbuf_bump_head() +{ + TEST_DECL(); + UNUSED(subtest_no); + + size_t test_sizes[] = { 1, 2, 3, 5, 6, 7, 8, 100, 99999, 0 }; + for (int i = 0; test_sizes[i]; i++) + test_rbuf_bump_head_bsize(test_sizes[i]); +} + +static void test_rbuf_bump_tail_noopt(int subtest_no) +{ + rbuf_t buff = rbuf_create(10); + CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free"); + CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail"); + + subtest_no++; + int ret = rbuf_bump_head(buff, 5); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_free(buff), 5, "size_free"); + CHECK_EQ(rbuf_bytes_available(buff), 5, "size_avail"); + CHECK_EQ(buff->head, buff->data + 5, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_tail_noopt(buff, 2); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 3, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 7, "size_free"); + CHECK_EQ(buff->head, buff->data + 5, "head_ptr"); + CHECK_EQ(buff->tail, buff->data + 2, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_tail_noopt(buff, 3); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free"); + CHECK_EQ(buff->head, buff->data + 5, "head_ptr"); + CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_tail_noopt(buff, 1); + CHECK_EQ(ret, 0, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free"); + CHECK_EQ(buff->head, buff->data + 5, "head_ptr"); + CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_head(buff, 7); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 7, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 3, "size_free"); + CHECK_EQ(buff->head, buff->data + 2, "head_ptr"); + CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_tail_noopt(buff, 5); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free"); + CHECK_EQ(buff->head, buff->data + 2, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + // check tail can't overrun head + subtest_no++; + ret = rbuf_bump_tail_noopt(buff, 3); + CHECK_EQ(ret, 0, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free"); + CHECK_EQ(buff->head, buff->data + 2, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + // check head can't overrun tail + subtest_no++; + ret = rbuf_bump_head(buff, 9); + CHECK_EQ(ret, 0, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free"); + CHECK_EQ(buff->head, buff->data + 2, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + // check head can fill the buffer + subtest_no++; + ret = rbuf_bump_head(buff, 8); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 10, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free"); + CHECK_EQ(buff->head, buff->data, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + // check can empty the buffer + subtest_no++; + ret = rbuf_bump_tail_noopt(buff, 10); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free"); + CHECK_EQ(buff->head, buff->data, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); +} + +static void test_rbuf_bump_tail_opt(int subtest_no) +{ + subtest_no++; + rbuf_t buff = rbuf_create(10); + CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free"); + CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail"); + + subtest_no++; + int ret = rbuf_bump_head(buff, 5); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_free(buff), 5, "size_free"); + CHECK_EQ(rbuf_bytes_available(buff), 5, "size_avail"); + CHECK_EQ(buff->head, buff->data + 5, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_tail(buff, 2); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 3, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 7, "size_free"); + CHECK_EQ(buff->head, buff->data + 5, "head_ptr"); + CHECK_EQ(buff->tail, buff->data + 2, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_tail(buff, 3); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free"); + CHECK_EQ(buff->head, buff->data, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_tail_noopt(buff, 1); + CHECK_EQ(ret, 0, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free"); + CHECK_EQ(buff->head, buff->data, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_head(buff, 6); + ret = rbuf_bump_tail(buff, 5); + ret = rbuf_bump_head(buff, 6); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 7, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 3, "size_free"); + CHECK_EQ(buff->head, buff->data + 2, "head_ptr"); + CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr"); + + subtest_no++; + ret = rbuf_bump_tail(buff, 5); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free"); + CHECK_EQ(buff->head, buff->data + 2, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + // check tail can't overrun head + subtest_no++; + ret = rbuf_bump_tail(buff, 3); + CHECK_EQ(ret, 0, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free"); + CHECK_EQ(buff->head, buff->data + 2, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + // check head can't overrun tail + subtest_no++; + ret = rbuf_bump_head(buff, 9); + CHECK_EQ(ret, 0, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free"); + CHECK_EQ(buff->head, buff->data + 2, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + // check head can fill the buffer + subtest_no++; + ret = rbuf_bump_head(buff, 8); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 10, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free"); + CHECK_EQ(buff->head, buff->data, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + + // check can empty the buffer + subtest_no++; + ret = rbuf_bump_tail(buff, 10); + CHECK_EQ(ret, 1, "ret"); + CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail"); + CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free"); + CHECK_EQ(buff->head, buff->data, "head_ptr"); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); +} + +static void test_rbuf_bump_tail() +{ + TEST_DECL(); + test_rbuf_bump_tail_noopt(subtest_no); + test_rbuf_bump_tail_opt(subtest_no); +} + +#define ASCII_A 0x61 +#define ASCII_Z 0x7A +#define TEST_DATA_SIZE ASCII_Z-ASCII_A+1 +static void test_rbuf_push() +{ + TEST_DECL(); + rbuf_t buff = rbuf_create(10); + int i; + char test_data[TEST_DATA_SIZE]; + + for (int i = 0; i <= TEST_DATA_SIZE; i++) + test_data[i] = i + ASCII_A; + + int ret = rbuf_push(buff, test_data, 10); + CHECK_EQ(ret, 10, "written 10 bytes"); + CHECK_EQ(rbuf_bytes_free(buff), 0, "empty size == 0"); + for (i = 0; i < 10; i++) + CHECK_EQ(buff->data[i], i + ASCII_A, "Check data"); + + subtest_no++; + rbuf_flush(buff); + rbuf_bump_head(buff, 5); + rbuf_bump_tail_noopt(buff, 5); //to not reset both pointers to beginning + ret = rbuf_push(buff, test_data, 10); + CHECK_EQ(ret, 10, "written 10 bytes"); + for (i = 0; i < 10; i++) + CHECK_EQ(buff->data[i], ((i+5)%10) + ASCII_A, "Check Data"); + + subtest_no++; + rbuf_flush(buff); + rbuf_bump_head(buff, 9); + rbuf_bump_tail_noopt(buff, 9); + ret = rbuf_push(buff, test_data, 10); + CHECK_EQ(ret, 10, "written 10 bytes"); + for (i = 0; i < 10; i++) + CHECK_EQ(buff->data[i], ((i + 1) % 10) + ASCII_A, "Check data"); + + // let tail > head + subtest_no++; + rbuf_flush(buff); + rbuf_bump_head(buff, 9); + rbuf_bump_tail_noopt(buff, 9); + rbuf_bump_head(buff, 1); + ret = rbuf_push(buff, test_data, 9); + CHECK_EQ(ret, 9, "written 9 bytes"); + CHECK_EQ(buff->head, buff->end - 1, "head_ptr"); + CHECK_EQ(buff->tail, buff->head, "tail_ptr"); + rbuf_bump_tail(buff, 1); + //TODO push byte can be usefull optimisation + ret = rbuf_push(buff, &test_data[9], 1); + CHECK_EQ(ret, 1, "written 1 byte"); + CHECK_EQ(rbuf_bytes_free(buff), 0, "empty size == 0"); + for (i = 0; i < 10; i++) + CHECK_EQ(buff->data[i], i + ASCII_A, "Check data"); + + subtest_no++; + rbuf_flush(buff); + rbuf_bump_head(buff, 9); + rbuf_bump_tail_noopt(buff, 7); + rbuf_bump_head(buff, 1); + ret = rbuf_push(buff, test_data, 7); + CHECK_EQ(ret, 7, "written 7 bytes"); + CHECK_EQ(buff->head, buff->data + 7, "head_ptr"); + CHECK_EQ(buff->tail, buff->head, "tail_ptr"); + rbuf_bump_tail(buff, 3); + CHECK_EQ(buff->tail, buff->data, "tail_ptr"); + //TODO push byte can be usefull optimisation + ret = rbuf_push(buff, &test_data[7], 3); + CHECK_EQ(ret, 3, "written 3 bytes"); + CHECK_EQ(rbuf_bytes_free(buff), 0, "empty size == 0"); + for (i = 0; i < 10; i++) + CHECK_EQ(buff->data[i], i + ASCII_A, "Check data"); + + // test can't overfill the buffer + subtest_no++; + rbuf_flush(buff); + rbuf_push(buff, test_data, TEST_DATA_SIZE); + CHECK_EQ(ret, 3, "written 10 bytes"); + for (i = 0; i < 10; i++) + CHECK_EQ(buff->data[i], i + ASCII_A, "Check data"); +} + +#define TEST_RBUF_FIND_BYTES_SIZE 10 +void test_rbuf_find_bytes() +{ + TEST_DECL(); + rbuf_t buff = rbuf_create(TEST_RBUF_FIND_BYTES_SIZE); + char *filler_3 = " "; + char *needle = "needle"; + int idx; + char *ptr; + + // make sure needle is wrapped aroung in the buffer + // to test we still can find it + // target "edle ne" + rbuf_bump_head(buff, TEST_RBUF_FIND_BYTES_SIZE / 2); + rbuf_push(buff, filler_3, strlen(filler_3)); + rbuf_bump_tail(buff, TEST_RBUF_FIND_BYTES_SIZE / 2); + rbuf_push(buff, needle, strlen(needle)); + ptr = rbuf_find_bytes(buff, needle, strlen(needle), &idx); + CHECK_EQ(ptr, buff->data + (TEST_RBUF_FIND_BYTES_SIZE / 2) + strlen(filler_3), "Pointer to needle correct"); + CHECK_EQ(idx, ptr - buff->tail, "Check needle index"); +} + +int main() +{ + test_rbuf_bump_head(); + test_rbuf_bump_tail(); + test_rbuf_get_linear_insert_range(); + test_rbuf_push(); + test_rbuf_find_bytes(); + + printf( + KNRM "Total Tests %d, Total Checks %d, Successful Checks %d, Failed Checks %d\n", + total_tests, total_checks, total_checks - total_fails, total_fails); + if (total_fails) + printf(KRED "!!!Some test(s) Failed!!!\n"); + else + printf(KGRN "ALL TESTS PASSED\n"); + + return total_fails; +} |