rename test directory to avoid name clash with Makefile target

Tue, 07 Feb 2023 21:55:37 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 07 Feb 2023 21:55:37 +0100
changeset 653
e081643aae2a
parent 652
bf817b825ed2
child 654
c9d008861178

rename test directory to avoid name clash with Makefile target

CMakeLists.txt file | annotate | diff | comparison | revisions
test/.clang-tidy file | annotate | diff | comparison | revisions
test/CMakeLists.txt file | annotate | diff | comparison | revisions
test/selftest.cpp file | annotate | diff | comparison | revisions
test/test_allocator.cpp file | annotate | diff | comparison | revisions
test/test_basic_mempool.cpp file | annotate | diff | comparison | revisions
test/test_buffer.cpp file | annotate | diff | comparison | revisions
test/test_compare.cpp file | annotate | diff | comparison | revisions
test/test_hash_key.cpp file | annotate | diff | comparison | revisions
test/test_list.cpp file | annotate | diff | comparison | revisions
test/test_map.cpp file | annotate | diff | comparison | revisions
test/test_printf.cpp file | annotate | diff | comparison | revisions
test/test_string.cpp file | annotate | diff | comparison | revisions
test/test_tree.cpp file | annotate | diff | comparison | revisions
test/test_utils.cpp file | annotate | diff | comparison | revisions
test/util_allocator.cpp file | annotate | diff | comparison | revisions
test/util_allocator.h file | annotate | diff | comparison | revisions
tests/.clang-tidy file | annotate | diff | comparison | revisions
tests/CMakeLists.txt file | annotate | diff | comparison | revisions
tests/selftest.cpp file | annotate | diff | comparison | revisions
tests/test_allocator.cpp file | annotate | diff | comparison | revisions
tests/test_basic_mempool.cpp file | annotate | diff | comparison | revisions
tests/test_buffer.cpp file | annotate | diff | comparison | revisions
tests/test_compare.cpp file | annotate | diff | comparison | revisions
tests/test_hash_key.cpp file | annotate | diff | comparison | revisions
tests/test_list.cpp file | annotate | diff | comparison | revisions
tests/test_map.cpp file | annotate | diff | comparison | revisions
tests/test_printf.cpp file | annotate | diff | comparison | revisions
tests/test_string.cpp file | annotate | diff | comparison | revisions
tests/test_tree.cpp file | annotate | diff | comparison | revisions
tests/test_utils.cpp file | annotate | diff | comparison | revisions
tests/util_allocator.cpp file | annotate | diff | comparison | revisions
tests/util_allocator.h file | annotate | diff | comparison | revisions
     1.1 --- a/CMakeLists.txt	Tue Feb 07 21:53:06 2023 +0100
     1.2 +++ b/CMakeLists.txt	Tue Feb 07 21:55:37 2023 +0100
     1.3 @@ -15,7 +15,7 @@
     1.4  
     1.5  # Tests
     1.6  enable_testing()
     1.7 -add_subdirectory(test)
     1.8 +add_subdirectory(tests)
     1.9  
    1.10  # Web Documentation
    1.11  add_subdirectory(docs/src)
     2.1 --- a/test/.clang-tidy	Tue Feb 07 21:53:06 2023 +0100
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,2 +0,0 @@
     2.4 -# Disable static initialization warning for test code
     2.5 -Checks: '-cert-err58-cpp'
     3.1 --- a/test/CMakeLists.txt	Tue Feb 07 21:53:06 2023 +0100
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,32 +0,0 @@
     3.4 -# Load Google Test Framework
     3.5 -set(CMAKE_CXX_STANDARD 17)
     3.6 -
     3.7 -include(FetchContent)
     3.8 -FetchContent_Declare(
     3.9 -        googletest
    3.10 -        GIT_REPOSITORY https://github.com/google/googletest.git
    3.11 -        GIT_TAG e2239ee6043f73722e7aa812a459f54a28552929 # release 1.11.0
    3.12 -)
    3.13 -# For Windows: Prevent overriding the parent project's compiler/linker settings
    3.14 -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
    3.15 -FetchContent_MakeAvailable(googletest)
    3.16 -include(GoogleTest)
    3.17 -message(STATUS "Google Test made available")
    3.18 -
    3.19 -add_executable(ucxtest
    3.20 -        test_utils.cpp
    3.21 -        test_allocator.cpp
    3.22 -        test_compare.cpp
    3.23 -        test_string.cpp
    3.24 -        test_buffer.cpp
    3.25 -        test_list.cpp
    3.26 -        test_tree.cpp
    3.27 -        test_hash_key.cpp
    3.28 -        test_map.cpp
    3.29 -        test_basic_mempool.cpp
    3.30 -        test_printf.cpp
    3.31 -        selftest.cpp
    3.32 -        util_allocator.cpp
    3.33 -        )
    3.34 -target_link_libraries(ucxtest PRIVATE ucx_static gtest_main)
    3.35 -gtest_discover_tests(ucxtest)
     4.1 --- a/test/selftest.cpp	Tue Feb 07 21:53:06 2023 +0100
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,39 +0,0 @@
     4.4 -/*
     4.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     4.6 - *
     4.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     4.8 - *
     4.9 - * Redistribution and use in source and binary forms, with or without
    4.10 - * modification, are permitted provided that the following conditions are met:
    4.11 - *
    4.12 - *   1. Redistributions of source code must retain the above copyright
    4.13 - *      notice, this list of conditions and the following disclaimer.
    4.14 - *
    4.15 - *   2. Redistributions in binary form must reproduce the above copyright
    4.16 - *      notice, this list of conditions and the following disclaimer in the
    4.17 - *      documentation and/or other materials provided with the distribution.
    4.18 - *
    4.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    4.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    4.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    4.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    4.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    4.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    4.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    4.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    4.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    4.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    4.29 - * POSSIBILITY OF SUCH DAMAGE.
    4.30 - */
    4.31 -
    4.32 -#include <gtest/gtest.h>
    4.33 -#include <cx/common.h>
    4.34 -
    4.35 -TEST(SelfTest, BasicAssertion) {
    4.36 -    EXPECT_EQ(7 * 6, 42);
    4.37 -}
    4.38 -
    4.39 -TEST(SelfTest, UcxVersion) {
    4.40 -    EXPECT_GE(UCX_VERSION_MAJOR, 3);
    4.41 -    EXPECT_GE(UCX_VERSION, 3 << 16);
    4.42 -}
     5.1 --- a/test/test_allocator.cpp	Tue Feb 07 21:53:06 2023 +0100
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,96 +0,0 @@
     5.4 -/*
     5.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     5.6 - *
     5.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     5.8 - *
     5.9 - * Redistribution and use in source and binary forms, with or without
    5.10 - * modification, are permitted provided that the following conditions are met:
    5.11 - *
    5.12 - *   1. Redistributions of source code must retain the above copyright
    5.13 - *      notice, this list of conditions and the following disclaimer.
    5.14 - *
    5.15 - *   2. Redistributions in binary form must reproduce the above copyright
    5.16 - *      notice, this list of conditions and the following disclaimer in the
    5.17 - *      documentation and/or other materials provided with the distribution.
    5.18 - *
    5.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    5.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    5.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    5.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    5.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    5.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    5.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    5.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    5.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    5.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    5.29 - * POSSIBILITY OF SUCH DAMAGE.
    5.30 - */
    5.31 -
    5.32 -#include "cx/allocator.h"
    5.33 -#include <gtest/gtest.h>
    5.34 -
    5.35 -TEST(Allocator, DefaultAllocator) {
    5.36 -    cx_allocator_class *clazz = cxDefaultAllocator->cl;
    5.37 -    ASSERT_NE(clazz, nullptr);
    5.38 -}
    5.39 -
    5.40 -TEST(Allocator, DefaultMalloc) {
    5.41 -    void *test = cxMalloc(cxDefaultAllocator, 16);
    5.42 -    ASSERT_NE(test, nullptr);
    5.43 -    free(test);
    5.44 -}
    5.45 -
    5.46 -TEST(Allocator, DefaultRealloc) {
    5.47 -    void *test = calloc(8, 1);
    5.48 -    memcpy(test, "Test", 5);
    5.49 -    test = cxRealloc(cxDefaultAllocator, test, 16);
    5.50 -    ASSERT_NE(test, nullptr);
    5.51 -    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
    5.52 -    free(test);
    5.53 -}
    5.54 -
    5.55 -TEST(Allocator, Reallocate) {
    5.56 -    void *test = calloc(8, 1);
    5.57 -    memcpy(test, "Test", 5);
    5.58 -    int ret = cxReallocate(cxDefaultAllocator, &test, 16);
    5.59 -    EXPECT_EQ(ret, 0);
    5.60 -    ASSERT_NE(test, nullptr);
    5.61 -    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
    5.62 -    free(test);
    5.63 -}
    5.64 -
    5.65 -TEST(Allocator, DefaultCalloc) {
    5.66 -    char *test = reinterpret_cast<char *>(cxCalloc(cxDefaultAllocator, 8, 2));
    5.67 -    ASSERT_NE(test, nullptr);
    5.68 -    for (int i = 0; i < 16; i++) ASSERT_EQ(test[i], 0);
    5.69 -    free(test);
    5.70 -}
    5.71 -
    5.72 -TEST(Allocator, DefaultFree) {
    5.73 -    void *test = malloc(16);
    5.74 -    EXPECT_NO_FATAL_FAILURE(
    5.75 -            cxFree(cxDefaultAllocator, test);
    5.76 -    );
    5.77 -}
    5.78 -
    5.79 -TEST(Allocator, FailingReallocate) {
    5.80 -    // Mock an allocator that always returns nullptr on realloc
    5.81 -    cx_allocator_class mock_cl;
    5.82 -    mock_cl.realloc = [](
    5.83 -            [[maybe_unused]]void *p,
    5.84 -            [[maybe_unused]]void *d,
    5.85 -            [[maybe_unused]]size_t n
    5.86 -    ) -> void * { return nullptr; };
    5.87 -    cx_allocator_s mock{&mock_cl, nullptr};
    5.88 -
    5.89 -    void *test = calloc(8, 1);
    5.90 -    memcpy(test, "Test", 5);
    5.91 -    void *original = test;
    5.92 -    int ret = cxReallocate(&mock, &test, 16);
    5.93 -    // non-zero return code because of the failure
    5.94 -    EXPECT_NE(ret, 0);
    5.95 -    // the test pointer was not changed and still points to the same memory
    5.96 -    EXPECT_EQ(test, original);
    5.97 -    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
    5.98 -    free(test);
    5.99 -}
     6.1 --- a/test/test_basic_mempool.cpp	Tue Feb 07 21:53:06 2023 +0100
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,154 +0,0 @@
     6.4 -/*
     6.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     6.6 - *
     6.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     6.8 - *
     6.9 - * Redistribution and use in source and binary forms, with or without
    6.10 - * modification, are permitted provided that the following conditions are met:
    6.11 - *
    6.12 - *   1. Redistributions of source code must retain the above copyright
    6.13 - *      notice, this list of conditions and the following disclaimer.
    6.14 - *
    6.15 - *   2. Redistributions in binary form must reproduce the above copyright
    6.16 - *      notice, this list of conditions and the following disclaimer in the
    6.17 - *      documentation and/or other materials provided with the distribution.
    6.18 - *
    6.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    6.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    6.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    6.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    6.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    6.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    6.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    6.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    6.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    6.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    6.29 - * POSSIBILITY OF SUCH DAMAGE.
    6.30 - */
    6.31 -
    6.32 -#include "cx/basic_mempool.h"
    6.33 -#include "util_allocator.h"
    6.34 -#include <gtest/gtest.h>
    6.35 -
    6.36 -class CxBasicMempool : public ::testing::Test {
    6.37 -protected:
    6.38 -    CxMempool *pool = nullptr;
    6.39 -
    6.40 -    void TearDown() override {
    6.41 -        if (pool != nullptr) {
    6.42 -            cxMempoolDestroy(pool);
    6.43 -        }
    6.44 -    }
    6.45 -};
    6.46 -
    6.47 -TEST_F(CxBasicMempool, Create) {
    6.48 -    pool = cxBasicMempoolCreate(16);
    6.49 -    ASSERT_NE(pool->allocator, nullptr);
    6.50 -    ASSERT_NE(pool->cl, nullptr);
    6.51 -    EXPECT_NE(pool->cl->destroy, nullptr);
    6.52 -    ASSERT_NE(pool->allocator->cl, nullptr);
    6.53 -    EXPECT_EQ(pool->allocator->data, pool);
    6.54 -    EXPECT_NE(pool->allocator->cl->malloc, nullptr);
    6.55 -    EXPECT_NE(pool->allocator->cl->calloc, nullptr);
    6.56 -    EXPECT_NE(pool->allocator->cl->realloc, nullptr);
    6.57 -    EXPECT_NE(pool->allocator->cl->free, nullptr);
    6.58 -
    6.59 -    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
    6.60 -    EXPECT_EQ(basic_pool->size, 16);
    6.61 -    EXPECT_EQ(basic_pool->ndata, 0);
    6.62 -    EXPECT_NE(basic_pool->data, nullptr);
    6.63 -}
    6.64 -
    6.65 -TEST_F(CxBasicMempool, malloc) {
    6.66 -    pool = cxBasicMempoolCreate(4);
    6.67 -    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
    6.68 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.69 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.70 -    EXPECT_EQ(basic_pool->ndata, 2);
    6.71 -    EXPECT_EQ(basic_pool->size, 4);
    6.72 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.73 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.74 -    EXPECT_EQ(basic_pool->ndata, 4);
    6.75 -    EXPECT_EQ(basic_pool->size, 4);
    6.76 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.77 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.78 -    EXPECT_EQ(basic_pool->ndata, 6);
    6.79 -    EXPECT_GE(basic_pool->size, 6);
    6.80 -}
    6.81 -
    6.82 -TEST_F(CxBasicMempool, calloc) {
    6.83 -    pool = cxBasicMempoolCreate(4);
    6.84 -
    6.85 -    auto test = (int *) cxCalloc(pool->allocator, 2, sizeof(int));
    6.86 -    ASSERT_NE(test, nullptr);
    6.87 -    EXPECT_EQ(test[0], 0);
    6.88 -    EXPECT_EQ(test[1], 0);
    6.89 -}
    6.90 -
    6.91 -static unsigned test_destructor_called = 0;
    6.92 -
    6.93 -static void test_destructor([[maybe_unused]] void *mem) {
    6.94 -    test_destructor_called++;
    6.95 -}
    6.96 -
    6.97 -TEST_F(CxBasicMempool, destructor) {
    6.98 -    pool = cxBasicMempoolCreate(4);
    6.99 -    auto data = cxMalloc(pool->allocator, sizeof(int));
   6.100 -    *((int *) data) = 13;
   6.101 -    cxMempoolSetDestructor(pool, data, test_destructor);
   6.102 -    EXPECT_EQ(*((int *) data), 13);
   6.103 -    test_destructor_called = 0;
   6.104 -    cxFree(pool->allocator, data);
   6.105 -    EXPECT_EQ(test_destructor_called, 1);
   6.106 -    data = cxMalloc(pool->allocator, sizeof(int));
   6.107 -    cxMempoolSetDestructor(pool, data, test_destructor);
   6.108 -    cxMempoolDestroy(pool);
   6.109 -    pool = nullptr;
   6.110 -    EXPECT_EQ(test_destructor_called, 2);
   6.111 -}
   6.112 -
   6.113 -TEST_F(CxBasicMempool, realloc) {
   6.114 -    pool = cxBasicMempoolCreate(4);
   6.115 -    auto data = cxMalloc(pool->allocator, sizeof(int));
   6.116 -    *((int *) data) = 13;
   6.117 -    cxMempoolSetDestructor(pool, data, test_destructor);
   6.118 -
   6.119 -    void *rdata = data;
   6.120 -    unsigned n = 1;
   6.121 -    while (rdata == data) {
   6.122 -        n <<= 1;
   6.123 -        ASSERT_LT(n, 65536); // eventually the memory should be moved elsewhere
   6.124 -        rdata = cxRealloc(pool->allocator, data, n * sizeof(intptr_t));
   6.125 -    }
   6.126 -
   6.127 -    EXPECT_EQ(*((int *) rdata), 13);
   6.128 -    // test if destructor is still intact
   6.129 -    test_destructor_called = 0;
   6.130 -    cxFree(pool->allocator, rdata);
   6.131 -    EXPECT_EQ(test_destructor_called, 1);
   6.132 -}
   6.133 -
   6.134 -
   6.135 -TEST_F(CxBasicMempool, free) {
   6.136 -    pool = cxBasicMempoolCreate(4);
   6.137 -    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
   6.138 -
   6.139 -    void *mem1;
   6.140 -    void *mem2;
   6.141 -
   6.142 -    mem1 = cxMalloc(pool->allocator, 16);
   6.143 -    cxFree(pool->allocator, mem1);
   6.144 -    EXPECT_EQ(basic_pool->ndata, 0);
   6.145 -
   6.146 -    cxMalloc(pool->allocator, 16);
   6.147 -    cxMalloc(pool->allocator, 16);
   6.148 -    mem1 = cxMalloc(pool->allocator, 16);
   6.149 -    cxMalloc(pool->allocator, 16);
   6.150 -    mem2 = cxMalloc(pool->allocator, 16);
   6.151 -
   6.152 -    EXPECT_EQ(basic_pool->ndata, 5);
   6.153 -    cxFree(pool->allocator, mem1);
   6.154 -    EXPECT_EQ(basic_pool->ndata, 4);
   6.155 -    cxFree(pool->allocator, mem2);
   6.156 -    EXPECT_EQ(basic_pool->ndata, 3);
   6.157 -}
   6.158 \ No newline at end of file
     7.1 --- a/test/test_buffer.cpp	Tue Feb 07 21:53:06 2023 +0100
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,815 +0,0 @@
     7.4 -/*
     7.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     7.6 - *
     7.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     7.8 - *
     7.9 - * Redistribution and use in source and binary forms, with or without
    7.10 - * modification, are permitted provided that the following conditions are met:
    7.11 - *
    7.12 - *   1. Redistributions of source code must retain the above copyright
    7.13 - *      notice, this list of conditions and the following disclaimer.
    7.14 - *
    7.15 - *   2. Redistributions in binary form must reproduce the above copyright
    7.16 - *      notice, this list of conditions and the following disclaimer in the
    7.17 - *      documentation and/or other materials provided with the distribution.
    7.18 - *
    7.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    7.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    7.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    7.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    7.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    7.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    7.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    7.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    7.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    7.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    7.29 - * POSSIBILITY OF SUCH DAMAGE.
    7.30 - */
    7.31 -
    7.32 -#include "cx/buffer.h"
    7.33 -
    7.34 -#include <gtest/gtest.h>
    7.35 -#include "util_allocator.h"
    7.36 -
    7.37 -class BufferFixture : public ::testing::Test {
    7.38 -protected:
    7.39 -    void SetUp() override {
    7.40 -        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    7.41 -        buf.size = 6;
    7.42 -        buf.pos = 3;
    7.43 -    }
    7.44 -
    7.45 -    void TearDown() override {
    7.46 -        cxBufferDestroy(&buf);
    7.47 -    }
    7.48 -
    7.49 -    CxBuffer buf{};
    7.50 -};
    7.51 -
    7.52 -static void expect_default_flush_config(CxBuffer *buf) {
    7.53 -    EXPECT_EQ(buf->flush_blkmax, 0);
    7.54 -    EXPECT_EQ(buf->flush_blksize, 4096);
    7.55 -    EXPECT_EQ(buf->flush_threshold, SIZE_MAX);
    7.56 -    EXPECT_EQ(buf->flush_func, nullptr);
    7.57 -    EXPECT_EQ(buf->flush_target, nullptr);
    7.58 -}
    7.59 -
    7.60 -TEST(BufferInit, WrapSpace) {
    7.61 -    CxTestingAllocator alloc;
    7.62 -    CxBuffer buf;
    7.63 -    void *space = cxMalloc(&alloc, 16);
    7.64 -    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_DEFAULT);
    7.65 -    expect_default_flush_config(&buf);
    7.66 -    EXPECT_EQ(buf.space, space);
    7.67 -    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
    7.68 -    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
    7.69 -    EXPECT_EQ(buf.pos, 0);
    7.70 -    EXPECT_EQ(buf.size, 0);
    7.71 -    EXPECT_EQ(buf.capacity, 16);
    7.72 -    EXPECT_EQ(buf.allocator, &alloc);
    7.73 -    cxBufferDestroy(&buf);
    7.74 -    EXPECT_FALSE(alloc.verify());
    7.75 -    cxFree(&alloc, space);
    7.76 -    EXPECT_TRUE(alloc.verify());
    7.77 -}
    7.78 -
    7.79 -TEST(BufferInit, WrapSpaceAutoExtend) {
    7.80 -    CxTestingAllocator alloc;
    7.81 -    CxBuffer buf;
    7.82 -    void *space = cxMalloc(&alloc, 16);
    7.83 -    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_AUTO_EXTEND);
    7.84 -    expect_default_flush_config(&buf);
    7.85 -    EXPECT_EQ(buf.space, space);
    7.86 -    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, CX_BUFFER_AUTO_EXTEND);
    7.87 -    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
    7.88 -    EXPECT_EQ(buf.pos, 0);
    7.89 -    EXPECT_EQ(buf.size, 0);
    7.90 -    EXPECT_EQ(buf.capacity, 16);
    7.91 -    EXPECT_EQ(buf.allocator, &alloc);
    7.92 -    cxBufferDestroy(&buf);
    7.93 -    EXPECT_FALSE(alloc.verify());
    7.94 -    cxFree(&alloc, space);
    7.95 -    EXPECT_TRUE(alloc.verify());
    7.96 -}
    7.97 -
    7.98 -TEST(BufferInit, WrapSpaceAutoFree) {
    7.99 -    CxTestingAllocator alloc;
   7.100 -    CxBuffer buf;
   7.101 -    void *space = cxMalloc(&alloc, 16);
   7.102 -    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_FREE_CONTENTS);
   7.103 -    expect_default_flush_config(&buf);
   7.104 -    EXPECT_EQ(buf.space, space);
   7.105 -    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
   7.106 -    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
   7.107 -    EXPECT_EQ(buf.pos, 0);
   7.108 -    EXPECT_EQ(buf.size, 0);
   7.109 -    EXPECT_EQ(buf.capacity, 16);
   7.110 -    EXPECT_EQ(buf.allocator, &alloc);
   7.111 -    EXPECT_FALSE(alloc.verify());
   7.112 -    cxBufferDestroy(&buf);
   7.113 -    EXPECT_TRUE(alloc.verify());
   7.114 -}
   7.115 -
   7.116 -TEST(BufferInit, FreshSpace) {
   7.117 -    CxTestingAllocator alloc;
   7.118 -    CxBuffer buf;
   7.119 -    cxBufferInit(&buf, nullptr, 8, &alloc, CX_BUFFER_DEFAULT);
   7.120 -    expect_default_flush_config(&buf);
   7.121 -    EXPECT_NE(buf.space, nullptr);
   7.122 -    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
   7.123 -    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
   7.124 -    EXPECT_EQ(buf.pos, 0);
   7.125 -    EXPECT_EQ(buf.size, 0);
   7.126 -    EXPECT_EQ(buf.capacity, 8);
   7.127 -    EXPECT_EQ(buf.allocator, &alloc);
   7.128 -    EXPECT_FALSE(alloc.verify()); // space is still allocated
   7.129 -    cxBufferDestroy(&buf);
   7.130 -    EXPECT_TRUE(alloc.verify());
   7.131 -}
   7.132 -
   7.133 -class BufferShiftFixture : public ::testing::Test {
   7.134 -protected:
   7.135 -    void SetUp() override {
   7.136 -        ASSERT_TRUE(alloc.verify());
   7.137 -        cxBufferInit(&buf, nullptr, 16, &alloc, CX_BUFFER_DEFAULT);
   7.138 -        memcpy(buf.space, "test____________", 16);
   7.139 -        buf.capacity = 8; // purposely pretend that the buffer has less capacity s.t. we can test beyond the range
   7.140 -        buf.pos = 4;
   7.141 -        buf.size = 4;
   7.142 -    }
   7.143 -
   7.144 -    void TearDown() override {
   7.145 -        cxBufferDestroy(&buf);
   7.146 -        EXPECT_TRUE(alloc.verify());
   7.147 -    }
   7.148 -
   7.149 -    CxTestingAllocator alloc;
   7.150 -    CxBuffer buf{};
   7.151 -};
   7.152 -
   7.153 -class BufferShiftLeft : public BufferShiftFixture {
   7.154 -};
   7.155 -
   7.156 -TEST_F(BufferShiftLeft, Zero) {
   7.157 -    ASSERT_EQ(buf.pos, 4);
   7.158 -    ASSERT_EQ(buf.size, 4);
   7.159 -    int ret = cxBufferShiftLeft(&buf, 0);
   7.160 -    EXPECT_EQ(ret, 0);
   7.161 -    EXPECT_EQ(buf.pos, 4);
   7.162 -    EXPECT_EQ(buf.size, 4);
   7.163 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   7.164 -}
   7.165 -
   7.166 -TEST_F(BufferShiftLeft, ZeroOffsetInterface) {
   7.167 -    ASSERT_EQ(buf.pos, 4);
   7.168 -    ASSERT_EQ(buf.size, 4);
   7.169 -    int ret = cxBufferShift(&buf, -0);
   7.170 -    EXPECT_EQ(ret, 0);
   7.171 -    EXPECT_EQ(buf.pos, 4);
   7.172 -    EXPECT_EQ(buf.size, 4);
   7.173 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   7.174 -}
   7.175 -
   7.176 -TEST_F(BufferShiftLeft, Standard) {
   7.177 -    ASSERT_EQ(buf.pos, 4);
   7.178 -    ASSERT_EQ(buf.size, 4);
   7.179 -    int ret = cxBufferShiftLeft(&buf, 2);
   7.180 -    EXPECT_EQ(ret, 0);
   7.181 -    EXPECT_EQ(buf.pos, 2);
   7.182 -    EXPECT_EQ(buf.size, 2);
   7.183 -    EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
   7.184 -}
   7.185 -
   7.186 -TEST_F(BufferShiftLeft, Overshift) {
   7.187 -    ASSERT_LT(buf.pos, 6);
   7.188 -    ASSERT_LT(buf.size, 6);
   7.189 -    int ret = cxBufferShiftLeft(&buf, 6);
   7.190 -    EXPECT_EQ(ret, 0);
   7.191 -    EXPECT_EQ(buf.pos, 0);
   7.192 -    EXPECT_EQ(buf.size, 0);
   7.193 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   7.194 -}
   7.195 -
   7.196 -TEST_F(BufferShiftLeft, OvershiftPosOnly) {
   7.197 -    buf.pos = 2;
   7.198 -    ASSERT_EQ(buf.size, 4);
   7.199 -    int ret = cxBufferShiftLeft(&buf, 3);
   7.200 -    EXPECT_EQ(ret, 0);
   7.201 -    EXPECT_EQ(buf.pos, 0);
   7.202 -    EXPECT_EQ(buf.size, 1);
   7.203 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   7.204 -}
   7.205 -
   7.206 -TEST_F(BufferShiftLeft, OffsetInterface) {
   7.207 -    buf.pos = 3;
   7.208 -    ASSERT_EQ(buf.size, 4);
   7.209 -    int ret = cxBufferShift(&buf, -2);
   7.210 -    EXPECT_EQ(ret, 0);
   7.211 -    EXPECT_EQ(buf.pos, 1);
   7.212 -    EXPECT_EQ(buf.size, 2);
   7.213 -    EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
   7.214 -}
   7.215 -
   7.216 -class BufferShiftRight : public BufferShiftFixture {
   7.217 -};
   7.218 -
   7.219 -TEST_F(BufferShiftRight, Zero) {
   7.220 -    ASSERT_EQ(buf.pos, 4);
   7.221 -    ASSERT_EQ(buf.size, 4);
   7.222 -    int ret = cxBufferShiftRight(&buf, 0);
   7.223 -    EXPECT_EQ(ret, 0);
   7.224 -    EXPECT_EQ(buf.pos, 4);
   7.225 -    EXPECT_EQ(buf.size, 4);
   7.226 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   7.227 -}
   7.228 -
   7.229 -TEST_F(BufferShiftRight, ZeroOffsetInterface) {
   7.230 -    ASSERT_EQ(buf.pos, 4);
   7.231 -    ASSERT_EQ(buf.size, 4);
   7.232 -    int ret = cxBufferShift(&buf, +0);
   7.233 -    EXPECT_EQ(ret, 0);
   7.234 -    EXPECT_EQ(buf.pos, 4);
   7.235 -    EXPECT_EQ(buf.size, 4);
   7.236 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   7.237 -}
   7.238 -
   7.239 -TEST_F(BufferShiftRight, Standard) {
   7.240 -    ASSERT_EQ(buf.pos, 4);
   7.241 -    ASSERT_EQ(buf.size, 4);
   7.242 -    int ret = cxBufferShiftRight(&buf, 3);
   7.243 -    EXPECT_EQ(ret, 0);
   7.244 -    EXPECT_EQ(buf.pos, 7);
   7.245 -    EXPECT_EQ(buf.size, 7);
   7.246 -    EXPECT_TRUE(memcmp(buf.space, "testest_____", 8) == 0);
   7.247 -}
   7.248 -
   7.249 -TEST_F(BufferShiftRight, OvershiftDiscard) {
   7.250 -    ASSERT_EQ(buf.pos, 4);
   7.251 -    ASSERT_EQ(buf.size, 4);
   7.252 -    ASSERT_EQ(buf.capacity, 8);
   7.253 -    int ret = cxBufferShiftRight(&buf, 6);
   7.254 -    EXPECT_EQ(ret, 0);
   7.255 -    EXPECT_EQ(buf.pos, 8);
   7.256 -    EXPECT_EQ(buf.size, 8);
   7.257 -    EXPECT_EQ(buf.capacity, 8);
   7.258 -    EXPECT_TRUE(memcmp(buf.space, "test__te____", 8) == 0);
   7.259 -}
   7.260 -
   7.261 -TEST_F(BufferShiftRight, OvershiftExtend) {
   7.262 -    ASSERT_EQ(buf.pos, 4);
   7.263 -    ASSERT_EQ(buf.size, 4);
   7.264 -    ASSERT_EQ(buf.capacity, 8);
   7.265 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
   7.266 -    int ret = cxBufferShiftRight(&buf, 6);
   7.267 -    EXPECT_EQ(ret, 0);
   7.268 -    EXPECT_EQ(buf.pos, 10);
   7.269 -    EXPECT_EQ(buf.size, 10);
   7.270 -    EXPECT_GE(buf.capacity, 10);
   7.271 -    EXPECT_TRUE(memcmp(buf.space, "test__test__", 8) == 0);
   7.272 -}
   7.273 -
   7.274 -TEST_F(BufferShiftRight, OffsetInterface) {
   7.275 -    buf.pos = 3;
   7.276 -    ASSERT_EQ(buf.size, 4);
   7.277 -    int ret = cxBufferShift(&buf, 2);
   7.278 -    EXPECT_EQ(ret, 0);
   7.279 -    EXPECT_EQ(buf.pos, 5);
   7.280 -    EXPECT_EQ(buf.size, 6);
   7.281 -    EXPECT_TRUE(memcmp(buf.space, "tetest______", 8) == 0);
   7.282 -}
   7.283 -
   7.284 -TEST(BufferMinimumCapacity, Sufficient) {
   7.285 -    CxTestingAllocator alloc;
   7.286 -    auto space = cxMalloc(&alloc, 8);
   7.287 -    CxBuffer buf;
   7.288 -    cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS);
   7.289 -    memcpy(space, "Testing", 8);
   7.290 -    buf.size = 8;
   7.291 -    cxBufferMinimumCapacity(&buf, 6);
   7.292 -    EXPECT_EQ(buf.capacity, 8);
   7.293 -    EXPECT_EQ(buf.size, 8);
   7.294 -    EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
   7.295 -    cxBufferDestroy(&buf);
   7.296 -    EXPECT_TRUE(alloc.verify());
   7.297 -}
   7.298 -
   7.299 -TEST(BufferMinimumCapacity, Extend) {
   7.300 -    CxTestingAllocator alloc;
   7.301 -    auto space = cxMalloc(&alloc, 8);
   7.302 -    CxBuffer buf;
   7.303 -    cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS); // NO auto extend!
   7.304 -    memcpy(space, "Testing", 8);
   7.305 -    buf.size = 8;
   7.306 -    cxBufferMinimumCapacity(&buf, 16);
   7.307 -    EXPECT_EQ(buf.capacity, 16);
   7.308 -    EXPECT_EQ(buf.size, 8);
   7.309 -    EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
   7.310 -    cxBufferDestroy(&buf);
   7.311 -    EXPECT_TRUE(alloc.verify());
   7.312 -}
   7.313 -
   7.314 -TEST(BufferClear, Test) {
   7.315 -    char space[16];
   7.316 -    strcpy(space, "clear test");
   7.317 -    CxBuffer buf;
   7.318 -    cxBufferInit(&buf, space, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   7.319 -    ASSERT_EQ(buf.size, 0);
   7.320 -    // only clear the used part of the buffer
   7.321 -    cxBufferClear(&buf);
   7.322 -    EXPECT_EQ(memcmp(space, "clear test", 10), 0);
   7.323 -    buf.size = 5;
   7.324 -    buf.pos = 3;
   7.325 -    cxBufferClear(&buf);
   7.326 -    EXPECT_EQ(memcmp(space, "\0\0\0\0\0 test", 10), 0);
   7.327 -    EXPECT_EQ(buf.size, 0);
   7.328 -    EXPECT_EQ(buf.pos, 0);
   7.329 -    cxBufferDestroy(&buf);
   7.330 -}
   7.331 -
   7.332 -class BufferWrite : public ::testing::Test {
   7.333 -protected:
   7.334 -    CxBuffer buf{}, target{};
   7.335 -
   7.336 -    void SetUp() override {
   7.337 -        cxBufferInit(&target, nullptr, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
   7.338 -        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   7.339 -        buf.capacity = 8; // artificially reduce capacity to check OOB writes
   7.340 -        memset(buf.space, 0, 16);
   7.341 -        memcpy(buf.space, "prep", 4);
   7.342 -        buf.size = buf.pos = 4;
   7.343 -    }
   7.344 -
   7.345 -    void TearDown() override {
   7.346 -        cxBufferDestroy(&buf);
   7.347 -        cxBufferDestroy(&target);
   7.348 -    }
   7.349 -
   7.350 -    void enableFlushing() {
   7.351 -        buf.flush_target = &target;
   7.352 -        buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
   7.353 -        buf.flush_blkmax = 1;
   7.354 -    }
   7.355 -};
   7.356 -
   7.357 -static size_t mock_write_limited_rate(
   7.358 -        void const *ptr,
   7.359 -        size_t size,
   7.360 -        __attribute__((unused)) size_t nitems,
   7.361 -        CxBuffer *buffer
   7.362 -) {
   7.363 -    // simulate limited target drain capacity
   7.364 -    static bool full = false;
   7.365 -    if (full) {
   7.366 -        full = false;
   7.367 -        return 0;
   7.368 -    } else {
   7.369 -        full = true;
   7.370 -        return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
   7.371 -    }
   7.372 -}
   7.373 -
   7.374 -TEST_F(BufferWrite, SizeOneFit) {
   7.375 -    const char *data = "test";
   7.376 -    ASSERT_EQ(buf.capacity, 8);
   7.377 -    ASSERT_EQ(buf.pos, 4);
   7.378 -    ASSERT_EQ(buf.size, 4);
   7.379 -    size_t written = cxBufferWrite(data, 1, 4, &buf);
   7.380 -    EXPECT_EQ(written, 4);
   7.381 -    EXPECT_EQ(buf.size, 8);
   7.382 -    EXPECT_EQ(buf.pos, 8);
   7.383 -    EXPECT_EQ(buf.capacity, 8);
   7.384 -    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   7.385 -}
   7.386 -
   7.387 -TEST_F(BufferWrite, SizeOneDiscard) {
   7.388 -    const char *data = "testing";
   7.389 -    ASSERT_EQ(buf.capacity, 8);
   7.390 -    ASSERT_EQ(buf.pos, 4);
   7.391 -    ASSERT_EQ(buf.size, 4);
   7.392 -    size_t written = cxBufferWrite(data, 1, 7, &buf);
   7.393 -    EXPECT_EQ(written, 4);
   7.394 -    EXPECT_EQ(buf.size, 8);
   7.395 -    EXPECT_EQ(buf.pos, 8);
   7.396 -    EXPECT_EQ(buf.capacity, 8);
   7.397 -    EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   7.398 -}
   7.399 -
   7.400 -TEST_F(BufferWrite, SizeOneExtend) {
   7.401 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
   7.402 -    const char *data = "testing";
   7.403 -    ASSERT_EQ(buf.capacity, 8);
   7.404 -    ASSERT_EQ(buf.pos, 4);
   7.405 -    ASSERT_EQ(buf.size, 4);
   7.406 -    size_t written = cxBufferWrite(data, 1, 7, &buf);
   7.407 -    EXPECT_EQ(written, 7);
   7.408 -    EXPECT_EQ(buf.size, 11);
   7.409 -    EXPECT_EQ(buf.pos, 11);
   7.410 -    EXPECT_GE(buf.capacity, 11);
   7.411 -    EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   7.412 -}
   7.413 -
   7.414 -TEST_F(BufferWrite, MultibyteFit) {
   7.415 -    const char *data = "test";
   7.416 -    ASSERT_EQ(buf.capacity, 8);
   7.417 -    ASSERT_EQ(buf.pos, 4);
   7.418 -    ASSERT_EQ(buf.size, 4);
   7.419 -    size_t written = cxBufferWrite(data, 2, 2, &buf);
   7.420 -    EXPECT_EQ(written, 2);
   7.421 -    EXPECT_EQ(buf.size, 8);
   7.422 -    EXPECT_EQ(buf.pos, 8);
   7.423 -    EXPECT_EQ(buf.capacity, 8);
   7.424 -    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   7.425 -}
   7.426 -
   7.427 -TEST_F(BufferWrite, MultibyteDiscard) {
   7.428 -    const char *data = "testing";
   7.429 -    ASSERT_EQ(buf.capacity, 8);
   7.430 -    ASSERT_EQ(buf.size, 4);
   7.431 -    buf.pos = 3;
   7.432 -    size_t written = cxBufferWrite(data, 2, 4, &buf);
   7.433 -    // remember: whole elements are discarded if they do not fit
   7.434 -    EXPECT_EQ(written, 2);
   7.435 -    EXPECT_EQ(buf.size, 7);
   7.436 -    EXPECT_EQ(buf.pos, 7);
   7.437 -    EXPECT_EQ(buf.capacity, 8);
   7.438 -    EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0);
   7.439 -}
   7.440 -
   7.441 -TEST_F(BufferWrite, MultibyteExtend) {
   7.442 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
   7.443 -    const char *data = "tester";
   7.444 -    ASSERT_EQ(buf.capacity, 8);
   7.445 -    ASSERT_EQ(buf.size, 4);
   7.446 -    buf.pos = 3;
   7.447 -    size_t written = cxBufferWrite(data, 2, 3, &buf);
   7.448 -    // remember: whole elements are discarded if they do not fit
   7.449 -    EXPECT_EQ(written, 3);
   7.450 -    EXPECT_EQ(buf.size, 9);
   7.451 -    EXPECT_EQ(buf.pos, 9);
   7.452 -    EXPECT_GE(buf.capacity, 9);
   7.453 -    EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0);
   7.454 -}
   7.455 -
   7.456 -TEST_F(BufferWrite, PutcWrapperFit) {
   7.457 -    ASSERT_EQ(buf.capacity, 8);
   7.458 -    ASSERT_EQ(buf.pos, 4);
   7.459 -    ASSERT_EQ(buf.size, 4);
   7.460 -    int c = cxBufferPut(&buf, 0x200 | 'a');
   7.461 -    EXPECT_EQ(c, 'a');
   7.462 -    EXPECT_EQ(buf.size, 5);
   7.463 -    EXPECT_EQ(buf.pos, 5);
   7.464 -    EXPECT_EQ(buf.capacity, 8);
   7.465 -    EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0);
   7.466 -}
   7.467 -
   7.468 -TEST_F(BufferWrite, PutcWrapperDiscard) {
   7.469 -    ASSERT_EQ(buf.capacity, 8);
   7.470 -    ASSERT_EQ(buf.size, 4);
   7.471 -    buf.pos = 8;
   7.472 -    int c = cxBufferPut(&buf, 0x200 | 'a');
   7.473 -    EXPECT_EQ(c, EOF);
   7.474 -    EXPECT_EQ(buf.size, 4);
   7.475 -    EXPECT_EQ(buf.pos, 8);
   7.476 -    EXPECT_EQ(buf.capacity, 8);
   7.477 -    EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0);
   7.478 -}
   7.479 -
   7.480 -TEST_F(BufferWrite, PutcWrapperExtend) {
   7.481 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
   7.482 -    ASSERT_EQ(buf.capacity, 8);
   7.483 -    ASSERT_EQ(buf.size, 4);
   7.484 -    buf.pos = 8;
   7.485 -    int c = cxBufferPut(&buf, 0x200 | 'a');
   7.486 -    EXPECT_EQ(c, 'a');
   7.487 -    EXPECT_EQ(buf.size, 9);
   7.488 -    EXPECT_EQ(buf.pos, 9);
   7.489 -    EXPECT_GE(buf.capacity, 9);
   7.490 -    EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0);
   7.491 -}
   7.492 -
   7.493 -TEST_F(BufferWrite, PutStringWrapperFit) {
   7.494 -    const char *data = "test";
   7.495 -    ASSERT_EQ(buf.capacity, 8);
   7.496 -    ASSERT_EQ(buf.pos, 4);
   7.497 -    ASSERT_EQ(buf.size, 4);
   7.498 -    size_t written = cxBufferPutString(&buf, data);
   7.499 -    EXPECT_EQ(written, 4);
   7.500 -    EXPECT_EQ(buf.size, 8);
   7.501 -    EXPECT_EQ(buf.pos, 8);
   7.502 -    EXPECT_EQ(buf.capacity, 8);
   7.503 -    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   7.504 -}
   7.505 -
   7.506 -TEST_F(BufferWrite, PutStringWrapperDiscard) {
   7.507 -    const char *data = "testing";
   7.508 -    ASSERT_EQ(buf.capacity, 8);
   7.509 -    ASSERT_EQ(buf.pos, 4);
   7.510 -    ASSERT_EQ(buf.size, 4);
   7.511 -    size_t written = cxBufferPutString(&buf, data);
   7.512 -    EXPECT_EQ(written, 4);
   7.513 -    EXPECT_EQ(buf.size, 8);
   7.514 -    EXPECT_EQ(buf.pos, 8);
   7.515 -    EXPECT_EQ(buf.capacity, 8);
   7.516 -    EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   7.517 -}
   7.518 -
   7.519 -TEST_F(BufferWrite, PutStringWrapperExtend) {
   7.520 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
   7.521 -    const char *data = "testing";
   7.522 -    ASSERT_EQ(buf.capacity, 8);
   7.523 -    ASSERT_EQ(buf.pos, 4);
   7.524 -    ASSERT_EQ(buf.size, 4);
   7.525 -    size_t written = cxBufferPutString(&buf, data);
   7.526 -    EXPECT_EQ(written, 7);
   7.527 -    EXPECT_EQ(buf.size, 11);
   7.528 -    EXPECT_EQ(buf.pos, 11);
   7.529 -    EXPECT_GE(buf.capacity, 11);
   7.530 -    EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   7.531 -}
   7.532 -
   7.533 -TEST_F(BufferWrite, MultOverflow) {
   7.534 -    const char *data = "testing";
   7.535 -    ASSERT_EQ(buf.capacity, 8);
   7.536 -    ASSERT_EQ(buf.pos, 4);
   7.537 -    ASSERT_EQ(buf.size, 4);
   7.538 -    size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf);
   7.539 -    EXPECT_EQ(written, 0);
   7.540 -    EXPECT_EQ(buf.capacity, 8);
   7.541 -    EXPECT_EQ(buf.pos, 4);
   7.542 -    EXPECT_EQ(buf.size, 4);
   7.543 -    EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
   7.544 -}
   7.545 -
   7.546 -TEST_F(BufferWrite, MaxCapaOverflow) {
   7.547 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
   7.548 -    const char *data = "testing";
   7.549 -    ASSERT_EQ(buf.capacity, 8);
   7.550 -    ASSERT_EQ(buf.pos, 4);
   7.551 -    ASSERT_EQ(buf.size, 4);
   7.552 -    size_t written = cxBufferWrite(data, 1, SIZE_MAX - 2, &buf);
   7.553 -    EXPECT_EQ(written, 0);
   7.554 -    EXPECT_EQ(buf.capacity, 8);
   7.555 -    EXPECT_EQ(buf.pos, 4);
   7.556 -    EXPECT_EQ(buf.size, 4);
   7.557 -    EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
   7.558 -}
   7.559 -
   7.560 -TEST_F(BufferWrite, OnlyOverwrite) {
   7.561 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
   7.562 -    ASSERT_EQ(buf.capacity, 8);
   7.563 -    memcpy(buf.space, "preptest", 8);
   7.564 -    buf.pos = 3;
   7.565 -    buf.size = 8;
   7.566 -    size_t written = cxBufferWrite("XXX", 2, 2, &buf);
   7.567 -    EXPECT_EQ(written, 2);
   7.568 -    EXPECT_EQ(buf.capacity, 8);
   7.569 -    EXPECT_EQ(buf.size, 8);
   7.570 -    EXPECT_EQ(buf.pos, 7);
   7.571 -    EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0);
   7.572 -}
   7.573 -
   7.574 -TEST_F(BufferWrite, FlushAtCapacity) {
   7.575 -    enableFlushing();
   7.576 -    ASSERT_EQ(buf.capacity, 8);
   7.577 -    ASSERT_EQ(buf.pos, 4);
   7.578 -    size_t written = cxBufferWrite("foo", 1, 3, &buf);
   7.579 -    EXPECT_EQ(written, 3);
   7.580 -    ASSERT_EQ(buf.pos, 7);
   7.581 -    ASSERT_EQ(buf.size, 7);
   7.582 -    ASSERT_EQ(target.pos, 0);
   7.583 -    ASSERT_EQ(target.size, 0);
   7.584 -    written = cxBufferWrite("hello", 1, 5, &buf);
   7.585 -    EXPECT_EQ(written, 5);
   7.586 -    EXPECT_EQ(buf.pos, 0);
   7.587 -    EXPECT_EQ(buf.size, 0);
   7.588 -    EXPECT_EQ(buf.capacity, 8);
   7.589 -    EXPECT_EQ(target.pos, 12);
   7.590 -    ASSERT_EQ(target.size, 12);
   7.591 -    EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0);
   7.592 -}
   7.593 -
   7.594 -TEST_F(BufferWrite, FlushAtThreshold) {
   7.595 -    enableFlushing();
   7.596 -    buf.flush_threshold = 12;
   7.597 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
   7.598 -    ASSERT_EQ(buf.capacity, 8);
   7.599 -    ASSERT_EQ(buf.pos, 4);
   7.600 -    size_t written = cxBufferWrite("foobar", 1, 6, &buf);
   7.601 -    EXPECT_EQ(written, 6);
   7.602 -    ASSERT_EQ(buf.pos, 10);
   7.603 -    ASSERT_EQ(buf.size, 10);
   7.604 -    ASSERT_GE(buf.capacity, 10);
   7.605 -    ASSERT_LE(buf.capacity, 12);
   7.606 -    ASSERT_EQ(target.pos, 0);
   7.607 -    ASSERT_EQ(target.size, 0);
   7.608 -    written = cxBufferWrite("hello", 1, 5, &buf);
   7.609 -    EXPECT_EQ(written, 5);
   7.610 -    EXPECT_EQ(buf.pos, 0);
   7.611 -    EXPECT_EQ(buf.size, 0);
   7.612 -    EXPECT_LE(buf.capacity, 12);
   7.613 -    EXPECT_EQ(target.pos, 15);
   7.614 -    ASSERT_EQ(target.size, 15);
   7.615 -    EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0);
   7.616 -}
   7.617 -
   7.618 -TEST_F(BufferWrite, FlushRateLimited) {
   7.619 -    enableFlushing();
   7.620 -    // limit the rate of the flush function and the capacity of the target
   7.621 -    target.capacity = 16;
   7.622 -    target.flags &= ~CX_BUFFER_AUTO_EXTEND;
   7.623 -    buf.flush_func = (cx_write_func) mock_write_limited_rate;
   7.624 -    ASSERT_EQ(buf.capacity, 8);
   7.625 -    ASSERT_EQ(buf.pos, 4);
   7.626 -    size_t written = cxBufferWrite("foo", 1, 3, &buf);
   7.627 -    EXPECT_EQ(written, 3);
   7.628 -    ASSERT_EQ(buf.pos, 7);
   7.629 -    ASSERT_EQ(buf.size, 7);
   7.630 -    ASSERT_EQ(target.pos, 0);
   7.631 -    ASSERT_EQ(target.size, 0);
   7.632 -    written = cxBufferWrite("hello, world!", 1, 13, &buf);
   7.633 -    // " world!" fits into this buffer, the remaining stuff is flushed out
   7.634 -    EXPECT_EQ(written, 13);
   7.635 -    EXPECT_EQ(buf.pos, 7);
   7.636 -    EXPECT_EQ(buf.size, 7);
   7.637 -    EXPECT_EQ(buf.capacity, 8);
   7.638 -    EXPECT_EQ(memcmp(buf.space, " world!", 7), 0);
   7.639 -    EXPECT_EQ(target.pos, 13);
   7.640 -    ASSERT_EQ(target.size, 13);
   7.641 -    EXPECT_EQ(target.capacity, 16);
   7.642 -    EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0);
   7.643 -}
   7.644 -
   7.645 -class BufferSeek : public BufferFixture {
   7.646 -};
   7.647 -
   7.648 -TEST_F(BufferSeek, SetZero) {
   7.649 -    int result = cxBufferSeek(&buf, 0, SEEK_SET);
   7.650 -    EXPECT_EQ(result, 0);
   7.651 -    EXPECT_EQ(buf.pos, 0);
   7.652 -}
   7.653 -
   7.654 -TEST_F(BufferSeek, SetValid) {
   7.655 -    int result = cxBufferSeek(&buf, 5, SEEK_SET);
   7.656 -    EXPECT_EQ(result, 0);
   7.657 -    EXPECT_EQ(buf.pos, 5);
   7.658 -}
   7.659 -
   7.660 -TEST_F(BufferSeek, SetInvalid) {
   7.661 -    ASSERT_EQ(buf.pos, 3);
   7.662 -    int result = cxBufferSeek(&buf, 6, SEEK_SET);
   7.663 -    EXPECT_NE(result, 0);
   7.664 -    EXPECT_EQ(buf.pos, 3);
   7.665 -}
   7.666 -
   7.667 -TEST_F(BufferSeek, CurZero) {
   7.668 -    ASSERT_EQ(buf.pos, 3);
   7.669 -    int result = cxBufferSeek(&buf, 0, SEEK_CUR);
   7.670 -    EXPECT_EQ(result, 0);
   7.671 -    EXPECT_EQ(buf.pos, 3);
   7.672 -}
   7.673 -
   7.674 -TEST_F(BufferSeek, CurValidPositive) {
   7.675 -    ASSERT_EQ(buf.pos, 3);
   7.676 -    int result = cxBufferSeek(&buf, 2, SEEK_CUR);
   7.677 -    EXPECT_EQ(result, 0);
   7.678 -    EXPECT_EQ(buf.pos, 5);
   7.679 -}
   7.680 -
   7.681 -TEST_F(BufferSeek, CurValidNegative) {
   7.682 -    ASSERT_EQ(buf.pos, 3);
   7.683 -    int result = cxBufferSeek(&buf, -3, SEEK_CUR);
   7.684 -    EXPECT_EQ(result, 0);
   7.685 -    EXPECT_EQ(buf.pos, 0);
   7.686 -}
   7.687 -
   7.688 -TEST_F(BufferSeek, CurInvalidPositive) {
   7.689 -    ASSERT_EQ(buf.pos, 3);
   7.690 -    int result = cxBufferSeek(&buf, 3, SEEK_CUR);
   7.691 -    EXPECT_NE(result, 0);
   7.692 -    EXPECT_EQ(buf.pos, 3);
   7.693 -}
   7.694 -
   7.695 -TEST_F(BufferSeek, CurInvalidNegative) {
   7.696 -    ASSERT_EQ(buf.pos, 3);
   7.697 -    int result = cxBufferSeek(&buf, -4, SEEK_CUR);
   7.698 -    EXPECT_NE(result, 0);
   7.699 -    EXPECT_EQ(buf.pos, 3);
   7.700 -}
   7.701 -
   7.702 -TEST_F(BufferSeek, EndZero) {
   7.703 -    ASSERT_EQ(buf.size, 6);
   7.704 -    int result = cxBufferSeek(&buf, 0, SEEK_END);
   7.705 -    // the (past-the-)end position is always invalid
   7.706 -    EXPECT_NE(result, 0);
   7.707 -    EXPECT_EQ(buf.pos, 3);
   7.708 -}
   7.709 -
   7.710 -TEST_F(BufferSeek, EndValid) {
   7.711 -    ASSERT_EQ(buf.size, 6);
   7.712 -    int result = cxBufferSeek(&buf, -6, SEEK_END);
   7.713 -    EXPECT_EQ(result, 0);
   7.714 -    EXPECT_EQ(buf.pos, 0);
   7.715 -}
   7.716 -
   7.717 -TEST_F(BufferSeek, EndInvalid) {
   7.718 -    ASSERT_EQ(buf.size, 6);
   7.719 -    int result = cxBufferSeek(&buf, 1, SEEK_END);
   7.720 -    EXPECT_NE(result, 0);
   7.721 -    EXPECT_EQ(buf.pos, 3);
   7.722 -}
   7.723 -
   7.724 -TEST_F(BufferSeek, WhenceInvalid) {
   7.725 -    ASSERT_EQ(buf.size, 6);
   7.726 -    ASSERT_EQ(buf.pos, 3);
   7.727 -    int result = cxBufferSeek(&buf, 2, 9000);
   7.728 -    EXPECT_NE(result, 0);
   7.729 -    EXPECT_EQ(buf.size, 6);
   7.730 -    EXPECT_EQ(buf.pos, 3);
   7.731 -}
   7.732 -
   7.733 -class BufferEof : public BufferFixture {
   7.734 -};
   7.735 -
   7.736 -TEST_F(BufferEof, Reached) {
   7.737 -    buf.pos = buf.size;
   7.738 -    EXPECT_TRUE(cxBufferEof(&buf));
   7.739 -    buf.pos = buf.size - 1;
   7.740 -    ASSERT_FALSE(cxBufferEof(&buf));
   7.741 -    cxBufferPut(&buf, 'a');
   7.742 -    EXPECT_TRUE(cxBufferEof(&buf));
   7.743 -}
   7.744 -
   7.745 -TEST_F(BufferEof, NotReached) {
   7.746 -    buf.pos = buf.size - 1;
   7.747 -    EXPECT_FALSE(cxBufferEof(&buf));
   7.748 -    buf.pos = 0;
   7.749 -    cxBufferWrite("test", 1, 5, &buf);
   7.750 -    EXPECT_FALSE(cxBufferEof(&buf));
   7.751 -}
   7.752 -
   7.753 -class BufferRead : public ::testing::Test {
   7.754 -protected:
   7.755 -    CxBuffer buf{};
   7.756 -
   7.757 -    void SetUp() override {
   7.758 -        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   7.759 -        buf.capacity = 8; // artificially reduce capacity to check OOB writes
   7.760 -        memset(buf.space, 0, 16);
   7.761 -        memcpy(buf.space, "some data", 9);
   7.762 -        buf.size = 9;
   7.763 -    }
   7.764 -
   7.765 -    void TearDown() override {
   7.766 -        cxBufferDestroy(&buf);
   7.767 -    }
   7.768 -};
   7.769 -
   7.770 -TEST_F(BufferRead, GetByte) {
   7.771 -    buf.pos = 2;
   7.772 -    EXPECT_EQ(cxBufferGet(&buf), 'm');
   7.773 -    EXPECT_EQ(cxBufferGet(&buf), 'e');
   7.774 -    EXPECT_EQ(cxBufferGet(&buf), ' ');
   7.775 -    EXPECT_EQ(cxBufferGet(&buf), 'd');
   7.776 -    EXPECT_EQ(buf.pos, 6);
   7.777 -}
   7.778 -
   7.779 -TEST_F(BufferRead, GetEof) {
   7.780 -    buf.pos = buf.size;
   7.781 -    EXPECT_EQ(cxBufferGet(&buf), EOF);
   7.782 -}
   7.783 -
   7.784 -TEST_F(BufferRead, ReadWithinBounds) {
   7.785 -    buf.pos = 2;
   7.786 -    char target[4];
   7.787 -    auto read = cxBufferRead(&target, 1, 4, &buf);
   7.788 -    ASSERT_EQ(read, 4);
   7.789 -    EXPECT_EQ(memcmp(&target, "me d", 4), 0);
   7.790 -    EXPECT_EQ(buf.pos, 6);
   7.791 -}
   7.792 -
   7.793 -TEST_F(BufferRead, ReadOutOfBounds) {
   7.794 -    buf.pos = 6;
   7.795 -    char target[4];
   7.796 -    auto read = cxBufferRead(&target, 1, 4, &buf);
   7.797 -    ASSERT_EQ(read, 3);
   7.798 -    EXPECT_EQ(memcmp(&target, "ata", 3), 0);
   7.799 -    EXPECT_EQ(buf.pos, 9);
   7.800 -}
   7.801 -
   7.802 -TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
   7.803 -    buf.pos = 6;
   7.804 -    char target[4];
   7.805 -    target[2] = '\0';
   7.806 -    auto read = cxBufferRead(&target, 2, 2, &buf);
   7.807 -    ASSERT_EQ(read, 1);
   7.808 -    EXPECT_EQ(memcmp(&target, "at\0", 3), 0);
   7.809 -    EXPECT_EQ(buf.pos, 8);
   7.810 -}
   7.811 -
   7.812 -TEST_F(BufferRead, ReadEof) {
   7.813 -    buf.pos = 9;
   7.814 -    char target[4];
   7.815 -    auto read = cxBufferRead(&target, 1, 1, &buf);
   7.816 -    ASSERT_EQ(read, 0);
   7.817 -    EXPECT_EQ(buf.pos, 9);
   7.818 -}
     8.1 --- a/test/test_compare.cpp	Tue Feb 07 21:53:06 2023 +0100
     8.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.3 @@ -1,127 +0,0 @@
     8.4 -/*
     8.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     8.6 - *
     8.7 - * Copyright 2022 Mike Becker, Olaf Wintermann All rights reserved.
     8.8 - *
     8.9 - * Redistribution and use in source and binary forms, with or without
    8.10 - * modification, are permitted provided that the following conditions are met:
    8.11 - *
    8.12 - *   1. Redistributions of source code must retain the above copyright
    8.13 - *      notice, this list of conditions and the following disclaimer.
    8.14 - *
    8.15 - *   2. Redistributions in binary form must reproduce the above copyright
    8.16 - *      notice, this list of conditions and the following disclaimer in the
    8.17 - *      documentation and/or other materials provided with the distribution.
    8.18 - *
    8.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    8.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    8.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    8.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    8.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    8.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    8.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    8.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    8.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    8.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    8.29 - * POSSIBILITY OF SUCH DAMAGE.
    8.30 - */
    8.31 -
    8.32 -#include "cx/compare.h"
    8.33 -
    8.34 -#include <gtest/gtest.h>
    8.35 -
    8.36 -template<typename T>
    8.37 -static void test_compare(
    8.38 -        int (*fnc)(
    8.39 -                void const *,
    8.40 -                void const *
    8.41 -        )
    8.42 -) {
    8.43 -    auto m = std::numeric_limits<T>::max() / 400;
    8.44 -    T x, y;
    8.45 -
    8.46 -    x = (std::is_signed_v<T> ? -3 : 3) * m;
    8.47 -    y = 5 * m;
    8.48 -    EXPECT_LT(fnc(&x, &y), 0);
    8.49 -    EXPECT_GT(fnc(&y, &x), 0);
    8.50 -
    8.51 -    x = 120 * m;
    8.52 -    y = 348 * m;
    8.53 -    EXPECT_LT(fnc(&x, &y), 0);
    8.54 -    EXPECT_GT(fnc(&y, &x), 0);
    8.55 -
    8.56 -    if constexpr (std::is_signed_v<T>) {
    8.57 -        x = -120 * m;
    8.58 -        y = -348 * m;
    8.59 -        EXPECT_GT(fnc(&x, &y), 0);
    8.60 -        EXPECT_LT(fnc(&y, &x), 0);
    8.61 -    }
    8.62 -
    8.63 -    x = y;
    8.64 -    EXPECT_EQ(fnc(&x, &y), 0);
    8.65 -    EXPECT_EQ(fnc(&y, &x), 0);
    8.66 -}
    8.67 -
    8.68 -TEST(Compare, Int) {
    8.69 -    test_compare<int>(cx_cmp_int);
    8.70 -}
    8.71 -
    8.72 -TEST(Compare, Longint) {
    8.73 -    test_compare<long int>(cx_cmp_longint);
    8.74 -}
    8.75 -
    8.76 -TEST(Compare, Longlong) {
    8.77 -    test_compare<long long>(cx_cmp_longlong);
    8.78 -}
    8.79 -
    8.80 -TEST(Compare, Int16) {
    8.81 -    test_compare<int16_t>(cx_cmp_int16);
    8.82 -}
    8.83 -
    8.84 -TEST(Compare, Int32) {
    8.85 -    test_compare<int32_t>(cx_cmp_int32);
    8.86 -}
    8.87 -
    8.88 -TEST(Compare, Int64) {
    8.89 -    test_compare<int64_t>(cx_cmp_int64);
    8.90 -}
    8.91 -
    8.92 -TEST(Compare, Uint) {
    8.93 -    test_compare<unsigned int>(cx_cmp_uint);
    8.94 -}
    8.95 -
    8.96 -TEST(Compare, Ulongint) {
    8.97 -    test_compare<unsigned long int>(cx_cmp_ulongint);
    8.98 -}
    8.99 -
   8.100 -TEST(Compare, Ulonglong) {
   8.101 -    test_compare<unsigned long long>(cx_cmp_ulonglong);
   8.102 -}
   8.103 -
   8.104 -TEST(Compare, Uint16) {
   8.105 -    test_compare<uint16_t>(cx_cmp_uint16);
   8.106 -}
   8.107 -
   8.108 -TEST(Compare, Uint32) {
   8.109 -    test_compare<uint32_t>(cx_cmp_uint32);
   8.110 -}
   8.111 -
   8.112 -TEST(Compare, Uint64) {
   8.113 -    test_compare<uint64_t>(cx_cmp_uint64);
   8.114 -}
   8.115 -
   8.116 -TEST(Compare, Float) {
   8.117 -    test_compare<float>(cx_cmp_float);
   8.118 -}
   8.119 -
   8.120 -TEST(Compare, Double) {
   8.121 -    test_compare<double>(cx_cmp_double);
   8.122 -}
   8.123 -
   8.124 -TEST(Compare, IntPtr) {
   8.125 -    test_compare<intptr_t>(cx_cmp_intptr);
   8.126 -}
   8.127 -
   8.128 -TEST(Compare, UintPtr) {
   8.129 -    test_compare<uintptr_t>(cx_cmp_uintptr);
   8.130 -}
     9.1 --- a/test/test_hash_key.cpp	Tue Feb 07 21:53:06 2023 +0100
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,87 +0,0 @@
     9.4 -/*
     9.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     9.6 - *
     9.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     9.8 - *
     9.9 - * Redistribution and use in source and binary forms, with or without
    9.10 - * modification, are permitted provided that the following conditions are met:
    9.11 - *
    9.12 - *   1. Redistributions of source code must retain the above copyright
    9.13 - *      notice, this list of conditions and the following disclaimer.
    9.14 - *
    9.15 - *   2. Redistributions in binary form must reproduce the above copyright
    9.16 - *      notice, this list of conditions and the following disclaimer in the
    9.17 - *      documentation and/or other materials provided with the distribution.
    9.18 - *
    9.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    9.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    9.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    9.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    9.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    9.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    9.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    9.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    9.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    9.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    9.29 - * POSSIBILITY OF SUCH DAMAGE.
    9.30 - */
    9.31 -
    9.32 -#include "cx/hash_key.h"
    9.33 -
    9.34 -#include <gtest/gtest.h>
    9.35 -
    9.36 -TEST(cx_hash_key, functions) {
    9.37 -    auto str = "my key";
    9.38 -    auto len = strlen(str);
    9.39 -
    9.40 -    auto str_key = cx_hash_key_str(str);
    9.41 -    auto bytes_key = cx_hash_key_bytes(
    9.42 -            reinterpret_cast<unsigned char const *>(str), len);
    9.43 -    auto obj_key = cx_hash_key(
    9.44 -            reinterpret_cast<void const *>(str), len);
    9.45 -
    9.46 -    EXPECT_EQ(str_key.hash, bytes_key.hash);
    9.47 -    EXPECT_EQ(obj_key.hash, bytes_key.hash);
    9.48 -    EXPECT_EQ(str_key.len, len);
    9.49 -    EXPECT_EQ(bytes_key.len, len);
    9.50 -    EXPECT_EQ(bytes_key.len, len);
    9.51 -    EXPECT_EQ(str_key.data.cstr, str);
    9.52 -    EXPECT_EQ(bytes_key.data.cbytes, reinterpret_cast<unsigned char const *>(str));
    9.53 -    EXPECT_EQ(bytes_key.data.cobj, reinterpret_cast<void const *>(str));
    9.54 -}
    9.55 -
    9.56 -TEST(cx_hash_key, empty_string) {
    9.57 -    auto str = "";
    9.58 -
    9.59 -    auto str_key = cx_hash_key_str(str);
    9.60 -    auto bytes_key = cx_hash_key_bytes(
    9.61 -            reinterpret_cast<unsigned char const *>(str), 0);
    9.62 -    auto obj_key = cx_hash_key(
    9.63 -            reinterpret_cast<void const *>(str), 0);
    9.64 -
    9.65 -    EXPECT_EQ(bytes_key.hash, 4152238450u);
    9.66 -    EXPECT_EQ(str_key.hash, 4152238450u);
    9.67 -    EXPECT_EQ(obj_key.hash, 4152238450u);
    9.68 -    EXPECT_EQ(str_key.len, 0);
    9.69 -    EXPECT_EQ(bytes_key.len, 0);
    9.70 -    EXPECT_EQ(bytes_key.len, 0);
    9.71 -    EXPECT_EQ(str_key.data.cstr, str);
    9.72 -    EXPECT_EQ(bytes_key.data.cbytes, reinterpret_cast<unsigned char const *>(str));
    9.73 -    EXPECT_EQ(bytes_key.data.cobj, reinterpret_cast<void const *>(str));
    9.74 -}
    9.75 -
    9.76 -TEST(cx_hash_key, null_ptr) {
    9.77 -    auto str_key = cx_hash_key_str(nullptr);
    9.78 -    auto bytes_key = cx_hash_key_bytes(nullptr, 0);
    9.79 -    auto obj_key = cx_hash_key(nullptr, 0);
    9.80 -
    9.81 -    EXPECT_EQ(bytes_key.hash, 1574210520u);
    9.82 -    EXPECT_EQ(str_key.hash, 1574210520u);
    9.83 -    EXPECT_EQ(obj_key.hash, 1574210520u);
    9.84 -    EXPECT_EQ(str_key.len, 0);
    9.85 -    EXPECT_EQ(bytes_key.len, 0);
    9.86 -    EXPECT_EQ(bytes_key.len, 0);
    9.87 -    EXPECT_EQ(str_key.data.cstr, nullptr);
    9.88 -    EXPECT_EQ(bytes_key.data.cbytes, nullptr);
    9.89 -    EXPECT_EQ(bytes_key.data.cobj, nullptr);
    9.90 -}
    10.1 --- a/test/test_list.cpp	Tue Feb 07 21:53:06 2023 +0100
    10.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.3 @@ -1,1077 +0,0 @@
    10.4 -/*
    10.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    10.6 - *
    10.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    10.8 - *
    10.9 - * Redistribution and use in source and binary forms, with or without
   10.10 - * modification, are permitted provided that the following conditions are met:
   10.11 - *
   10.12 - *   1. Redistributions of source code must retain the above copyright
   10.13 - *      notice, this list of conditions and the following disclaimer.
   10.14 - *
   10.15 - *   2. Redistributions in binary form must reproduce the above copyright
   10.16 - *      notice, this list of conditions and the following disclaimer in the
   10.17 - *      documentation and/or other materials provided with the distribution.
   10.18 - *
   10.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   10.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   10.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   10.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   10.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   10.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   10.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   10.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   10.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   10.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   10.29 - * POSSIBILITY OF SUCH DAMAGE.
   10.30 - */
   10.31 -
   10.32 -#include "cx/linked_list.h"
   10.33 -#include "cx/array_list.h"
   10.34 -#include "cx/utils.h"
   10.35 -#include "cx/compare.h"
   10.36 -#include "util_allocator.h"
   10.37 -
   10.38 -#include <gtest/gtest.h>
   10.39 -#include <array>
   10.40 -#include <vector>
   10.41 -#include <unordered_set>
   10.42 -#include <algorithm>
   10.43 -
   10.44 -struct node {
   10.45 -    node *next = nullptr;
   10.46 -    node *prev = nullptr;
   10.47 -    int data = 0;
   10.48 -};
   10.49 -
   10.50 -const ptrdiff_t loc_prev = offsetof(struct node, prev);
   10.51 -const ptrdiff_t loc_next = offsetof(struct node, next);
   10.52 -const ptrdiff_t loc_data = offsetof(struct node, data);
   10.53 -
   10.54 -struct node_test_data {
   10.55 -    node *begin = nullptr;
   10.56 -
   10.57 -    explicit node_test_data(node *begin) : begin(begin) {
   10.58 -        auto n = begin;
   10.59 -        while (n != nullptr) {
   10.60 -            nodes.push_back(n);
   10.61 -            n = n->next;
   10.62 -        }
   10.63 -    }
   10.64 -
   10.65 -    node_test_data(node_test_data &) = delete;
   10.66 -
   10.67 -    node_test_data(node_test_data &&) = default;
   10.68 -
   10.69 -    ~node_test_data() {
   10.70 -        for (auto &&n: nodes) delete n;
   10.71 -    }
   10.72 -
   10.73 -private:
   10.74 -    std::vector<node *> nodes;
   10.75 -};
   10.76 -
   10.77 -static node_test_data create_nodes_test_data(size_t len) {
   10.78 -    if (len == 0) return node_test_data{nullptr};
   10.79 -    auto begin = new node;
   10.80 -    auto prev = begin;
   10.81 -    for (size_t i = 1; i < len; i++) {
   10.82 -        auto n = new node;
   10.83 -        cx_linked_list_link(prev, n, loc_prev, loc_next);
   10.84 -        prev = n;
   10.85 -    }
   10.86 -    return node_test_data{begin};
   10.87 -}
   10.88 -
   10.89 -template<typename InputIter>
   10.90 -static node_test_data create_nodes_test_data(
   10.91 -        InputIter begin,
   10.92 -        InputIter end
   10.93 -) {
   10.94 -    if (begin == end) return node_test_data{nullptr};
   10.95 -    node *first = new node;
   10.96 -    first->data = *begin;
   10.97 -    node *prev = first;
   10.98 -    begin++;
   10.99 -    for (; begin != end; begin++) {
  10.100 -        auto n = new node;
  10.101 -        n->data = *begin;
  10.102 -        cx_linked_list_link(prev, n, loc_prev, loc_next);
  10.103 -        prev = n;
  10.104 -    }
  10.105 -    return node_test_data{first};
  10.106 -}
  10.107 -
  10.108 -static node_test_data create_nodes_test_data(std::initializer_list<int> data) {
  10.109 -    return create_nodes_test_data(data.begin(), data.end());
  10.110 -}
  10.111 -
  10.112 -template<size_t N>
  10.113 -struct int_test_data {
  10.114 -    std::array<int, N> data;
  10.115 -
  10.116 -    int_test_data() {
  10.117 -        cx_for_n (i, N) data[i] = ::rand(); // NOLINT(cert-msc50-cpp)
  10.118 -    }
  10.119 -};
  10.120 -
  10.121 -TEST(LinkedList_LowLevel, link_unlink) {
  10.122 -    node a, b, c;
  10.123 -
  10.124 -    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  10.125 -    EXPECT_EQ(a.prev, nullptr);
  10.126 -    EXPECT_EQ(a.next, &b);
  10.127 -    EXPECT_EQ(b.prev, &a);
  10.128 -    EXPECT_EQ(b.next, nullptr);
  10.129 -
  10.130 -    cx_linked_list_unlink(&a, &b, loc_prev, loc_next);
  10.131 -    EXPECT_EQ(a.prev, nullptr);
  10.132 -    EXPECT_EQ(a.next, nullptr);
  10.133 -    EXPECT_EQ(b.prev, nullptr);
  10.134 -    EXPECT_EQ(b.next, nullptr);
  10.135 -
  10.136 -    cx_linked_list_link(&b, &c, loc_prev, loc_next);
  10.137 -    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  10.138 -    cx_linked_list_unlink(&b, &c, loc_prev, loc_next);
  10.139 -    EXPECT_EQ(a.prev, nullptr);
  10.140 -    EXPECT_EQ(a.next, &b);
  10.141 -    EXPECT_EQ(b.prev, &a);
  10.142 -    EXPECT_EQ(b.next, nullptr);
  10.143 -    EXPECT_EQ(c.prev, nullptr);
  10.144 -    EXPECT_EQ(c.next, nullptr);
  10.145 -}
  10.146 -
  10.147 -TEST(LinkedList_LowLevel, cx_linked_list_at) {
  10.148 -    node a, b, c, d;
  10.149 -    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  10.150 -    cx_linked_list_link(&b, &c, loc_prev, loc_next);
  10.151 -    cx_linked_list_link(&c, &d, loc_prev, loc_next);
  10.152 -
  10.153 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 0), &a);
  10.154 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 1), &b);
  10.155 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 2), &c);
  10.156 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 3), &d);
  10.157 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 4), nullptr);
  10.158 -
  10.159 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_prev, 0), &a);
  10.160 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 1), &b);
  10.161 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 2), &c);
  10.162 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 3), &d);
  10.163 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 4), nullptr);
  10.164 -
  10.165 -    EXPECT_EQ(cx_linked_list_at(&d, 3, loc_prev, 0), &a);
  10.166 -    EXPECT_EQ(cx_linked_list_at(&d, 3, loc_prev, 1), &b);
  10.167 -}
  10.168 -
  10.169 -TEST(LinkedList_LowLevel, cx_linked_list_find) {
  10.170 -    auto testdata = create_nodes_test_data({2, 4, 6, 8});
  10.171 -    auto list = testdata.begin;
  10.172 -    int s;
  10.173 -
  10.174 -    s = 2;
  10.175 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 0);
  10.176 -    s = 4;
  10.177 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 1);
  10.178 -    s = 6;
  10.179 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 2);
  10.180 -    s = 8;
  10.181 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 3);
  10.182 -    s = 10;
  10.183 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 4);
  10.184 -    s = -2;
  10.185 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 4);
  10.186 -}
  10.187 -
  10.188 -TEST(LinkedList_LowLevel, cx_linked_list_compare) {
  10.189 -    auto ta = create_nodes_test_data({2, 4, 6, 8});
  10.190 -    auto tb = create_nodes_test_data({2, 4, 6});
  10.191 -    auto tc = create_nodes_test_data({2, 4, 6, 9});
  10.192 -    auto la = ta.begin, lb = tb.begin, lc = tc.begin;
  10.193 -
  10.194 -    EXPECT_GT(cx_linked_list_compare(la, lb, loc_next, loc_data, cx_cmp_int), 0);
  10.195 -    EXPECT_LT(cx_linked_list_compare(lb, la, loc_next, loc_data, cx_cmp_int), 0);
  10.196 -    EXPECT_GT(cx_linked_list_compare(lc, la, loc_next, loc_data, cx_cmp_int), 0);
  10.197 -    EXPECT_LT(cx_linked_list_compare(la, lc, loc_next, loc_data, cx_cmp_int), 0);
  10.198 -    EXPECT_EQ(cx_linked_list_compare(la, la, loc_next, loc_data, cx_cmp_int), 0);
  10.199 -}
  10.200 -
  10.201 -TEST(LinkedList_LowLevel, cx_linked_list_add) {
  10.202 -    // test with begin, end / prev, next
  10.203 -    {
  10.204 -        node nodes[4];
  10.205 -        void *begin = nullptr, *end = nullptr;
  10.206 -
  10.207 -        cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[0]);
  10.208 -        EXPECT_EQ(begin, &nodes[0]);
  10.209 -        EXPECT_EQ(end, &nodes[0]);
  10.210 -        EXPECT_EQ(nodes[0].prev, nullptr);
  10.211 -        EXPECT_EQ(nodes[0].next, nullptr);
  10.212 -
  10.213 -        cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[1]);
  10.214 -        EXPECT_EQ(begin, &nodes[0]);
  10.215 -        EXPECT_EQ(end, &nodes[1]);
  10.216 -        EXPECT_EQ(nodes[0].next, &nodes[1]);
  10.217 -        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  10.218 -    }
  10.219 -
  10.220 -    // test with begin only / prev, next
  10.221 -    {
  10.222 -        node nodes[4];
  10.223 -        void *begin = nullptr;
  10.224 -
  10.225 -        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[0]);
  10.226 -        EXPECT_EQ(begin, &nodes[0]);
  10.227 -        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[1]);
  10.228 -        EXPECT_EQ(begin, &nodes[0]);
  10.229 -        EXPECT_EQ(nodes[0].next, &nodes[1]);
  10.230 -        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  10.231 -
  10.232 -        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[2]);
  10.233 -        EXPECT_EQ(nodes[1].next, &nodes[2]);
  10.234 -        EXPECT_EQ(nodes[2].prev, &nodes[1]);
  10.235 -    }
  10.236 -
  10.237 -    // test with end only / prev, next
  10.238 -    {
  10.239 -        node nodes[4];
  10.240 -        void *end = nullptr;
  10.241 -
  10.242 -        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[0]);
  10.243 -        EXPECT_EQ(end, &nodes[0]);
  10.244 -        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[1]);
  10.245 -        EXPECT_EQ(end, &nodes[1]);
  10.246 -        EXPECT_EQ(nodes[0].next, &nodes[1]);
  10.247 -        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  10.248 -
  10.249 -        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[2]);
  10.250 -        EXPECT_EQ(end, &nodes[2]);
  10.251 -        EXPECT_EQ(nodes[1].next, &nodes[2]);
  10.252 -        EXPECT_EQ(nodes[2].prev, &nodes[1]);
  10.253 -    }
  10.254 -
  10.255 -    // test with begin, end / next
  10.256 -    {
  10.257 -        node nodes[4];
  10.258 -        void *begin = nullptr, *end = nullptr;
  10.259 -
  10.260 -        cx_linked_list_add(&begin, &end, -1, loc_next, &nodes[0]);
  10.261 -        EXPECT_EQ(begin, &nodes[0]);
  10.262 -        EXPECT_EQ(end, &nodes[0]);
  10.263 -        cx_linked_list_add(&begin, &end, -1, loc_next, &nodes[1]);
  10.264 -        EXPECT_EQ(end, &nodes[1]);
  10.265 -        EXPECT_EQ(nodes[0].next, &nodes[1]);
  10.266 -        EXPECT_EQ(nodes[1].prev, nullptr);
  10.267 -    }
  10.268 -}
  10.269 -
  10.270 -TEST(LinkedList_LowLevel, cx_linked_list_prepend) {
  10.271 -    // test with begin, end / prev, next
  10.272 -    {
  10.273 -        node nodes[4];
  10.274 -        void *begin = nullptr, *end = nullptr;
  10.275 -
  10.276 -        cx_linked_list_prepend(&begin, &end, loc_prev, loc_next, &nodes[0]);
  10.277 -        EXPECT_EQ(begin, &nodes[0]);
  10.278 -        EXPECT_EQ(end, &nodes[0]);
  10.279 -        EXPECT_EQ(nodes[0].prev, nullptr);
  10.280 -        EXPECT_EQ(nodes[0].next, nullptr);
  10.281 -
  10.282 -        cx_linked_list_prepend(&begin, &end, loc_prev, loc_next, &nodes[1]);
  10.283 -        EXPECT_EQ(begin, &nodes[1]);
  10.284 -        EXPECT_EQ(end, &nodes[0]);
  10.285 -        EXPECT_EQ(nodes[1].next, &nodes[0]);
  10.286 -        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  10.287 -    }
  10.288 -
  10.289 -    // test with begin only / prev, next
  10.290 -    {
  10.291 -        node nodes[4];
  10.292 -        void *begin = nullptr;
  10.293 -
  10.294 -        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[0]);
  10.295 -        EXPECT_EQ(begin, &nodes[0]);
  10.296 -        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[1]);
  10.297 -        EXPECT_EQ(begin, &nodes[1]);
  10.298 -        EXPECT_EQ(nodes[1].next, &nodes[0]);
  10.299 -        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  10.300 -
  10.301 -        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[2]);
  10.302 -        EXPECT_EQ(begin, &nodes[2]);
  10.303 -        EXPECT_EQ(nodes[2].next, &nodes[1]);
  10.304 -        EXPECT_EQ(nodes[1].prev, &nodes[2]);
  10.305 -    }
  10.306 -
  10.307 -    // test with end only / prev, next
  10.308 -    {
  10.309 -        node nodes[4];
  10.310 -        void *end = nullptr;
  10.311 -
  10.312 -        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[0]);
  10.313 -        EXPECT_EQ(end, &nodes[0]);
  10.314 -        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[1]);
  10.315 -        EXPECT_EQ(end, &nodes[0]);
  10.316 -        EXPECT_EQ(nodes[1].next, &nodes[0]);
  10.317 -        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  10.318 -
  10.319 -        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[2]);
  10.320 -        EXPECT_EQ(end, &nodes[0]);
  10.321 -        EXPECT_EQ(nodes[2].next, &nodes[1]);
  10.322 -        EXPECT_EQ(nodes[1].prev, &nodes[2]);
  10.323 -    }
  10.324 -
  10.325 -    // test with begin, end / next
  10.326 -    {
  10.327 -        node nodes[4];
  10.328 -        void *begin = nullptr, *end = nullptr;
  10.329 -
  10.330 -        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[0]);
  10.331 -        EXPECT_EQ(begin, &nodes[0]);
  10.332 -        EXPECT_EQ(end, &nodes[0]);
  10.333 -        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[1]);
  10.334 -        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[2]);
  10.335 -        EXPECT_EQ(begin, &nodes[2]);
  10.336 -        EXPECT_EQ(end, &nodes[0]);
  10.337 -        EXPECT_EQ(nodes[1].next, &nodes[0]);
  10.338 -        EXPECT_EQ(nodes[2].next, &nodes[1]);
  10.339 -        EXPECT_EQ(nodes[1].prev, nullptr);
  10.340 -        EXPECT_EQ(nodes[0].prev, nullptr);
  10.341 -    }
  10.342 -}
  10.343 -
  10.344 -TEST(LinkedList_LowLevel, cx_linked_list_insert) {
  10.345 -    // insert mid list
  10.346 -    {
  10.347 -        node nodes[4];
  10.348 -        void *begin = &nodes[0], *end = &nodes[2];
  10.349 -
  10.350 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  10.351 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  10.352 -
  10.353 -        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, &nodes[1], &nodes[3]);
  10.354 -        EXPECT_EQ(begin, &nodes[0]);
  10.355 -        EXPECT_EQ(end, &nodes[2]);
  10.356 -        EXPECT_EQ(nodes[1].next, &nodes[3]);
  10.357 -        EXPECT_EQ(nodes[2].prev, &nodes[3]);
  10.358 -        EXPECT_EQ(nodes[3].prev, &nodes[1]);
  10.359 -        EXPECT_EQ(nodes[3].next, &nodes[2]);
  10.360 -    }
  10.361 -
  10.362 -    // insert end
  10.363 -    {
  10.364 -        node nodes[4];
  10.365 -        void *begin = &nodes[0], *end = &nodes[2];
  10.366 -
  10.367 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  10.368 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  10.369 -
  10.370 -        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, &nodes[2], &nodes[3]);
  10.371 -        EXPECT_EQ(begin, &nodes[0]);
  10.372 -        EXPECT_EQ(end, &nodes[3]);
  10.373 -        EXPECT_EQ(nodes[2].next, &nodes[3]);
  10.374 -        EXPECT_EQ(nodes[3].prev, &nodes[2]);
  10.375 -        EXPECT_EQ(nodes[3].next, nullptr);
  10.376 -    }
  10.377 -
  10.378 -    // insert begin
  10.379 -    {
  10.380 -        node nodes[4];
  10.381 -        void *begin = &nodes[0], *end = &nodes[2];
  10.382 -
  10.383 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  10.384 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  10.385 -
  10.386 -        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, nullptr, &nodes[3]);
  10.387 -        EXPECT_EQ(begin, &nodes[3]);
  10.388 -        EXPECT_EQ(end, &nodes[2]);
  10.389 -        EXPECT_EQ(nodes[0].prev, &nodes[3]);
  10.390 -        EXPECT_EQ(nodes[3].prev, nullptr);
  10.391 -        EXPECT_EQ(nodes[3].next, &nodes[0]);
  10.392 -    }
  10.393 -}
  10.394 -
  10.395 -TEST(LinkedList_LowLevel, cx_linked_list_insert_chain) {
  10.396 -    // insert mid list
  10.397 -    {
  10.398 -        node nodes[5];
  10.399 -        void *begin = &nodes[0], *end = &nodes[2];
  10.400 -
  10.401 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  10.402 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  10.403 -        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  10.404 -
  10.405 -        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, &nodes[1], &nodes[3], nullptr);
  10.406 -        EXPECT_EQ(begin, &nodes[0]);
  10.407 -        EXPECT_EQ(end, &nodes[2]);
  10.408 -        EXPECT_EQ(nodes[1].next, &nodes[3]);
  10.409 -        EXPECT_EQ(nodes[2].prev, &nodes[4]);
  10.410 -        EXPECT_EQ(nodes[3].prev, &nodes[1]);
  10.411 -        EXPECT_EQ(nodes[4].next, &nodes[2]);
  10.412 -    }
  10.413 -
  10.414 -    // insert end
  10.415 -    {
  10.416 -        node nodes[5];
  10.417 -        void *begin = &nodes[0], *end = &nodes[2];
  10.418 -
  10.419 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  10.420 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  10.421 -        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  10.422 -
  10.423 -        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, &nodes[2], &nodes[3], nullptr);
  10.424 -        EXPECT_EQ(begin, &nodes[0]);
  10.425 -        EXPECT_EQ(end, &nodes[4]);
  10.426 -        EXPECT_EQ(nodes[2].next, &nodes[3]);
  10.427 -        EXPECT_EQ(nodes[3].prev, &nodes[2]);
  10.428 -        EXPECT_EQ(nodes[4].next, nullptr);
  10.429 -    }
  10.430 -
  10.431 -    // insert begin
  10.432 -    {
  10.433 -        node nodes[5];
  10.434 -        void *begin = &nodes[0], *end = &nodes[2];
  10.435 -
  10.436 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  10.437 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  10.438 -        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  10.439 -
  10.440 -        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, nullptr, &nodes[3], nullptr);
  10.441 -        EXPECT_EQ(begin, &nodes[3]);
  10.442 -        EXPECT_EQ(end, &nodes[2]);
  10.443 -        EXPECT_EQ(nodes[0].prev, &nodes[4]);
  10.444 -        EXPECT_EQ(nodes[3].prev, nullptr);
  10.445 -        EXPECT_EQ(nodes[4].next, &nodes[0]);
  10.446 -    }
  10.447 -}
  10.448 -
  10.449 -TEST(LinkedList_LowLevel, cx_linked_list_first) {
  10.450 -    auto testdata = create_nodes_test_data(3);
  10.451 -    auto begin = testdata.begin;
  10.452 -    EXPECT_EQ(cx_linked_list_first(begin, loc_prev), begin);
  10.453 -    EXPECT_EQ(cx_linked_list_first(begin->next, loc_prev), begin);
  10.454 -    EXPECT_EQ(cx_linked_list_first(begin->next->next, loc_prev), begin);
  10.455 -}
  10.456 -
  10.457 -TEST(LinkedList_LowLevel, cx_linked_list_last) {
  10.458 -    auto testdata = create_nodes_test_data(3);
  10.459 -    auto begin = testdata.begin;
  10.460 -    auto end = begin->next->next;
  10.461 -    EXPECT_EQ(cx_linked_list_last(begin, loc_next), end);
  10.462 -    EXPECT_EQ(cx_linked_list_last(begin->next, loc_next), end);
  10.463 -    EXPECT_EQ(cx_linked_list_last(begin->next->next, loc_next), end);
  10.464 -}
  10.465 -
  10.466 -TEST(LinkedList_LowLevel, cx_linked_list_prev) {
  10.467 -    auto testdata = create_nodes_test_data(3);
  10.468 -    auto begin = testdata.begin;
  10.469 -    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin), nullptr);
  10.470 -    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin->next), begin);
  10.471 -    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin->next->next), begin->next);
  10.472 -}
  10.473 -
  10.474 -TEST(LinkedList_LowLevel, cx_linked_list_remove) {
  10.475 -    auto testdata = create_nodes_test_data({2, 4, 6});
  10.476 -    auto begin = reinterpret_cast<void *>(testdata.begin);
  10.477 -    auto first = testdata.begin;
  10.478 -    auto second = first->next;
  10.479 -    auto third = second->next;
  10.480 -    auto end = reinterpret_cast<void *>(third);
  10.481 -
  10.482 -    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, second);
  10.483 -    EXPECT_EQ(begin, first);
  10.484 -    EXPECT_EQ(end, third);
  10.485 -    EXPECT_EQ(first->prev, nullptr);
  10.486 -    EXPECT_EQ(first->next, third);
  10.487 -    EXPECT_EQ(third->prev, first);
  10.488 -    EXPECT_EQ(third->next, nullptr);
  10.489 -
  10.490 -    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, third);
  10.491 -    EXPECT_EQ(begin, first);
  10.492 -    EXPECT_EQ(end, first);
  10.493 -    EXPECT_EQ(first->prev, nullptr);
  10.494 -    EXPECT_EQ(first->next, nullptr);
  10.495 -
  10.496 -    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, first);
  10.497 -    EXPECT_EQ(begin, nullptr);
  10.498 -    EXPECT_EQ(end, nullptr);
  10.499 -}
  10.500 -
  10.501 -TEST(LinkedList_LowLevel, cx_linked_list_size) {
  10.502 -    EXPECT_EQ(cx_linked_list_size(nullptr, loc_next), 0);
  10.503 -
  10.504 -    {
  10.505 -        auto testdata = create_nodes_test_data(5);
  10.506 -        EXPECT_EQ(cx_linked_list_size(testdata.begin, loc_next), 5);
  10.507 -    }
  10.508 -
  10.509 -    {
  10.510 -        auto testdata = create_nodes_test_data(13);
  10.511 -        EXPECT_EQ(cx_linked_list_size(testdata.begin, loc_next), 13);
  10.512 -    }
  10.513 -}
  10.514 -
  10.515 -TEST(LinkedList_LowLevel, cx_linked_list_sort) {
  10.516 -    int_test_data<1500> testdata;
  10.517 -    std::array<int, 1500> sorted{};
  10.518 -    std::partial_sort_copy(testdata.data.begin(), testdata.data.end(), sorted.begin(), sorted.end());
  10.519 -
  10.520 -    auto scrambled = create_nodes_test_data(testdata.data.begin(), testdata.data.end());
  10.521 -    void *begin = scrambled.begin;
  10.522 -    void *end = cx_linked_list_last(begin, loc_next);
  10.523 -
  10.524 -    cx_linked_list_sort(&begin, &end, loc_prev, loc_next, loc_data, cx_cmp_int);
  10.525 -
  10.526 -    node *check = reinterpret_cast<node *>(begin);
  10.527 -    node *check_last = nullptr;
  10.528 -    cx_for_n (i, sorted.size()) {
  10.529 -        EXPECT_EQ(check->data, sorted[i]);
  10.530 -        EXPECT_EQ(check->prev, check_last);
  10.531 -        if (i < sorted.size() - 1) {
  10.532 -            ASSERT_NE(check->next, nullptr);
  10.533 -        }
  10.534 -        check_last = check;
  10.535 -        check = check->next;
  10.536 -    }
  10.537 -    EXPECT_EQ(check, nullptr);
  10.538 -    EXPECT_EQ(end, check_last);
  10.539 -}
  10.540 -
  10.541 -TEST(LinkedList_LowLevel, cx_linked_list_reverse) {
  10.542 -    auto testdata = create_nodes_test_data({2, 4, 6, 8});
  10.543 -    auto expected = create_nodes_test_data({8, 6, 4, 2});
  10.544 -
  10.545 -    auto begin = reinterpret_cast<void *>(testdata.begin);
  10.546 -    auto end = cx_linked_list_last(begin, loc_next);
  10.547 -    auto orig_begin = begin, orig_end = end;
  10.548 -
  10.549 -    cx_linked_list_reverse(&begin, &end, loc_prev, loc_next);
  10.550 -    EXPECT_EQ(end, orig_begin);
  10.551 -    EXPECT_EQ(begin, orig_end);
  10.552 -    EXPECT_EQ(cx_linked_list_compare(begin, expected.begin, loc_next, loc_data, cx_cmp_int), 0);
  10.553 -}
  10.554 -
  10.555 -class HighLevelTest : public ::testing::Test {
  10.556 -    mutable std::unordered_set<CxList *> lists;
  10.557 -protected:
  10.558 -    CxTestingAllocator testingAllocator;
  10.559 -
  10.560 -    void TearDown() override {
  10.561 -        for (auto &&l: lists) cxListDestroy(l);
  10.562 -        EXPECT_TRUE(testingAllocator.verify());
  10.563 -    }
  10.564 -
  10.565 -    static constexpr size_t testdata_len = 250;
  10.566 -    int_test_data<testdata_len> testdata;
  10.567 -
  10.568 -    auto autofree(CxList *list) const -> CxList * {
  10.569 -        if (list != nullptr) lists.insert(list);
  10.570 -        return list;
  10.571 -    }
  10.572 -
  10.573 -    auto linkedListFromTestData() const -> CxList * {
  10.574 -        auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  10.575 -        cxListAddArray(list, testdata.data.data(), testdata_len);
  10.576 -        return list;
  10.577 -    }
  10.578 -
  10.579 -    auto pointerLinkedListFromTestData() const -> CxList * {
  10.580 -        auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  10.581 -        cxListStorePointers(list);
  10.582 -        // note: cannot use cxListAddArray() because we don't have a list of pointers
  10.583 -        cx_for_n(i, testdata_len) cxListAdd(list, &testdata.data[i]);
  10.584 -        return list;
  10.585 -    }
  10.586 -
  10.587 -    auto arrayListFromTestData() const -> CxList * {
  10.588 -        auto list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), testdata_len));
  10.589 -        cxListAddArray(list, testdata.data.data(), testdata_len);
  10.590 -        return list;
  10.591 -    }
  10.592 -
  10.593 -    void verifyCreate(CxList *list) const {
  10.594 -        EXPECT_EQ(list->content_destructor_type, CX_DESTRUCTOR_NONE);
  10.595 -        EXPECT_EQ(list->size, 0);
  10.596 -        EXPECT_EQ(list->allocator, &testingAllocator);
  10.597 -        EXPECT_EQ(list->cmpfunc, cx_cmp_int);
  10.598 -    }
  10.599 -
  10.600 -    void verifyAdd(
  10.601 -            CxList *list,
  10.602 -            bool as_pointer
  10.603 -    ) {
  10.604 -        auto len = testdata_len;
  10.605 -        cx_for_n (i, len) EXPECT_EQ(cxListAdd(list, &testdata.data[i]), 0);
  10.606 -        EXPECT_EQ(list->size, len);
  10.607 -        EXPECT_GE(list->capacity, list->size);
  10.608 -        cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  10.609 -        cx_for_n (i, len) ++testdata.data[i];
  10.610 -        if (as_pointer) {
  10.611 -            cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  10.612 -        } else {
  10.613 -            cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i] - 1);
  10.614 -        }
  10.615 -    }
  10.616 -
  10.617 -    static void verifyInsert(CxList *list) {
  10.618 -        int a = 5, b = 47, c = 13, d = 42;
  10.619 -
  10.620 -        EXPECT_NE(cxListInsert(list, 1, &a), 0);
  10.621 -        EXPECT_EQ(list->size, 0);
  10.622 -        EXPECT_EQ(cxListInsert(list, 0, &a), 0);
  10.623 -        EXPECT_EQ(list->size, 1);
  10.624 -        EXPECT_EQ(cxListInsert(list, 0, &b), 0);
  10.625 -        EXPECT_EQ(list->size, 2);
  10.626 -        EXPECT_EQ(cxListInsert(list, 1, &c), 0);
  10.627 -        EXPECT_EQ(list->size, 3);
  10.628 -        EXPECT_EQ(cxListInsert(list, 3, &d), 0);
  10.629 -
  10.630 -        ASSERT_EQ(list->size, 4);
  10.631 -        EXPECT_GE(list->capacity, list->size);
  10.632 -
  10.633 -        EXPECT_EQ(*(int *) cxListAt(list, 0), 47);
  10.634 -        EXPECT_EQ(*(int *) cxListAt(list, 1), 13);
  10.635 -        EXPECT_EQ(*(int *) cxListAt(list, 2), 5);
  10.636 -        EXPECT_EQ(*(int *) cxListAt(list, 3), 42);
  10.637 -    }
  10.638 -
  10.639 -    static void verifyInsertArray(
  10.640 -            CxList *list,
  10.641 -            bool pointers = false
  10.642 -    ) {
  10.643 -        int a[5] = {5, 47, 11, 13, 42};
  10.644 -        int b[5] = {9, 18, 72, 50, 7};
  10.645 -        int *aptr[5];
  10.646 -        int *bptr[5];
  10.647 -        cx_for_n(i, 5) {
  10.648 -            aptr[i] = &a[i];
  10.649 -            bptr[i] = &b[i];
  10.650 -        }
  10.651 -
  10.652 -        size_t inserted;
  10.653 -
  10.654 -        if (pointers) {
  10.655 -            inserted = cxListInsertArray(list, 0, aptr, 5);
  10.656 -        } else {
  10.657 -            inserted = cxListInsertArray(list, 0, a, 5);
  10.658 -        }
  10.659 -        EXPECT_EQ(inserted, 5);
  10.660 -        EXPECT_EQ(*(int *) cxListAt(list, 0), 5);
  10.661 -        EXPECT_EQ(*(int *) cxListAt(list, 1), 47);
  10.662 -        EXPECT_EQ(*(int *) cxListAt(list, 2), 11);
  10.663 -        EXPECT_EQ(*(int *) cxListAt(list, 3), 13);
  10.664 -        EXPECT_EQ(*(int *) cxListAt(list, 4), 42);
  10.665 -        if (pointers) {
  10.666 -            inserted = cxListInsertArray(list, 3, bptr, 5);
  10.667 -        } else {
  10.668 -            inserted = cxListInsertArray(list, 3, b, 5);
  10.669 -        }
  10.670 -        EXPECT_EQ(inserted, 5);
  10.671 -        EXPECT_EQ(*(int *) cxListAt(list, 0), 5);
  10.672 -        EXPECT_EQ(*(int *) cxListAt(list, 1), 47);
  10.673 -        EXPECT_EQ(*(int *) cxListAt(list, 2), 11);
  10.674 -        EXPECT_EQ(*(int *) cxListAt(list, 3), 9);
  10.675 -        EXPECT_EQ(*(int *) cxListAt(list, 4), 18);
  10.676 -        EXPECT_EQ(*(int *) cxListAt(list, 5), 72);
  10.677 -        EXPECT_EQ(*(int *) cxListAt(list, 6), 50);
  10.678 -        EXPECT_EQ(*(int *) cxListAt(list, 7), 7);
  10.679 -        EXPECT_EQ(*(int *) cxListAt(list, 8), 13);
  10.680 -        EXPECT_EQ(*(int *) cxListAt(list, 9), 42);
  10.681 -    }
  10.682 -
  10.683 -    void verifyRemove(CxList *list) const {
  10.684 -        EXPECT_EQ(cxListRemove(list, 2), 0);
  10.685 -        EXPECT_EQ(cxListRemove(list, 4), 0);
  10.686 -        EXPECT_EQ(list->size, testdata_len - 2);
  10.687 -        EXPECT_GE(list->capacity, list->size);
  10.688 -        EXPECT_EQ(*(int *) cxListAt(list, 0), testdata.data[0]);
  10.689 -        EXPECT_EQ(*(int *) cxListAt(list, 1), testdata.data[1]);
  10.690 -        EXPECT_EQ(*(int *) cxListAt(list, 2), testdata.data[3]);
  10.691 -        EXPECT_EQ(*(int *) cxListAt(list, 3), testdata.data[4]);
  10.692 -        EXPECT_EQ(*(int *) cxListAt(list, 4), testdata.data[6]);
  10.693 -
  10.694 -        EXPECT_EQ(cxListRemove(list, 0), 0);
  10.695 -        EXPECT_EQ(list->size, testdata_len - 3);
  10.696 -        EXPECT_GE(list->capacity, list->size);
  10.697 -        EXPECT_EQ(*(int *) cxListAt(list, 0), testdata.data[1]);
  10.698 -        EXPECT_EQ(*(int *) cxListAt(list, 1), testdata.data[3]);
  10.699 -
  10.700 -        EXPECT_NE(cxListRemove(list, testdata_len), 0);
  10.701 -    }
  10.702 -
  10.703 -    void verifyAt(CxList *list) const {
  10.704 -        auto len = testdata_len;
  10.705 -        EXPECT_EQ(list->size, len);
  10.706 -        cx_for_n (i, len) {
  10.707 -            EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  10.708 -        }
  10.709 -        EXPECT_EQ(cxListAt(list, list->size), nullptr);
  10.710 -    }
  10.711 -
  10.712 -    void verifyFind(CxList *list) const {
  10.713 -        cx_for_n (attempt, 25) {
  10.714 -            size_t exp = rand() % testdata_len; // NOLINT(cert-msc50-cpp)
  10.715 -            int val = testdata.data[exp];
  10.716 -            // randomly picked number could occur earlier in list - find first position
  10.717 -            cx_for_n (i, exp) {
  10.718 -                if (testdata.data[i] == val) {
  10.719 -                    exp = i;
  10.720 -                    break;
  10.721 -                }
  10.722 -            }
  10.723 -            EXPECT_EQ(cxListFind(list, &val), exp);
  10.724 -        }
  10.725 -    }
  10.726 -
  10.727 -    void verifySort(CxList *list) const {
  10.728 -        std::array<int, testdata_len> expected{};
  10.729 -        std::partial_sort_copy(testdata.data.begin(), testdata.data.end(), expected.begin(), expected.end());
  10.730 -        cxListSort(list);
  10.731 -        cx_for_n (i, testdata_len) ASSERT_EQ(*(int *) cxListAt(list, i), expected[i]);
  10.732 -    }
  10.733 -
  10.734 -    void verifyIterator(CxList *list) const {
  10.735 -        int i = 0;
  10.736 -        auto iter = cxListBeginMut(list);
  10.737 -        cx_foreach(int*, x, iter) {
  10.738 -            ASSERT_EQ(iter.index, (size_t) (i + 1) / 2);
  10.739 -            ASSERT_EQ(*x, testdata.data[i]);
  10.740 -            if (i % 2 == 1) cxIteratorFlagRemoval(iter);
  10.741 -            i++;
  10.742 -        }
  10.743 -        auto len = testdata_len;
  10.744 -        EXPECT_EQ(i, len);
  10.745 -        ASSERT_EQ(list->size, len / 2);
  10.746 -        cx_for_n(j, len / 2) ASSERT_EQ(*(int *) cxListAt(list, j), testdata.data[j * 2]);
  10.747 -    }
  10.748 -
  10.749 -    static void verifyInsertViaIterator(CxList *list) {
  10.750 -        int newdata[] = {10, 20, 30, 40, 50};
  10.751 -
  10.752 -        auto iter = cxListMutIterator(list, 2);
  10.753 -        EXPECT_TRUE(cxIteratorValid(iter));
  10.754 -        EXPECT_EQ(iter.index, 2);
  10.755 -        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  10.756 -        cxListInsertAfter(&iter, &newdata[0]);
  10.757 -        EXPECT_TRUE(cxIteratorValid(iter));
  10.758 -        EXPECT_EQ(iter.index, 2);
  10.759 -        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  10.760 -        cxListInsertBefore(&iter, &newdata[1]);
  10.761 -        EXPECT_TRUE(cxIteratorValid(iter));
  10.762 -        EXPECT_EQ(iter.index, 3);
  10.763 -        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  10.764 -
  10.765 -        iter = cxListBeginMut(list);
  10.766 -        cxListInsertBefore(&iter, &newdata[2]);
  10.767 -        EXPECT_TRUE(cxIteratorValid(iter));
  10.768 -        EXPECT_EQ(iter.index, 1);
  10.769 -        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 0);
  10.770 -        iter = cxListMutIterator(list, list->size);
  10.771 -        cxListInsertBefore(&iter, &newdata[3]);
  10.772 -        EXPECT_FALSE(cxIteratorValid(iter));
  10.773 -        EXPECT_EQ(iter.index, 9);
  10.774 -        iter = cxListMutIterator(list, list->size);
  10.775 -        cxListInsertAfter(&iter, &newdata[4]);
  10.776 -        EXPECT_FALSE(cxIteratorValid(iter));
  10.777 -        EXPECT_EQ(iter.index, 10);
  10.778 -
  10.779 -        int expdata[] = {30, 0, 1, 20, 2, 10, 3, 4, 40, 50};
  10.780 -        cx_for_n (j, 10) EXPECT_EQ(*(int *) cxListAt(list, j), expdata[j]);
  10.781 -    }
  10.782 -
  10.783 -    void verifyReverse(CxList *list) const {
  10.784 -        cxListReverse(list);
  10.785 -        cx_for_n(i, testdata_len) {
  10.786 -            ASSERT_EQ(*(int *) cxListAt(list, i), testdata.data[testdata_len - 1 - i]);
  10.787 -        }
  10.788 -    }
  10.789 -
  10.790 -    static void verifyCompare(
  10.791 -            CxList *left,
  10.792 -            CxList *right
  10.793 -    ) {
  10.794 -        EXPECT_EQ(cxListCompare(left, right), 0);
  10.795 -        int x = 42;
  10.796 -        cxListAdd(left, &x);
  10.797 -        ASSERT_GT(left->size, right->size);
  10.798 -        EXPECT_GT(cxListCompare(left, right), 0);
  10.799 -        EXPECT_LT(cxListCompare(right, left), 0);
  10.800 -        cxListAdd(right, &x);
  10.801 -        ASSERT_EQ(left->size, right->size);
  10.802 -        EXPECT_EQ(cxListCompare(left, right), 0);
  10.803 -        int a = 5, b = 10;
  10.804 -        cxListInsert(left, 15, &a);
  10.805 -        cxListInsert(right, 15, &b);
  10.806 -        ASSERT_EQ(left->size, right->size);
  10.807 -        EXPECT_LT(cxListCompare(left, right), 0);
  10.808 -        EXPECT_GT(cxListCompare(right, left), 0);
  10.809 -        *(int *) cxListAt(left, 15) = 10;
  10.810 -        EXPECT_EQ(cxListCompare(left, right), 0);
  10.811 -    }
  10.812 -};
  10.813 -
  10.814 -class LinkedList : public HighLevelTest {
  10.815 -};
  10.816 -
  10.817 -class PointerLinkedList : public HighLevelTest {
  10.818 -};
  10.819 -
  10.820 -class ArrayList : public HighLevelTest {
  10.821 -};
  10.822 -
  10.823 -TEST_F(PointerLinkedList, cxListStorePointers) {
  10.824 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, 47));
  10.825 -    EXPECT_FALSE(cxListIsStoringPointers(list));
  10.826 -    cxListStorePointers(list);
  10.827 -    EXPECT_EQ(list->itemsize, sizeof(void *));
  10.828 -    EXPECT_NE(list->cl, nullptr);
  10.829 -    EXPECT_NE(list->climpl, nullptr);
  10.830 -    EXPECT_TRUE(cxListIsStoringPointers(list));
  10.831 -    cxListStoreObjects(list);
  10.832 -    EXPECT_NE(list->cl, nullptr);
  10.833 -    EXPECT_EQ(list->climpl, nullptr);
  10.834 -    EXPECT_FALSE(cxListIsStoringPointers(list));
  10.835 -}
  10.836 -
  10.837 -TEST_F(LinkedList, cxLinkedListCreate) {
  10.838 -    CxList *list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  10.839 -    ASSERT_NE(list, nullptr);
  10.840 -    EXPECT_EQ(list->itemsize, sizeof(int));
  10.841 -    EXPECT_EQ(list->capacity, (size_t) -1);
  10.842 -    verifyCreate(list);
  10.843 -}
  10.844 -
  10.845 -TEST_F(ArrayList, cxArrayListCreate) {
  10.846 -    CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8));
  10.847 -    ASSERT_NE(list, nullptr);
  10.848 -    EXPECT_EQ(list->itemsize, sizeof(int));
  10.849 -    EXPECT_EQ(list->capacity, 8);
  10.850 -    verifyCreate(list);
  10.851 -}
  10.852 -
  10.853 -TEST_F(LinkedList, cxListAdd) {
  10.854 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  10.855 -    verifyAdd(list, false);
  10.856 -}
  10.857 -
  10.858 -TEST_F(PointerLinkedList, cxListAdd) {
  10.859 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  10.860 -    cxListStorePointers(list);
  10.861 -    verifyAdd(list, true);
  10.862 -}
  10.863 -
  10.864 -TEST_F(ArrayList, cxListAdd) {
  10.865 -    auto list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8));
  10.866 -    verifyAdd(list, false);
  10.867 -}
  10.868 -
  10.869 -TEST_F(LinkedList, cxListInsert) {
  10.870 -    verifyInsert(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  10.871 -}
  10.872 -
  10.873 -TEST_F(PointerLinkedList, cxListInsert) {
  10.874 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  10.875 -    cxListStorePointers(list);
  10.876 -    verifyInsert(list);
  10.877 -}
  10.878 -
  10.879 -TEST_F(ArrayList, cxListInsert) {
  10.880 -    verifyInsert(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 2)));
  10.881 -}
  10.882 -
  10.883 -TEST_F(LinkedList, cxListInsertArray) {
  10.884 -    verifyInsertArray(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  10.885 -}
  10.886 -
  10.887 -TEST_F(PointerLinkedList, cxListInsertArray) {
  10.888 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  10.889 -    cxListStorePointers(list);
  10.890 -    verifyInsertArray(list, true);
  10.891 -}
  10.892 -
  10.893 -TEST_F(ArrayList, cxListInsertArray) {
  10.894 -    verifyInsertArray(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 4)));
  10.895 -}
  10.896 -
  10.897 -TEST_F(LinkedList, cxListRemove) {
  10.898 -    verifyRemove(linkedListFromTestData());
  10.899 -}
  10.900 -
  10.901 -TEST_F(PointerLinkedList, cxListRemove) {
  10.902 -    verifyRemove(pointerLinkedListFromTestData());
  10.903 -}
  10.904 -
  10.905 -TEST_F(ArrayList, cxListRemove) {
  10.906 -    verifyRemove(arrayListFromTestData());
  10.907 -}
  10.908 -
  10.909 -TEST_F(LinkedList, cxListAt) {
  10.910 -    verifyAt(linkedListFromTestData());
  10.911 -}
  10.912 -
  10.913 -TEST_F(PointerLinkedList, cxListAt) {
  10.914 -    verifyAt(pointerLinkedListFromTestData());
  10.915 -}
  10.916 -
  10.917 -TEST_F(ArrayList, cxListAt) {
  10.918 -    verifyAt(arrayListFromTestData());
  10.919 -}
  10.920 -
  10.921 -TEST_F(LinkedList, cxListFind) {
  10.922 -    verifyFind(linkedListFromTestData());
  10.923 -}
  10.924 -
  10.925 -TEST_F(PointerLinkedList, cxListFind) {
  10.926 -    verifyFind(pointerLinkedListFromTestData());
  10.927 -}
  10.928 -
  10.929 -TEST_F(ArrayList, cxListFind) {
  10.930 -    verifyFind(arrayListFromTestData());
  10.931 -}
  10.932 -
  10.933 -TEST_F(LinkedList, cxListSort) {
  10.934 -    verifySort(linkedListFromTestData());
  10.935 -}
  10.936 -
  10.937 -TEST_F(PointerLinkedList, cxListSort) {
  10.938 -    verifySort(pointerLinkedListFromTestData());
  10.939 -}
  10.940 -
  10.941 -TEST_F(ArrayList, cxListSort) {
  10.942 -    verifySort(arrayListFromTestData());
  10.943 -}
  10.944 -
  10.945 -TEST_F(LinkedList, Iterator) {
  10.946 -    verifyIterator(linkedListFromTestData());
  10.947 -}
  10.948 -
  10.949 -TEST_F(PointerLinkedList, Iterator) {
  10.950 -    verifyIterator(pointerLinkedListFromTestData());
  10.951 -}
  10.952 -
  10.953 -TEST_F(ArrayList, Iterator) {
  10.954 -    verifyIterator(arrayListFromTestData());
  10.955 -}
  10.956 -
  10.957 -TEST_F(LinkedList, InsertViaIterator) {
  10.958 -    int fivenums[] = {0, 1, 2, 3, 4, 5};
  10.959 -    CxList *list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  10.960 -    cxListAddArray(list, fivenums, 5);
  10.961 -    verifyInsertViaIterator(list);
  10.962 -}
  10.963 -
  10.964 -TEST_F(PointerLinkedList, InsertViaIterator) {
  10.965 -    int fivenums[] = {0, 1, 2, 3, 4, 5};
  10.966 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  10.967 -    cxListStorePointers(list);
  10.968 -    // note: cannot use cxListAddArray() because we don't have a list of pointers
  10.969 -    cx_for_n(i, 5) cxListAdd(list, &fivenums[i]);
  10.970 -    verifyInsertViaIterator(list);
  10.971 -}
  10.972 -
  10.973 -TEST_F(ArrayList, InsertViaIterator) {
  10.974 -    int fivenums[] = {0, 1, 2, 3, 4, 5};
  10.975 -    CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 4));
  10.976 -    cxListAddArray(list, fivenums, 5);
  10.977 -    verifyInsertViaIterator(list);
  10.978 -}
  10.979 -
  10.980 -TEST_F(LinkedList, cxListReverse) {
  10.981 -    verifyReverse(linkedListFromTestData());
  10.982 -}
  10.983 -
  10.984 -TEST_F(PointerLinkedList, cxListReverse) {
  10.985 -    verifyReverse(pointerLinkedListFromTestData());
  10.986 -}
  10.987 -
  10.988 -TEST_F(ArrayList, cxListReverse) {
  10.989 -    verifyReverse(arrayListFromTestData());
  10.990 -}
  10.991 -
  10.992 -TEST_F(LinkedList, cxListCompare) {
  10.993 -    auto left = linkedListFromTestData();
  10.994 -    auto right = linkedListFromTestData();
  10.995 -    verifyCompare(left, right);
  10.996 -}
  10.997 -
  10.998 -TEST_F(LinkedList, cxListCompareWithPtrList) {
  10.999 -    auto left = linkedListFromTestData();
 10.1000 -    auto right = pointerLinkedListFromTestData();
 10.1001 -    verifyCompare(left, right);
 10.1002 -}
 10.1003 -
 10.1004 -TEST_F(LinkedList, cxListCompareWithArrayList) {
 10.1005 -    auto left = linkedListFromTestData();
 10.1006 -    auto right = arrayListFromTestData();
 10.1007 -    verifyCompare(left, right);
 10.1008 -}
 10.1009 -
 10.1010 -TEST_F(PointerLinkedList, cxListCompare) {
 10.1011 -    auto left = pointerLinkedListFromTestData();
 10.1012 -    auto right = pointerLinkedListFromTestData();
 10.1013 -    verifyCompare(left, right);
 10.1014 -}
 10.1015 -
 10.1016 -TEST_F(PointerLinkedList, cxListCompareWithNormalList) {
 10.1017 -    auto left = pointerLinkedListFromTestData();
 10.1018 -    auto right = linkedListFromTestData();
 10.1019 -    verifyCompare(left, right);
 10.1020 -}
 10.1021 -
 10.1022 -TEST_F(PointerLinkedList, cxListCompareWithArrayList) {
 10.1023 -    auto left = pointerLinkedListFromTestData();
 10.1024 -    auto right = arrayListFromTestData();
 10.1025 -    verifyCompare(left, right);
 10.1026 -}
 10.1027 -
 10.1028 -TEST_F(ArrayList, cxListCompare) {
 10.1029 -    auto left = arrayListFromTestData();
 10.1030 -    auto right = arrayListFromTestData();
 10.1031 -    verifyCompare(left, right);
 10.1032 -}
 10.1033 -
 10.1034 -TEST_F(ArrayList, cxListCompareWithPtrList) {
 10.1035 -    auto left = arrayListFromTestData();
 10.1036 -    auto right = pointerLinkedListFromTestData();
 10.1037 -    verifyCompare(left, right);
 10.1038 -}
 10.1039 -
 10.1040 -TEST_F(ArrayList, cxListCompareWithNormalList) {
 10.1041 -    auto left = arrayListFromTestData();
 10.1042 -    auto right = linkedListFromTestData();
 10.1043 -    verifyCompare(left, right);
 10.1044 -}
 10.1045 -
 10.1046 -TEST_F(PointerLinkedList, NoDestructor) {
 10.1047 -    void *item = cxMalloc(&testingAllocator, sizeof(int));
 10.1048 -    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 10.1049 -    cxListStorePointers(list);
 10.1050 -    cxListAdd(list, item);
 10.1051 -    ASSERT_FALSE(testingAllocator.verify());
 10.1052 -    cxListDestroy(list);
 10.1053 -    EXPECT_FALSE(testingAllocator.verify());
 10.1054 -    cxFree(&testingAllocator, item);
 10.1055 -    EXPECT_TRUE(testingAllocator.verify());
 10.1056 -}
 10.1057 -
 10.1058 -TEST_F(PointerLinkedList, SimpleDestructor) {
 10.1059 -    int item = 0;
 10.1060 -    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 10.1061 -    cxListStorePointers(list);
 10.1062 -    list->content_destructor_type = CX_DESTRUCTOR_SIMPLE;
 10.1063 -    list->simple_destructor = [](void *elem) { *(int *) elem = 42; };
 10.1064 -    cxListAdd(list, &item);
 10.1065 -    cxListDestroy(list);
 10.1066 -    EXPECT_EQ(item, 42);
 10.1067 -}
 10.1068 -
 10.1069 -TEST_F(PointerLinkedList, AdvancedDestructor) {
 10.1070 -    void *item = cxMalloc(&testingAllocator, sizeof(int));
 10.1071 -    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 10.1072 -    cxListStorePointers(list);
 10.1073 -    list->content_destructor_type = CX_DESTRUCTOR_ADVANCED;
 10.1074 -    list->advanced_destructor.data = &testingAllocator;
 10.1075 -    list->advanced_destructor.func = (cx_destructor_func2) cxFree;
 10.1076 -    cxListAdd(list, item);
 10.1077 -    ASSERT_FALSE(testingAllocator.verify());
 10.1078 -    cxListDestroy(list);
 10.1079 -    EXPECT_TRUE(testingAllocator.verify());
 10.1080 -}
    11.1 --- a/test/test_map.cpp	Tue Feb 07 21:53:06 2023 +0100
    11.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.3 @@ -1,272 +0,0 @@
    11.4 -/*
    11.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    11.6 - *
    11.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    11.8 - *
    11.9 - * Redistribution and use in source and binary forms, with or without
   11.10 - * modification, are permitted provided that the following conditions are met:
   11.11 - *
   11.12 - *   1. Redistributions of source code must retain the above copyright
   11.13 - *      notice, this list of conditions and the following disclaimer.
   11.14 - *
   11.15 - *   2. Redistributions in binary form must reproduce the above copyright
   11.16 - *      notice, this list of conditions and the following disclaimer in the
   11.17 - *      documentation and/or other materials provided with the distribution.
   11.18 - *
   11.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   11.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   11.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   11.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   11.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   11.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   11.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   11.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   11.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   11.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   11.29 - * POSSIBILITY OF SUCH DAMAGE.
   11.30 - */
   11.31 -
   11.32 -#include "cx/hash_map.h"
   11.33 -#include "cx/utils.h"
   11.34 -#include "util_allocator.h"
   11.35 -
   11.36 -#include <gtest/gtest.h>
   11.37 -#include <unordered_map>
   11.38 -#include <unordered_set>
   11.39 -
   11.40 -struct map_operation {
   11.41 -    enum {
   11.42 -        put, rm
   11.43 -    } op;
   11.44 -    char const *key;
   11.45 -    char const *value;
   11.46 -};
   11.47 -
   11.48 -auto generate_map_operations() -> std::vector<map_operation> {
   11.49 -    return {
   11.50 -            {map_operation::put, "key 1",          "test"},
   11.51 -            {map_operation::put, "key 2",          "blub"},
   11.52 -            {map_operation::put, "key 3",          "hallo"},
   11.53 -            {map_operation::put, "key 2",          "foobar"},
   11.54 -            {map_operation::put, "key 4",          "value 4"},
   11.55 -            {map_operation::put, "key 5",          "value 5"},
   11.56 -            {map_operation::put, "key 6",          "value 6"},
   11.57 -            {map_operation::rm,  "key 4",          nullptr},
   11.58 -            {map_operation::put, "key 7",          "value 7"},
   11.59 -            {map_operation::put, "key 8",          "value 8"},
   11.60 -            {map_operation::rm,  "does not exist", nullptr},
   11.61 -            {map_operation::put, "key 9",          "value 9"},
   11.62 -            {map_operation::put, "key 6",          "other value"},
   11.63 -            {map_operation::put, "key 7",          "something else"},
   11.64 -            {map_operation::rm,  "key 8",          nullptr},
   11.65 -            {map_operation::rm,  "key 2",          nullptr},
   11.66 -            {map_operation::put, "key 8",          "new value"},
   11.67 -    };
   11.68 -}
   11.69 -
   11.70 -static void verify_map_contents(
   11.71 -        CxMap *map,
   11.72 -        std::unordered_map<std::string, std::string> const &refmap
   11.73 -) {
   11.74 -    // verify key iterator
   11.75 -    {
   11.76 -        auto keyiter = cxMapIteratorKeys(map);
   11.77 -        std::unordered_set<std::string> keys;
   11.78 -        cx_foreach(CxHashKey*, elem, keyiter) {
   11.79 -            keys.insert(std::string(elem->data.cstr, elem->len));
   11.80 -        }
   11.81 -        EXPECT_EQ(keyiter.index, map->size);
   11.82 -        ASSERT_EQ(keys.size(), map->size);
   11.83 -        for (auto &&k: keys) {
   11.84 -            EXPECT_NE(refmap.find(k), refmap.end());
   11.85 -        }
   11.86 -    }
   11.87 -
   11.88 -    // verify value iterator
   11.89 -    {
   11.90 -        auto valiter = cxMapIteratorValues(map);
   11.91 -        std::unordered_set<std::string> values; // we use that the values in our test data are unique strings
   11.92 -        cx_foreach(char const*, elem, valiter) {
   11.93 -            values.insert(std::string(elem));
   11.94 -        }
   11.95 -        EXPECT_EQ(valiter.index, map->size);
   11.96 -        ASSERT_EQ(values.size(), map->size);
   11.97 -        for (auto &&v: values) {
   11.98 -            EXPECT_NE(std::find_if(refmap.begin(), refmap.end(),
   11.99 -                                   [v](auto const &e) { return e.second == v; }), refmap.end());
  11.100 -        }
  11.101 -    }
  11.102 -
  11.103 -    // verify pair iterator
  11.104 -    {
  11.105 -        auto pairiter = cxMapIterator(map);
  11.106 -        std::unordered_map<std::string, std::string> pairs;
  11.107 -        cx_foreach(CxMapEntry*, entry, pairiter) {
  11.108 -            pairs[std::string(entry->key->data.cstr, entry->key->len)] = std::string((char *) entry->value);
  11.109 -        }
  11.110 -        EXPECT_EQ(pairiter.index, map->size);
  11.111 -        ASSERT_EQ(pairs.size(), refmap.size());
  11.112 -        for (auto &&p: pairs) {
  11.113 -            ASSERT_EQ(p.second, refmap.at(p.first));
  11.114 -        }
  11.115 -    }
  11.116 -}
  11.117 -
  11.118 -TEST(CxHashMap, Create) {
  11.119 -    CxTestingAllocator allocator;
  11.120 -    auto map = cxHashMapCreate(&allocator, 0);
  11.121 -    auto hmap = reinterpret_cast<struct cx_hash_map_s *>(map);
  11.122 -    EXPECT_GT(hmap->bucket_count, 0);
  11.123 -    cx_for_n(i, hmap->bucket_count) {
  11.124 -        EXPECT_EQ(hmap->buckets[i], nullptr);
  11.125 -    }
  11.126 -    EXPECT_EQ(map->size, 0);
  11.127 -    EXPECT_EQ(map->allocator, &allocator);
  11.128 -
  11.129 -    cxMapDestroy(map);
  11.130 -    EXPECT_TRUE(allocator.verify());
  11.131 -}
  11.132 -
  11.133 -TEST(CxHashMap, BasicOperations) {
  11.134 -    // create the map
  11.135 -    CxTestingAllocator allocator;
  11.136 -    auto map = cxHashMapCreate(&allocator, 8);
  11.137 -
  11.138 -    // create a reference map
  11.139 -    std::unordered_map<std::string, std::string> refmap;
  11.140 -
  11.141 -    // generate operations
  11.142 -    auto ops = generate_map_operations();
  11.143 -
  11.144 -    // verify iterators for empty map
  11.145 -    verify_map_contents(map, refmap);
  11.146 -
  11.147 -    // execute operations and verify results
  11.148 -    for (auto &&op: ops) {
  11.149 -        CxHashKey key = cx_hash_key_str(op.key);
  11.150 -        key.hash = 0; // force the hash map to compute the hash
  11.151 -        if (op.op == map_operation::put) {
  11.152 -            // execute a put operation and verify that the exact value can be read back
  11.153 -            refmap[std::string(op.key)] = std::string(op.value);
  11.154 -            int result = cxMapPut(map, key, (void *) op.value);
  11.155 -            EXPECT_EQ(result, 0);
  11.156 -            auto added = cxMapGet(map, key);
  11.157 -            EXPECT_EQ(memcmp(op.value, added, strlen(op.value)), 0);
  11.158 -        } else {
  11.159 -            // execute a remove and verify that the removed element was returned (or nullptr)
  11.160 -            auto found = refmap.find(op.key);
  11.161 -            auto removed = cxMapRemove(map, key);
  11.162 -            if (found == refmap.end()) {
  11.163 -                EXPECT_EQ(removed, nullptr);
  11.164 -            } else {
  11.165 -                EXPECT_EQ(std::string((char *) removed), found->second);
  11.166 -                refmap.erase(found);
  11.167 -            }
  11.168 -        }
  11.169 -        // compare the current map state with the reference map
  11.170 -        verify_map_contents(map, refmap);
  11.171 -    }
  11.172 -
  11.173 -    // destroy the map and verify the memory (de)allocations
  11.174 -    cxMapDestroy(map);
  11.175 -    EXPECT_TRUE(allocator.verify());
  11.176 -}
  11.177 -
  11.178 -TEST(CxHashMap, RemoveViaIterator) {
  11.179 -    CxTestingAllocator allocator;
  11.180 -    auto map = cxHashMapCreate(&allocator, 4);
  11.181 -
  11.182 -    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  11.183 -    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  11.184 -    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  11.185 -    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  11.186 -    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  11.187 -    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  11.188 -
  11.189 -    auto iter = cxMapMutIterator(map);
  11.190 -    cx_foreach(CxMapEntry*, entry, iter) {
  11.191 -        if (entry->key->data.cstr[4] % 2 == 1) cxIteratorFlagRemoval(iter);
  11.192 -    }
  11.193 -    EXPECT_EQ(map->size, 3);
  11.194 -    EXPECT_EQ(iter.index, map->size);
  11.195 -
  11.196 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
  11.197 -    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
  11.198 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
  11.199 -    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 4")), nullptr);
  11.200 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 5")), nullptr);
  11.201 -    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 6")), nullptr);
  11.202 -
  11.203 -    cxMapDestroy(map);
  11.204 -    EXPECT_TRUE(allocator.verify());
  11.205 -}
  11.206 -
  11.207 -TEST(CxHashMap, RehashNotRequired) {
  11.208 -    CxTestingAllocator allocator;
  11.209 -    auto map = cxHashMapCreate(&allocator, 8);
  11.210 -
  11.211 -    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  11.212 -    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  11.213 -    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  11.214 -    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  11.215 -    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  11.216 -    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  11.217 -
  11.218 -    // 6/8 does not exceed 0.75, therefore the function should not rehash
  11.219 -    int result = cxMapRehash(map);
  11.220 -    EXPECT_EQ(result, 0);
  11.221 -    EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 8);
  11.222 -
  11.223 -    cxMapDestroy(map);
  11.224 -    EXPECT_TRUE(allocator.verify());
  11.225 -}
  11.226 -
  11.227 -TEST(CxHashMap, Rehash) {
  11.228 -    CxTestingAllocator allocator;
  11.229 -    auto map = cxHashMapCreate(&allocator, 8);
  11.230 -
  11.231 -    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  11.232 -    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  11.233 -    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  11.234 -    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  11.235 -    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  11.236 -    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  11.237 -    cxMapPut(map, cx_hash_key_str("key 7"), (void *) "val 7");
  11.238 -
  11.239 -    int result = cxMapRehash(map);
  11.240 -    EXPECT_EQ(result, 0);
  11.241 -    EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 17);
  11.242 -    EXPECT_EQ(map->size, 7);
  11.243 -
  11.244 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 1")), "val 1"), 0);
  11.245 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 2")), "val 2"), 0);
  11.246 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 3")), "val 3"), 0);
  11.247 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 4")), "val 4"), 0);
  11.248 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 5")), "val 5"), 0);
  11.249 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 6")), "val 6"), 0);
  11.250 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 7")), "val 7"), 0);
  11.251 -
  11.252 -    cxMapDestroy(map);
  11.253 -    EXPECT_TRUE(allocator.verify());
  11.254 -}
  11.255 -
  11.256 -TEST(CxHashMap, Clear) {
  11.257 -    CxTestingAllocator allocator;
  11.258 -    auto map = cxHashMapCreate(&allocator, 0);
  11.259 -    
  11.260 -    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  11.261 -    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  11.262 -    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  11.263 -
  11.264 -    EXPECT_EQ(map->size, 3);
  11.265 -
  11.266 -    cxMapClear(map);
  11.267 -
  11.268 -    EXPECT_EQ(map->size, 0);
  11.269 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
  11.270 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
  11.271 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
  11.272 -
  11.273 -    cxMapDestroy(map);
  11.274 -    EXPECT_TRUE(allocator.verify());
  11.275 -}
  11.276 \ No newline at end of file
    12.1 --- a/test/test_printf.cpp	Tue Feb 07 21:53:06 2023 +0100
    12.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.3 @@ -1,248 +0,0 @@
    12.4 -/*
    12.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    12.6 - *
    12.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    12.8 - *
    12.9 - * Redistribution and use in source and binary forms, with or without
   12.10 - * modification, are permitted provided that the following conditions are met:
   12.11 - *
   12.12 - *   1. Redistributions of source code must retain the above copyright
   12.13 - *      notice, this list of conditions and the following disclaimer.
   12.14 - *
   12.15 - *   2. Redistributions in binary form must reproduce the above copyright
   12.16 - *      notice, this list of conditions and the following disclaimer in the
   12.17 - *      documentation and/or other materials provided with the distribution.
   12.18 - *
   12.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   12.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   12.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   12.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   12.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   12.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   12.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   12.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   12.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   12.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   12.29 - * POSSIBILITY OF SUCH DAMAGE.
   12.30 - */
   12.31 -
   12.32 -#include "cx/printf.h"
   12.33 -#include "cx/buffer.h"
   12.34 -
   12.35 -#include <gtest/gtest.h>
   12.36 -#include "util_allocator.h"
   12.37 -
   12.38 -class PrintfFixture : public ::testing::Test {
   12.39 -protected:
   12.40 -    std::string buf;
   12.41 -    CxTestingAllocator alloc;
   12.42 -
   12.43 -    void TearDown() override {
   12.44 -        buf.clear();
   12.45 -        ASSERT_TRUE(alloc.verify());
   12.46 -    }
   12.47 -
   12.48 -    static size_t write_func(
   12.49 -            void const *src,
   12.50 -            size_t esize,
   12.51 -            size_t ecount,
   12.52 -            void *target
   12.53 -    ) {
   12.54 -        auto str = reinterpret_cast<char const *>(src);
   12.55 -        auto buf = reinterpret_cast<std::string *>(target);
   12.56 -        EXPECT_EQ(esize, 1);
   12.57 -        EXPECT_EQ(strlen(str), ecount);
   12.58 -        *buf = str;
   12.59 -        return ecount;
   12.60 -    }
   12.61 -};
   12.62 -
   12.63 -
   12.64 -TEST_F(PrintfFixture, BPrintf) {
   12.65 -    CxBuffer buf;
   12.66 -    cxBufferInit(&buf, nullptr, 64, &alloc, 0);
   12.67 -
   12.68 -    auto r = cx_bprintf(&buf, "This %s aged %u years in a %2XSK.", "Test", 10, 0xca);
   12.69 -    EXPECT_EQ(r, 34);
   12.70 -    EXPECT_EQ(buf.size, 34);
   12.71 -    buf.space[r] = '\0';
   12.72 -    EXPECT_STREQ(buf.space, "This Test aged 10 years in a CASK.");
   12.73 -
   12.74 -    cxBufferDestroy(&buf);
   12.75 -}
   12.76 -
   12.77 -TEST_F(PrintfFixture, FPrintf) {
   12.78 -    auto h = "Hello";
   12.79 -    size_t r;
   12.80 -
   12.81 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "teststring");
   12.82 -    EXPECT_EQ(r, 10);
   12.83 -    EXPECT_EQ(buf, "teststring");
   12.84 -
   12.85 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%10s]", h);
   12.86 -    EXPECT_EQ(r, 12);
   12.87 -    EXPECT_EQ(buf, "[     Hello]");
   12.88 -
   12.89 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-10s]", h);
   12.90 -    EXPECT_EQ(r, 12);
   12.91 -    EXPECT_EQ(buf, "[Hello     ]");
   12.92 -
   12.93 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%*s]", 10, h);
   12.94 -    EXPECT_EQ(r, 12);
   12.95 -    EXPECT_EQ(buf, "[     Hello]");
   12.96 -
   12.97 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-10.*s]", 4, h);
   12.98 -    EXPECT_EQ(r, 12);
   12.99 -    EXPECT_EQ(buf, "[Hell      ]");
  12.100 -
  12.101 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-*.*s]", 10, 4, h);
  12.102 -    EXPECT_EQ(r, 12);
  12.103 -    EXPECT_EQ(buf, "[Hell      ]");
  12.104 -
  12.105 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%c", 'A');
  12.106 -    EXPECT_EQ(r, 1);
  12.107 -    EXPECT_EQ(buf, "A");
  12.108 -
  12.109 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
  12.110 -    EXPECT_EQ(r, 19);
  12.111 -    EXPECT_EQ(buf, "1 2 000003 0  +4 -4");
  12.112 -
  12.113 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%x %x %X %#x", 5, 10, 10, 6);
  12.114 -    EXPECT_EQ(r, 9);
  12.115 -    EXPECT_EQ(buf, "5 a A 0x6");
  12.116 -
  12.117 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%o %#o %#o", 10, 10, 4);
  12.118 -    EXPECT_EQ(r, 9);
  12.119 -    EXPECT_EQ(buf, "12 012 04");
  12.120 -
  12.121 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
  12.122 -    EXPECT_EQ(r, 16);
  12.123 -    EXPECT_EQ(buf, "01.50 1.50  1.50");
  12.124 -
  12.125 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "'%*c'", 5, 'x');
  12.126 -    EXPECT_EQ(r, 7);
  12.127 -    EXPECT_EQ(buf, "'    x'");
  12.128 -
  12.129 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "'%*c'", -5, 'x');
  12.130 -    EXPECT_EQ(r, 7);
  12.131 -    EXPECT_EQ(buf, "'x    '");
  12.132 -}
  12.133 -
  12.134 -TEST_F(PrintfFixture, BPrintfLargeString) {
  12.135 -    CxBuffer buf;
  12.136 -    cxBufferInit(&buf, nullptr, 64, &alloc, CX_BUFFER_AUTO_EXTEND);
  12.137 -
  12.138 -    auto aaa = std::string(512, 'a');
  12.139 -    auto bbb = std::string(512, 'b');
  12.140 -
  12.141 -    auto r = cx_bprintf(&buf, "After %s comes %s.", aaa.data(), bbb.data());
  12.142 -    EXPECT_EQ(r, 1038);
  12.143 -    EXPECT_EQ(buf.size, 1038);
  12.144 -    cxBufferPut(&buf, 0);
  12.145 -    EXPECT_EQ(buf.space, std::string("After ") + aaa + " comes " + bbb + ".");
  12.146 -
  12.147 -    cxBufferDestroy(&buf);
  12.148 -}
  12.149 -
  12.150 -TEST_F(PrintfFixture, BPrintfNoCap) {
  12.151 -    CxBuffer buf;
  12.152 -    char space[20];
  12.153 -    memset(space, 'a', 20);
  12.154 -    cxBufferInit(&buf, space, 16, &alloc, 0);
  12.155 -
  12.156 -    auto r = cx_bprintf(&buf, "Hello %s with more than %d chars.", "string", 16);
  12.157 -    EXPECT_EQ(r, 16);
  12.158 -    EXPECT_EQ(buf.size, 16);
  12.159 -    EXPECT_EQ(0, memcmp(space, "Hello string witaaaa", 20));
  12.160 -
  12.161 -    cxBufferDestroy(&buf);
  12.162 -}
  12.163 -
  12.164 -TEST_F(PrintfFixture, SPrintf) {
  12.165 -    auto h = "Hello";
  12.166 -
  12.167 -    std::vector<char *> fl;
  12.168 -    cxmutstr r;
  12.169 -
  12.170 -    r = cx_asprintf_a(&alloc, "teststring");
  12.171 -    EXPECT_EQ(r.length, 10);
  12.172 -    EXPECT_STREQ(r.ptr, "teststring");
  12.173 -    fl.push_back(r.ptr);
  12.174 -
  12.175 -    r = cx_asprintf_a(&alloc, "[%10s]", h);
  12.176 -    EXPECT_EQ(r.length, 12);
  12.177 -    EXPECT_STREQ(r.ptr, "[     Hello]");
  12.178 -    fl.push_back(r.ptr);
  12.179 -
  12.180 -    r = cx_asprintf_a(&alloc, "[%-10s]", h);
  12.181 -    EXPECT_EQ(r.length, 12);
  12.182 -    EXPECT_STREQ(r.ptr, "[Hello     ]");
  12.183 -    fl.push_back(r.ptr);
  12.184 -
  12.185 -    r = cx_asprintf_a(&alloc, "[%*s]", 10, h);
  12.186 -    EXPECT_EQ(r.length, 12);
  12.187 -    EXPECT_STREQ(r.ptr, "[     Hello]");
  12.188 -    fl.push_back(r.ptr);
  12.189 -
  12.190 -    r = cx_asprintf_a(&alloc, "[%-10.*s]", 4, h);
  12.191 -    EXPECT_EQ(r.length, 12);
  12.192 -    EXPECT_STREQ(r.ptr, "[Hell      ]");
  12.193 -    fl.push_back(r.ptr);
  12.194 -
  12.195 -    r = cx_asprintf_a(&alloc, "[%-*.*s]", 10, 4, h);
  12.196 -    EXPECT_EQ(r.length, 12);
  12.197 -    EXPECT_STREQ(r.ptr, "[Hell      ]");
  12.198 -    fl.push_back(r.ptr);
  12.199 -
  12.200 -    r = cx_asprintf_a(&alloc, "%c", 'A');
  12.201 -    EXPECT_EQ(r.length, 1);
  12.202 -    EXPECT_STREQ(r.ptr, "A");
  12.203 -    fl.push_back(r.ptr);
  12.204 -
  12.205 -    r = cx_asprintf_a(&alloc, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
  12.206 -    EXPECT_EQ(r.length, 19);
  12.207 -    EXPECT_STREQ(r.ptr, "1 2 000003 0  +4 -4");
  12.208 -    fl.push_back(r.ptr);
  12.209 -
  12.210 -    r = cx_asprintf_a(&alloc, "%x %x %X %#x", 5, 10, 10, 6);
  12.211 -    EXPECT_EQ(r.length, 9);
  12.212 -    EXPECT_STREQ(r.ptr, "5 a A 0x6");
  12.213 -    fl.push_back(r.ptr);
  12.214 -
  12.215 -    r = cx_asprintf_a(&alloc, "%o %#o %#o", 10, 10, 4);
  12.216 -    EXPECT_EQ(r.length, 9);
  12.217 -    EXPECT_STREQ(r.ptr, "12 012 04");
  12.218 -    fl.push_back(r.ptr);
  12.219 -
  12.220 -    r = cx_asprintf_a(&alloc, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
  12.221 -    EXPECT_EQ(r.length, 16);
  12.222 -    EXPECT_STREQ(r.ptr, "01.50 1.50  1.50");
  12.223 -    fl.push_back(r.ptr);
  12.224 -
  12.225 -    r = cx_asprintf_a(&alloc, "'%*c'", 5, 'x');
  12.226 -    EXPECT_EQ(r.length, 7);
  12.227 -    EXPECT_STREQ(r.ptr, "'    x'");
  12.228 -    fl.push_back(r.ptr);
  12.229 -
  12.230 -    r = cx_asprintf_a(&alloc, "'%*c'", -5, 'x');
  12.231 -    EXPECT_EQ(r.length, 7);
  12.232 -    EXPECT_STREQ(r.ptr, "'x    '");
  12.233 -    fl.push_back(r.ptr);
  12.234 -
  12.235 -    for (auto c: fl) {
  12.236 -        auto s = cx_mutstrn(c, 0);
  12.237 -        cx_strfree_a(&alloc, &s);
  12.238 -    }
  12.239 -}
  12.240 -
  12.241 -TEST_F(PrintfFixture, SPrintfLargeString) {
  12.242 -    auto aaa = std::string(512, 'a');
  12.243 -    auto bbb = std::string(512, 'b');
  12.244 -
  12.245 -    auto r = cx_asprintf_a(&alloc, "After %s comes %s.", aaa.data(), bbb.data());
  12.246 -    EXPECT_EQ(r.length, 1038);
  12.247 -    EXPECT_EQ(r.ptr, std::string("After ") + aaa + " comes " + bbb + ".");
  12.248 -    EXPECT_EQ(r.ptr[1038], '\0');
  12.249 -
  12.250 -    cx_strfree_a(&alloc, &r);
  12.251 -}
  12.252 \ No newline at end of file
    13.1 --- a/test/test_string.cpp	Tue Feb 07 21:53:06 2023 +0100
    13.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.3 @@ -1,865 +0,0 @@
    13.4 -/*
    13.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    13.6 - *
    13.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    13.8 - *
    13.9 - * Redistribution and use in source and binary forms, with or without
   13.10 - * modification, are permitted provided that the following conditions are met:
   13.11 - *
   13.12 - *   1. Redistributions of source code must retain the above copyright
   13.13 - *      notice, this list of conditions and the following disclaimer.
   13.14 - *
   13.15 - *   2. Redistributions in binary form must reproduce the above copyright
   13.16 - *      notice, this list of conditions and the following disclaimer in the
   13.17 - *      documentation and/or other materials provided with the distribution.
   13.18 - *
   13.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   13.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   13.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   13.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   13.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   13.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   13.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   13.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   13.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   13.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   13.29 - * POSSIBILITY OF SUCH DAMAGE.
   13.30 - */
   13.31 -
   13.32 -#include "cx/string.h"
   13.33 -#include "util_allocator.h"
   13.34 -
   13.35 -#include <gtest/gtest.h>
   13.36 -
   13.37 -#define EXPECT_ZERO_TERMINATED(str) EXPECT_EQ((str).ptr[(str).length], '\0')
   13.38 -
   13.39 -TEST(String, construct) {
   13.40 -    cxstring s1 = cx_str("1234");
   13.41 -    cxstring s2 = cx_strn("abcd", 2);
   13.42 -    cxmutstr s3 = cx_mutstr((char *) "1234");
   13.43 -    cxmutstr s4 = cx_mutstrn((char *) "abcd", 2);
   13.44 -
   13.45 -    EXPECT_EQ(s1.length, 4);
   13.46 -    EXPECT_EQ(s2.length, 2);
   13.47 -    EXPECT_EQ(s3.length, 4);
   13.48 -    EXPECT_EQ(s4.length, 2);
   13.49 -}
   13.50 -
   13.51 -TEST(String, strfree) {
   13.52 -    CxTestingAllocator alloc;
   13.53 -    auto test = (char *) cxMalloc(&alloc, 16);
   13.54 -    cxmutstr str = cx_mutstrn(test, 16);
   13.55 -    ASSERT_EQ(str.ptr, test);
   13.56 -    EXPECT_EQ(str.length, 16);
   13.57 -    cx_strfree_a(&alloc, &str);
   13.58 -    EXPECT_EQ(str.ptr, nullptr);
   13.59 -    EXPECT_EQ(str.length, 0);
   13.60 -    EXPECT_TRUE(alloc.verify());
   13.61 -}
   13.62 -
   13.63 -TEST(String, strdup) {
   13.64 -    cxstring str = CX_STR("test");
   13.65 -    cxmutstr dup = cx_strdup(str);
   13.66 -    ASSERT_EQ(dup.length, str.length);
   13.67 -    EXPECT_STREQ(dup.ptr, str.ptr);
   13.68 -    EXPECT_ZERO_TERMINATED(dup);
   13.69 -    cx_strfree(&dup);
   13.70 -
   13.71 -    str.length = 2;
   13.72 -    dup = cx_strdup(str);
   13.73 -    ASSERT_EQ(dup.length, str.length);
   13.74 -    EXPECT_STREQ(dup.ptr, "te");
   13.75 -    EXPECT_ZERO_TERMINATED(dup);
   13.76 -    cx_strfree(&dup);
   13.77 -}
   13.78 -
   13.79 -TEST(String, strlen) {
   13.80 -    cxstring s1 = CX_STR("1234");
   13.81 -    cxstring s2 = CX_STR(".:.:.");
   13.82 -    cxstring s3 = CX_STR("X");
   13.83 -
   13.84 -    size_t len0 = cx_strlen(0);
   13.85 -    size_t len1 = cx_strlen(1, s1);
   13.86 -    size_t len2 = cx_strlen(2, s1, s2);
   13.87 -    size_t len3 = cx_strlen(3, s1, s2, s3);
   13.88 -
   13.89 -    EXPECT_EQ(len0, 0);
   13.90 -    EXPECT_EQ(len1, 4);
   13.91 -    EXPECT_EQ(len2, 9);
   13.92 -    EXPECT_EQ(len3, 10);
   13.93 -}
   13.94 -
   13.95 -TEST(String, strsubs) {
   13.96 -    cxstring str = CX_STR("A test string");
   13.97 -
   13.98 -    cxstring sub = cx_strsubs(str, 0);
   13.99 -    EXPECT_EQ(cx_strcmp(sub, str), 0);
  13.100 -
  13.101 -    sub = cx_strsubs(str, 2);
  13.102 -    EXPECT_EQ(cx_strcmp(sub, cx_str("test string")), 0);
  13.103 -
  13.104 -    sub = cx_strsubs(str, 7);
  13.105 -    EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
  13.106 -
  13.107 -    sub = cx_strsubs(str, 15);
  13.108 -    EXPECT_EQ(cx_strcmp(sub, cx_str("")), 0);
  13.109 -
  13.110 -    sub = cx_strsubsl(str, 2, 4);
  13.111 -    EXPECT_EQ(cx_strcmp(sub, cx_str("test")), 0);
  13.112 -
  13.113 -    sub = cx_strsubsl(str, 7, 3);
  13.114 -    EXPECT_EQ(cx_strcmp(sub, cx_str("str")), 0);
  13.115 -
  13.116 -    sub = cx_strsubsl(str, 7, 20);
  13.117 -    EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
  13.118 -
  13.119 -    // just for coverage, call the _m variant
  13.120 -    auto m = cx_strsubs_m(cx_mutstrn(nullptr, 0), 0);
  13.121 -    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  13.122 -}
  13.123 -
  13.124 -TEST(String, strchr) {
  13.125 -    cxstring str = CX_STR("I will find you - and I will kill you");
  13.126 -
  13.127 -    cxstring notfound = cx_strchr(str, 'x');
  13.128 -    EXPECT_EQ(notfound.length, 0);
  13.129 -
  13.130 -    cxstring result = cx_strchr(str, 'w');
  13.131 -    EXPECT_EQ(result.length, 35);
  13.132 -    EXPECT_STREQ(result.ptr, "will find you - and I will kill you");
  13.133 -
  13.134 -    // just for coverage, call the _m variant
  13.135 -    auto m = cx_strchr_m(cx_mutstrn(nullptr, 0), 'a');
  13.136 -    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  13.137 -}
  13.138 -
  13.139 -TEST(String, strrchr) {
  13.140 -    cxstring str = CX_STR("I will find you - and I will kill you");
  13.141 -
  13.142 -    cxstring notfound = cx_strrchr(str, 'x');
  13.143 -    EXPECT_EQ(notfound.length, 0);
  13.144 -
  13.145 -    cxstring result = cx_strrchr(str, 'w');
  13.146 -    EXPECT_EQ(result.length, 13);
  13.147 -    EXPECT_STREQ(result.ptr, "will kill you");
  13.148 -
  13.149 -    // just for coverage, call the _m variant
  13.150 -    auto m = cx_strrchr_m(cx_mutstrn(nullptr, 0), 'a');
  13.151 -    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  13.152 -}
  13.153 -
  13.154 -TEST(String, strstr) {
  13.155 -    cxstring str = CX_STR("find the match in this string");
  13.156 -    cxstring longstr = CX_STR(
  13.157 -            "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl"
  13.158 -            "mnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx"
  13.159 -            "yzabcdeababababnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij"
  13.160 -            "klmnopqrstuvwxyzaababababababababrstuvwxyzabcdefghijklmnopqrstuv"
  13.161 -            "abababababababababababababababababababababababababababababababab"
  13.162 -            "abababababababababababababababababababababababababababababababab"
  13.163 -            "abababababababababababababababababababababababababababababababab"
  13.164 -            "abababababababababababababababababababababababababababababababab"
  13.165 -            "abababababababababababababababababababababababababababababababab"
  13.166 -            "abababababababababababababababababababababababababababababababab"
  13.167 -            "wxyz1234567890");
  13.168 -    cxstring longstrpattern = CX_STR(
  13.169 -            "abababababababababababababababababababababababababababababababab"
  13.170 -            "abababababababababababababababababababababababababababababababab"
  13.171 -            "abababababababababababababababababababababababababababababababab"
  13.172 -            "abababababababababababababababababababababababababababababababab"
  13.173 -            "abababababababababababababababababababababababababababababababab"
  13.174 -    );
  13.175 -    cxstring longstrresult = CX_STR(
  13.176 -            "abababababababababababababababababababababababababababababababab"
  13.177 -            "abababababababababababababababababababababababababababababababab"
  13.178 -            "abababababababababababababababababababababababababababababababab"
  13.179 -            "abababababababababababababababababababababababababababababababab"
  13.180 -            "abababababababababababababababababababababababababababababababab"
  13.181 -            "abababababababababababababababababababababababababababababababab"
  13.182 -            "wxyz1234567890"
  13.183 -    );
  13.184 -
  13.185 -    cxstring notfound = cx_strstr(str, cx_str("no match"));
  13.186 -    EXPECT_EQ(notfound.length, 0);
  13.187 -
  13.188 -    cxstring result = cx_strstr(str, cx_str("match"));
  13.189 -    EXPECT_EQ(result.length, 20);
  13.190 -    EXPECT_STREQ(result.ptr, "match in this string");
  13.191 -
  13.192 -    result = cx_strstr(str, cx_str(""));
  13.193 -    EXPECT_EQ(result.length, str.length);
  13.194 -    EXPECT_STREQ(result.ptr, str.ptr);
  13.195 -
  13.196 -    result = cx_strstr(longstr, longstrpattern);
  13.197 -    EXPECT_EQ(result.length, longstrresult.length);
  13.198 -    EXPECT_STREQ(result.ptr, longstrresult.ptr);
  13.199 -
  13.200 -    // just for coverage, call the _m variant
  13.201 -    auto mstr = cx_strdup(longstr);
  13.202 -    auto m = cx_strstr_m(mstr, longstrpattern);
  13.203 -    EXPECT_EQ(m.length, longstrresult.length);
  13.204 -    EXPECT_STREQ(m.ptr, longstrresult.ptr);
  13.205 -    cx_strfree(&mstr);
  13.206 -}
  13.207 -
  13.208 -TEST(String, strcmp) {
  13.209 -    cxstring str = CX_STR("compare this");
  13.210 -
  13.211 -    EXPECT_EQ(cx_strcmp(cx_str(""), cx_str("")), 0);
  13.212 -    EXPECT_GT(cx_strcmp(str, cx_str("")), 0);
  13.213 -    EXPECT_EQ(cx_strcmp(str, cx_str("compare this")), 0);
  13.214 -    EXPECT_NE(cx_strcmp(str, cx_str("Compare This")), 0);
  13.215 -    EXPECT_LT(cx_strcmp(str, cx_str("compare tool")), 0);
  13.216 -    EXPECT_GT(cx_strcmp(str, cx_str("compare shit")), 0);
  13.217 -    EXPECT_LT(cx_strcmp(str, cx_str("compare this not")), 0);
  13.218 -    EXPECT_GT(cx_strcmp(str, cx_str("compare")), 0);
  13.219 -}
  13.220 -
  13.221 -TEST(String, strcasecmp) {
  13.222 -    cxstring str = CX_STR("compare this");
  13.223 -
  13.224 -    EXPECT_EQ(cx_strcasecmp(cx_str(""), cx_str("")), 0);
  13.225 -    EXPECT_GT(cx_strcasecmp(str, cx_str("")), 0);
  13.226 -    EXPECT_EQ(cx_strcasecmp(str, cx_str("compare this")), 0);
  13.227 -    EXPECT_EQ(cx_strcasecmp(str, cx_str("Compare This")), 0);
  13.228 -    EXPECT_LT(cx_strcasecmp(str, cx_str("compare tool")), 0);
  13.229 -    EXPECT_GT(cx_strcasecmp(str, cx_str("compare shit")), 0);
  13.230 -    EXPECT_LT(cx_strcasecmp(str, cx_str("compare this not")), 0);
  13.231 -    EXPECT_GT(cx_strcasecmp(str, cx_str("compare")), 0);
  13.232 -}
  13.233 -
  13.234 -TEST(String, strcat) {
  13.235 -    cxstring s1 = CX_STR("12");
  13.236 -    cxstring s2 = CX_STR("34");
  13.237 -    cxstring s3 = CX_STR("56");
  13.238 -    cxstring sn = {nullptr, 0};
  13.239 -
  13.240 -    CxTestingAllocator alloc;
  13.241 -
  13.242 -    cxmutstr t1 = cx_strcat_a(&alloc, 2, s1, s2);
  13.243 -    EXPECT_EQ(cx_strcmp(cx_strcast(t1), cx_str("1234")), 0);
  13.244 -    EXPECT_ZERO_TERMINATED(t1);
  13.245 -    cx_strfree_a(&alloc, &t1);
  13.246 -
  13.247 -    cxmutstr t2 = cx_strcat_a(&alloc, 3, s1, s2, s3);
  13.248 -    EXPECT_EQ(cx_strcmp(cx_strcast(t2), cx_str("123456")), 0);
  13.249 -    EXPECT_ZERO_TERMINATED(t2);
  13.250 -    cx_strfree_a(&alloc, &t2);
  13.251 -
  13.252 -    cxmutstr t3 = cx_strcat_a(&alloc, 6, s1, sn, s2, sn, s3, sn);
  13.253 -    EXPECT_EQ(cx_strcmp(cx_strcast(t3), cx_str("123456")), 0);
  13.254 -    EXPECT_ZERO_TERMINATED(t3);
  13.255 -    cx_strfree_a(&alloc, &t3);
  13.256 -
  13.257 -    cxmutstr t4 = cx_strcat_a(&alloc, 2, sn, sn);
  13.258 -    EXPECT_EQ(cx_strcmp(cx_strcast(t4), cx_str("")), 0);
  13.259 -    EXPECT_ZERO_TERMINATED(t4);
  13.260 -    cx_strfree_a(&alloc, &t4);
  13.261 -
  13.262 -    EXPECT_TRUE(alloc.verify());
  13.263 -
  13.264 -    // use the macro
  13.265 -    cxmutstr t5 = cx_strcat(3, s3, s1, s2);
  13.266 -    EXPECT_EQ(cx_strcmp(cx_strcast(t5), cx_str("561234")), 0);
  13.267 -    EXPECT_ZERO_TERMINATED(t5);
  13.268 -    cx_strfree(&t5);
  13.269 -}
  13.270 -
  13.271 -TEST(String, strsplit) {
  13.272 -
  13.273 -    cxstring test = cx_str("this,is,a,csv,string");
  13.274 -    size_t capa = 8;
  13.275 -    cxstring list[8];
  13.276 -    size_t n;
  13.277 -
  13.278 -    // special case: empty string
  13.279 -    n = cx_strsplit(test, cx_str(""), capa, list);
  13.280 -    ASSERT_EQ(n, 1);
  13.281 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  13.282 -
  13.283 -    // no delimiter occurrence
  13.284 -    n = cx_strsplit(test, cx_str("z"), capa, list);
  13.285 -    ASSERT_EQ(n, 1);
  13.286 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  13.287 -
  13.288 -    // partially matching delimiter
  13.289 -    n = cx_strsplit(test, cx_str("is,not"), capa, list);
  13.290 -    ASSERT_EQ(n, 1);
  13.291 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  13.292 -
  13.293 -    // matching single-char delimiter
  13.294 -    n = cx_strsplit(test, cx_str(","), capa, list);
  13.295 -    ASSERT_EQ(n, 5);
  13.296 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  13.297 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  13.298 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
  13.299 -    EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
  13.300 -    EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
  13.301 -
  13.302 -    // matching multi-char delimiter
  13.303 -    n = cx_strsplit(test, cx_str("is"), capa, list);
  13.304 -    ASSERT_EQ(n, 3);
  13.305 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  13.306 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
  13.307 -    EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
  13.308 -
  13.309 -    // bounded list using single-char delimiter
  13.310 -    n = cx_strsplit(test, cx_str(","), 3, list);
  13.311 -    ASSERT_EQ(n, 3);
  13.312 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  13.313 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  13.314 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  13.315 -
  13.316 -    // bounded list using multi-char delimiter
  13.317 -    n = cx_strsplit(test, cx_str("is"), 2, list);
  13.318 -    ASSERT_EQ(n, 2);
  13.319 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  13.320 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  13.321 -
  13.322 -    // start with delimiter
  13.323 -    n = cx_strsplit(test, cx_str("this"), capa, list);
  13.324 -    ASSERT_EQ(n, 2);
  13.325 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  13.326 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  13.327 -
  13.328 -    // end with delimiter
  13.329 -    n = cx_strsplit(test, cx_str("string"), capa, list);
  13.330 -    ASSERT_EQ(n, 2);
  13.331 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
  13.332 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  13.333 -
  13.334 -
  13.335 -    // end with delimiter exceed bound
  13.336 -    n = cx_strsplit(cx_str("a,b,c,"), cx_str(","), 3, list);
  13.337 -    ASSERT_EQ(n, 3);
  13.338 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
  13.339 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
  13.340 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
  13.341 -
  13.342 -    // exact match
  13.343 -    n = cx_strsplit(test, cx_str("this,is,a,csv,string"), capa, list);
  13.344 -    ASSERT_EQ(n, 2);
  13.345 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  13.346 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  13.347 -
  13.348 -    // string to be split is only substring
  13.349 -    n = cx_strsplit(test, cx_str("this,is,a,csv,string,with,extension"), capa, list);
  13.350 -    ASSERT_EQ(n, 1);
  13.351 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  13.352 -
  13.353 -    // subsequent encounter of delimiter (the string between is empty)
  13.354 -    n = cx_strsplit(test, cx_str("is,"), capa, list);
  13.355 -    ASSERT_EQ(n, 3);
  13.356 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  13.357 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  13.358 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  13.359 -
  13.360 -    // call the _m variant just for coverage
  13.361 -    auto mtest = cx_strdup(test);
  13.362 -    cxmutstr mlist[4];
  13.363 -    n = cx_strsplit_m(mtest, cx_str("is,"), 4, mlist);
  13.364 -    ASSERT_EQ(n, 3);
  13.365 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
  13.366 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
  13.367 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
  13.368 -    cx_strfree(&mtest);
  13.369 -}
  13.370 -
  13.371 -TEST(String, strsplit_a) {
  13.372 -    CxTestingAllocator alloc;
  13.373 -
  13.374 -    cxstring test = cx_str("this,is,a,csv,string");
  13.375 -    size_t capa = 8;
  13.376 -    cxstring *list;
  13.377 -    size_t n;
  13.378 -
  13.379 -    // special case: empty string
  13.380 -    n = cx_strsplit_a(&alloc, test, cx_str(""), capa, &list);
  13.381 -    ASSERT_EQ(n, 1);
  13.382 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  13.383 -    cxFree(&alloc, list);
  13.384 -
  13.385 -    // no delimiter occurrence
  13.386 -    n = cx_strsplit_a(&alloc, test, cx_str("z"), capa, &list);
  13.387 -    ASSERT_EQ(n, 1);
  13.388 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  13.389 -    cxFree(&alloc, list);
  13.390 -
  13.391 -    // partially matching delimiter
  13.392 -    n = cx_strsplit_a(&alloc, test, cx_str("is,not"), capa, &list);
  13.393 -    ASSERT_EQ(n, 1);
  13.394 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  13.395 -    cxFree(&alloc, list);
  13.396 -
  13.397 -    // matching single-char delimiter
  13.398 -    n = cx_strsplit_a(&alloc, test, cx_str(","), capa, &list);
  13.399 -    ASSERT_EQ(n, 5);
  13.400 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  13.401 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  13.402 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
  13.403 -    EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
  13.404 -    EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
  13.405 -    cxFree(&alloc, list);
  13.406 -
  13.407 -    // matching multi-char delimiter
  13.408 -    n = cx_strsplit_a(&alloc, test, cx_str("is"), capa, &list);
  13.409 -    ASSERT_EQ(n, 3);
  13.410 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  13.411 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
  13.412 -    EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
  13.413 -    cxFree(&alloc, list);
  13.414 -
  13.415 -    // bounded list using single-char delimiter
  13.416 -    n = cx_strsplit_a(&alloc, test, cx_str(","), 3, &list);
  13.417 -    ASSERT_EQ(n, 3);
  13.418 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  13.419 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  13.420 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  13.421 -    cxFree(&alloc, list);
  13.422 -
  13.423 -    // bounded list using multi-char delimiter
  13.424 -    n = cx_strsplit_a(&alloc, test, cx_str("is"), 2, &list);
  13.425 -    ASSERT_EQ(n, 2);
  13.426 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  13.427 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  13.428 -    cxFree(&alloc, list);
  13.429 -
  13.430 -    // start with delimiter
  13.431 -    n = cx_strsplit_a(&alloc, test, cx_str("this"), capa, &list);
  13.432 -    ASSERT_EQ(n, 2);
  13.433 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  13.434 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  13.435 -    cxFree(&alloc, list);
  13.436 -
  13.437 -    // end with delimiter
  13.438 -    n = cx_strsplit_a(&alloc, test, cx_str("string"), capa, &list);
  13.439 -    ASSERT_EQ(n, 2);
  13.440 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
  13.441 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  13.442 -    cxFree(&alloc, list);
  13.443 -
  13.444 -    // end with delimiter exceed bound
  13.445 -    n = cx_strsplit_a(&alloc, cx_str("a,b,c,"), cx_str(","), 3, &list);
  13.446 -    ASSERT_EQ(n, 3);
  13.447 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
  13.448 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
  13.449 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
  13.450 -    cxFree(&alloc, list);
  13.451 -
  13.452 -    // exact match
  13.453 -    n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string"), capa, &list);
  13.454 -    ASSERT_EQ(n, 2);
  13.455 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  13.456 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  13.457 -    cxFree(&alloc, list);
  13.458 -
  13.459 -    // string to be split is only substring
  13.460 -    n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string,with,extension"), capa, &list);
  13.461 -    ASSERT_EQ(n, 1);
  13.462 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  13.463 -    cxFree(&alloc, list);
  13.464 -
  13.465 -    // subsequent encounter of delimiter (the string between is empty)
  13.466 -    n = cx_strsplit_a(&alloc, test, cx_str("is,"), capa, &list);
  13.467 -    ASSERT_EQ(n, 3);
  13.468 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  13.469 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  13.470 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  13.471 -    cxFree(&alloc, list);
  13.472 -
  13.473 -    // call the _m variant just for coverage
  13.474 -    auto mtest = cx_strdup(test);
  13.475 -    cxmutstr *mlist;
  13.476 -    n = cx_strsplit_ma(&alloc, mtest, cx_str("is,"), 4, &mlist);
  13.477 -    ASSERT_EQ(n, 3);
  13.478 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
  13.479 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
  13.480 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
  13.481 -    cxFree(&alloc, mlist);
  13.482 -    cx_strfree(&mtest);
  13.483 -
  13.484 -    EXPECT_TRUE(alloc.verify());
  13.485 -}
  13.486 -
  13.487 -TEST(String, strtrim) {
  13.488 -    cxstring t1 = cx_strtrim(cx_str("  ein test  \t "));
  13.489 -    cxstring t2 = cx_strtrim(cx_str("abc"));
  13.490 -    cxstring t3 = cx_strtrim(cx_str(" 123"));
  13.491 -    cxstring t4 = cx_strtrim(cx_str("xyz "));
  13.492 -    cxstring t5 = cx_strtrim(cx_str("   "));
  13.493 -    cxstring empty = cx_strtrim(cx_str(""));
  13.494 -
  13.495 -    EXPECT_EQ(cx_strcmp(t1, cx_str("ein test")), 0);
  13.496 -    EXPECT_EQ(cx_strcmp(t2, cx_str("abc")), 0);
  13.497 -    EXPECT_EQ(cx_strcmp(t3, cx_str("123")), 0);
  13.498 -    EXPECT_EQ(cx_strcmp(t4, cx_str("xyz")), 0);
  13.499 -    EXPECT_EQ(cx_strcmp(t5, cx_str("")), 0);
  13.500 -    EXPECT_EQ(cx_strcmp(empty, cx_str("")), 0);
  13.501 -
  13.502 -    // call the _m variant just for coverage
  13.503 -    cxmutstr m1 = cx_strtrim_m(cx_mutstr((char *) "  ein test  \t "));
  13.504 -    EXPECT_EQ(cx_strcmp(cx_strcast(m1), cx_str("ein test")), 0);
  13.505 -}
  13.506 -
  13.507 -TEST(String, strprefix) {
  13.508 -    cxstring str = CX_STR("test my prefix and my suffix");
  13.509 -    cxstring empty = CX_STR("");
  13.510 -    EXPECT_FALSE(cx_strprefix(empty, cx_str("pref")));
  13.511 -    EXPECT_TRUE(cx_strprefix(str, empty));
  13.512 -    EXPECT_TRUE(cx_strprefix(empty, empty));
  13.513 -    EXPECT_TRUE(cx_strprefix(str, cx_str("test ")));
  13.514 -    EXPECT_FALSE(cx_strprefix(str, cx_str("8-) fsck ")));
  13.515 -}
  13.516 -
  13.517 -TEST(String, strsuffix) {
  13.518 -    cxstring str = CX_STR("test my prefix and my suffix");
  13.519 -    cxstring empty = CX_STR("");
  13.520 -    EXPECT_FALSE(cx_strsuffix(empty, cx_str("suf")));
  13.521 -    EXPECT_TRUE(cx_strsuffix(str, empty));
  13.522 -    EXPECT_TRUE(cx_strsuffix(empty, empty));
  13.523 -    EXPECT_TRUE(cx_strsuffix(str, cx_str("fix")));
  13.524 -    EXPECT_FALSE(cx_strsuffix(str, cx_str("fox")));
  13.525 -}
  13.526 -
  13.527 -TEST(String, strcaseprefix) {
  13.528 -    cxstring str = CX_STR("test my prefix and my suffix");
  13.529 -    cxstring empty = CX_STR("");
  13.530 -    EXPECT_FALSE(cx_strcaseprefix(empty, cx_str("pREf")));
  13.531 -    EXPECT_TRUE(cx_strcaseprefix(str, empty));
  13.532 -    EXPECT_TRUE(cx_strcaseprefix(empty, empty));
  13.533 -    EXPECT_TRUE(cx_strcaseprefix(str, cx_str("TEST ")));
  13.534 -    EXPECT_FALSE(cx_strcaseprefix(str, cx_str("8-) fsck ")));
  13.535 -}
  13.536 -
  13.537 -TEST(String, strcasesuffix) {
  13.538 -    cxstring str = CX_STR("test my prefix and my suffix");
  13.539 -    cxstring empty = CX_STR("");
  13.540 -    EXPECT_FALSE(cx_strcasesuffix(empty, cx_str("sUf")));
  13.541 -    EXPECT_TRUE(cx_strcasesuffix(str, empty));
  13.542 -    EXPECT_TRUE(cx_strcasesuffix(empty, empty));
  13.543 -    EXPECT_TRUE(cx_strcasesuffix(str, cx_str("FIX")));
  13.544 -    EXPECT_FALSE(cx_strcasesuffix(str, cx_str("fox")));
  13.545 -}
  13.546 -
  13.547 -TEST(String, strreplace) {
  13.548 -    CxTestingAllocator alloc;
  13.549 -    cxstring str = CX_STR("test ababab string aba");
  13.550 -    cxstring longstr = CX_STR(
  13.551 -            "xyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacd");
  13.552 -    cxstring notrail = CX_STR("test abab");
  13.553 -    cxstring empty = CX_STR("");
  13.554 -    cxstring astr = CX_STR("aaaaaaaaaa");
  13.555 -    cxstring csstr = CX_STR("test AB ab TEST xyz");
  13.556 -
  13.557 -    cxmutstr repl = cx_strreplace(str, cx_str("abab"), cx_str("muchlonger"));
  13.558 -    auto expected = "test muchlongerab string aba";
  13.559 -
  13.560 -    cxmutstr repln = cx_strreplacen(str, cx_str("ab"), cx_str("c"), 2);
  13.561 -    auto expectedn = "test ccab string aba";
  13.562 -
  13.563 -    cxmutstr longrepl = cx_strreplace(longstr, cx_str("a"), cx_str("z"));
  13.564 -    auto longexpect = "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd";
  13.565 -
  13.566 -    cxmutstr replnotrail = cx_strreplace(notrail, cx_str("ab"), cx_str("z"));
  13.567 -    auto notrailexpect = "test zz";
  13.568 -
  13.569 -    cxmutstr repleq = cx_strreplace(str, str, cx_str("hello"));
  13.570 -    auto eqexpect = "hello";
  13.571 -
  13.572 -    cxmutstr replempty1 = cx_strreplace(empty, cx_str("ab"), cx_str("c")); // expect: empty
  13.573 -    cxmutstr replempty2 = cx_strreplace(str, cx_str("abab"), empty);
  13.574 -    auto emptyexpect2 = "test ab string aba";
  13.575 -
  13.576 -    cxmutstr replpre = cx_strreplace(str, cx_str("test "), cx_str("TEST "));
  13.577 -    auto preexpected = "TEST ababab string aba";
  13.578 -
  13.579 -    cxmutstr replan1 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 1);
  13.580 -    auto an1expected = "xaaaaaaaaa";
  13.581 -
  13.582 -    cxmutstr replan4 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 4);
  13.583 -    auto an4expected = "xxxxaaaaaa";
  13.584 -
  13.585 -    cxmutstr replan9 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 9);
  13.586 -    auto an9expected = "xxxxxxxxxa";
  13.587 -
  13.588 -    cxmutstr replan10 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 10);
  13.589 -    auto an10expected = "xxxxxxxxxx";
  13.590 -
  13.591 -    cxmutstr repl1_a = cx_strreplace_a(&alloc, csstr, cx_str("AB"), cx_str("*"));
  13.592 -    auto expeced1_a = "test * ab TEST xyz";
  13.593 -
  13.594 -    cxmutstr repl2_a = cx_strreplace_a(&alloc, csstr, cx_str("test"), cx_str("TEST"));
  13.595 -    auto expected2_a = "TEST AB ab TEST xyz";
  13.596 -
  13.597 -
  13.598 -    EXPECT_NE(repl.ptr, str.ptr);
  13.599 -    EXPECT_ZERO_TERMINATED(repl);
  13.600 -    EXPECT_STREQ(repl.ptr, expected);
  13.601 -    EXPECT_ZERO_TERMINATED(repln);
  13.602 -    EXPECT_STREQ(repln.ptr, expectedn);
  13.603 -    EXPECT_ZERO_TERMINATED(longrepl);
  13.604 -    EXPECT_STREQ(longrepl.ptr, longexpect);
  13.605 -    EXPECT_ZERO_TERMINATED(replnotrail);
  13.606 -    EXPECT_STREQ(replnotrail.ptr, notrailexpect);
  13.607 -    EXPECT_ZERO_TERMINATED(repleq);
  13.608 -    EXPECT_STREQ(repleq.ptr, eqexpect);
  13.609 -    EXPECT_ZERO_TERMINATED(replempty1);
  13.610 -    EXPECT_STREQ(replempty1.ptr, "");
  13.611 -    EXPECT_ZERO_TERMINATED(replempty2);
  13.612 -    EXPECT_STREQ(replempty2.ptr, emptyexpect2);
  13.613 -    EXPECT_ZERO_TERMINATED(replpre);
  13.614 -    EXPECT_STREQ(replpre.ptr, preexpected);
  13.615 -    EXPECT_ZERO_TERMINATED(replan1);
  13.616 -    EXPECT_STREQ(replan1.ptr, an1expected);
  13.617 -    EXPECT_ZERO_TERMINATED(replan4);
  13.618 -    EXPECT_STREQ(replan4.ptr, an4expected);
  13.619 -    EXPECT_ZERO_TERMINATED(replan9);
  13.620 -    EXPECT_STREQ(replan9.ptr, an9expected);
  13.621 -    EXPECT_ZERO_TERMINATED(replan10);
  13.622 -    EXPECT_STREQ(replan10.ptr, an10expected);
  13.623 -    EXPECT_ZERO_TERMINATED(repl1_a);
  13.624 -    EXPECT_STREQ(repl1_a.ptr, expeced1_a);
  13.625 -    EXPECT_ZERO_TERMINATED(repl2_a);
  13.626 -    EXPECT_STREQ(repl2_a.ptr, expected2_a);
  13.627 -
  13.628 -    cx_strfree(&repl);
  13.629 -    cx_strfree(&repln);
  13.630 -    cx_strfree(&longrepl);
  13.631 -    cx_strfree(&replnotrail);
  13.632 -    cx_strfree(&repleq);
  13.633 -    cx_strfree(&replempty1);
  13.634 -    cx_strfree(&replempty2);
  13.635 -    cx_strfree(&replpre);
  13.636 -    cx_strfree(&replan1);
  13.637 -    cx_strfree(&replan4);
  13.638 -    cx_strfree(&replan9);
  13.639 -    cx_strfree(&replan10);
  13.640 -
  13.641 -    cx_strfree_a(&alloc, &repl1_a);
  13.642 -    cx_strfree_a(&alloc, &repl2_a);
  13.643 -    EXPECT_TRUE(alloc.verify());
  13.644 -}
  13.645 -
  13.646 -TEST(String, strupper) {
  13.647 -    cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
  13.648 -    cx_strupper(str);
  13.649 -    EXPECT_STREQ(str.ptr, "THIS 1S @ TE$T");
  13.650 -    cx_strfree(&str);
  13.651 -}
  13.652 -
  13.653 -TEST(String, strlower) {
  13.654 -    cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
  13.655 -    cx_strlower(str);
  13.656 -    EXPECT_STREQ(str.ptr, "this 1s @ te$t");
  13.657 -    cx_strfree(&str);
  13.658 -}
  13.659 -
  13.660 -TEST(String, strtok) {
  13.661 -    cxstring str = cx_str("a,comma,separated,string");
  13.662 -    cxstring delim = cx_str(",");
  13.663 -    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  13.664 -    EXPECT_EQ(ctx.str.ptr, str.ptr);
  13.665 -    EXPECT_EQ(ctx.str.length, str.length);
  13.666 -    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  13.667 -    EXPECT_EQ(ctx.delim.length, delim.length);
  13.668 -    EXPECT_EQ(ctx.limit, 3);
  13.669 -    EXPECT_EQ(ctx.found, 0);
  13.670 -    EXPECT_EQ(ctx.pos, 0);
  13.671 -    EXPECT_EQ(ctx.next_pos, 0);
  13.672 -    EXPECT_EQ(ctx.delim_more, nullptr);
  13.673 -    EXPECT_EQ(ctx.delim_more_count, 0);
  13.674 -}
  13.675 -
  13.676 -TEST(String, strtok_m) {
  13.677 -    cxmutstr str = cx_strdup(cx_str("a,comma,separated,string"));
  13.678 -    cxstring delim = cx_str(",");
  13.679 -    CxStrtokCtx ctx = cx_strtok_m(str, delim, 3);
  13.680 -    EXPECT_EQ(ctx.str.ptr, str.ptr);
  13.681 -    EXPECT_EQ(ctx.str.length, str.length);
  13.682 -    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  13.683 -    EXPECT_EQ(ctx.delim.length, delim.length);
  13.684 -    EXPECT_EQ(ctx.limit, 3);
  13.685 -    EXPECT_EQ(ctx.found, 0);
  13.686 -    EXPECT_EQ(ctx.pos, 0);
  13.687 -    EXPECT_EQ(ctx.next_pos, 0);
  13.688 -    EXPECT_EQ(ctx.delim_more, nullptr);
  13.689 -    EXPECT_EQ(ctx.delim_more_count, 0);
  13.690 -    cx_strfree(&str);
  13.691 -}
  13.692 -
  13.693 -TEST(String, strtok_delim) {
  13.694 -    cxstring str = cx_str("an,arbitrarily|separated;string");
  13.695 -    cxstring delim = cx_str(",");
  13.696 -    cxstring delim_more[2] = {CX_STR("|"), CX_STR(";")};
  13.697 -    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  13.698 -    cx_strtok_delim(&ctx, delim_more, 2);
  13.699 -    EXPECT_EQ(ctx.str.ptr, str.ptr);
  13.700 -    EXPECT_EQ(ctx.str.length, str.length);
  13.701 -    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  13.702 -    EXPECT_EQ(ctx.delim.length, delim.length);
  13.703 -    EXPECT_EQ(ctx.limit, 3);
  13.704 -    EXPECT_EQ(ctx.found, 0);
  13.705 -    EXPECT_EQ(ctx.pos, 0);
  13.706 -    EXPECT_EQ(ctx.next_pos, 0);
  13.707 -    EXPECT_EQ(ctx.delim_more, delim_more);
  13.708 -    EXPECT_EQ(ctx.delim_more_count, 2);
  13.709 -}
  13.710 -
  13.711 -TEST(String, strtok_next_easy) {
  13.712 -    cxstring str = cx_str("a,comma,separated,string");
  13.713 -    cxstring delim = cx_str(",");
  13.714 -    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  13.715 -    bool ret;
  13.716 -    cxstring tok;
  13.717 -
  13.718 -    ret = cx_strtok_next(&ctx, &tok);
  13.719 -    ASSERT_TRUE(ret);
  13.720 -    EXPECT_EQ(cx_strcmp(tok, cx_str("a")), 0);
  13.721 -    EXPECT_EQ(ctx.pos, 0);
  13.722 -    EXPECT_EQ(ctx.next_pos, 2);
  13.723 -    EXPECT_EQ(ctx.delim_pos, 1);
  13.724 -    EXPECT_EQ(ctx.found, 1);
  13.725 -
  13.726 -    ret = cx_strtok_next(&ctx, &tok);
  13.727 -    ASSERT_TRUE(ret);
  13.728 -    EXPECT_EQ(cx_strcmp(tok, cx_str("comma")), 0);
  13.729 -    EXPECT_EQ(ctx.pos, 2);
  13.730 -    EXPECT_EQ(ctx.next_pos, 8);
  13.731 -    EXPECT_EQ(ctx.delim_pos, 7);
  13.732 -    EXPECT_EQ(ctx.found, 2);
  13.733 -
  13.734 -    ret = cx_strtok_next(&ctx, &tok);
  13.735 -    ASSERT_TRUE(ret);
  13.736 -    EXPECT_EQ(cx_strcmp(tok, cx_str("separated")), 0);
  13.737 -    EXPECT_EQ(ctx.pos, 8);
  13.738 -    EXPECT_EQ(ctx.next_pos, 18);
  13.739 -    EXPECT_EQ(ctx.delim_pos, 17);
  13.740 -    EXPECT_EQ(ctx.found, 3);
  13.741 -
  13.742 -    ret = cx_strtok_next(&ctx, &tok);
  13.743 -    ASSERT_FALSE(ret);
  13.744 -    EXPECT_EQ(ctx.pos, 8);
  13.745 -    EXPECT_EQ(ctx.next_pos, 18);
  13.746 -    EXPECT_EQ(ctx.delim_pos, 17);
  13.747 -    EXPECT_EQ(ctx.found, 3);
  13.748 -}
  13.749 -
  13.750 -TEST(String, strtok_next_unlimited) {
  13.751 -    cxstring str = cx_str("some;-;otherwise;-;separated;-;string;-;");
  13.752 -    cxstring delim = cx_str(";-;");
  13.753 -    CxStrtokCtx ctx = cx_strtok(str, delim, SIZE_MAX);
  13.754 -    bool ret;
  13.755 -    cxstring tok;
  13.756 -
  13.757 -    ret = cx_strtok_next(&ctx, &tok);
  13.758 -    ASSERT_TRUE(ret);
  13.759 -    EXPECT_EQ(cx_strcmp(tok, cx_str("some")), 0);
  13.760 -    EXPECT_EQ(ctx.pos, 0);
  13.761 -    EXPECT_EQ(ctx.next_pos, 7);
  13.762 -    EXPECT_EQ(ctx.delim_pos, 4);
  13.763 -    EXPECT_EQ(ctx.found, 1);
  13.764 -
  13.765 -    ret = cx_strtok_next(&ctx, &tok);
  13.766 -    ASSERT_TRUE(ret);
  13.767 -    EXPECT_EQ(cx_strcmp(tok, cx_str("otherwise")), 0);
  13.768 -    EXPECT_EQ(ctx.pos, 7);
  13.769 -    EXPECT_EQ(ctx.next_pos, 19);
  13.770 -    EXPECT_EQ(ctx.delim_pos, 16);
  13.771 -    EXPECT_EQ(ctx.found, 2);
  13.772 -
  13.773 -    ret = cx_strtok_next(&ctx, &tok);
  13.774 -    ASSERT_TRUE(ret);
  13.775 -    EXPECT_EQ(cx_strcmp(tok, cx_str("separated")), 0);
  13.776 -    EXPECT_EQ(ctx.pos, 19);
  13.777 -    EXPECT_EQ(ctx.next_pos, 31);
  13.778 -    EXPECT_EQ(ctx.delim_pos, 28);
  13.779 -    EXPECT_EQ(ctx.found, 3);
  13.780 -
  13.781 -    ret = cx_strtok_next(&ctx, &tok);
  13.782 -    ASSERT_TRUE(ret);
  13.783 -    EXPECT_EQ(cx_strcmp(tok, cx_str("string")), 0);
  13.784 -    EXPECT_EQ(ctx.pos, 31);
  13.785 -    EXPECT_EQ(ctx.next_pos, 40);
  13.786 -    EXPECT_EQ(ctx.delim_pos, 37);
  13.787 -    EXPECT_EQ(ctx.found, 4);
  13.788 -
  13.789 -    ret = cx_strtok_next(&ctx, &tok);
  13.790 -    ASSERT_TRUE(ret);
  13.791 -    EXPECT_EQ(cx_strcmp(tok, cx_str("")), 0);
  13.792 -    EXPECT_EQ(ctx.pos, 40);
  13.793 -    EXPECT_EQ(ctx.next_pos, 40);
  13.794 -    EXPECT_EQ(ctx.delim_pos, 40);
  13.795 -    EXPECT_EQ(ctx.found, 5);
  13.796 -
  13.797 -    ret = cx_strtok_next(&ctx, &tok);
  13.798 -    ASSERT_FALSE(ret);
  13.799 -    EXPECT_EQ(ctx.pos, 40);
  13.800 -    EXPECT_EQ(ctx.delim_pos, 40);
  13.801 -    EXPECT_EQ(ctx.found, 5);
  13.802 -}
  13.803 -
  13.804 -TEST(String, strtok_next_advanced) {
  13.805 -    cxmutstr str = cx_strdup(cx_str("an,arbitrarily;||separated;string"));
  13.806 -    cxstring delim = cx_str(",");
  13.807 -    cxstring delim_more[2] = {CX_STR("||"), CX_STR(";")};
  13.808 -    CxStrtokCtx ctx = cx_strtok_m(str, delim, 10);
  13.809 -    cx_strtok_delim(&ctx, delim_more, 2);
  13.810 -    bool ret;
  13.811 -    cxmutstr tok;
  13.812 -
  13.813 -    ret = cx_strtok_next_m(&ctx, &tok);
  13.814 -    ASSERT_TRUE(ret);
  13.815 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("an")), 0);
  13.816 -    EXPECT_EQ(ctx.pos, 0);
  13.817 -    EXPECT_EQ(ctx.next_pos, 3);
  13.818 -    EXPECT_EQ(ctx.delim_pos, 2);
  13.819 -    EXPECT_EQ(ctx.found, 1);
  13.820 -    cx_strupper(tok);
  13.821 -
  13.822 -    ret = cx_strtok_next_m(&ctx, &tok);
  13.823 -    ASSERT_TRUE(ret);
  13.824 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("arbitrarily")), 0);
  13.825 -    EXPECT_EQ(ctx.pos, 3);
  13.826 -    EXPECT_EQ(ctx.next_pos, 15);
  13.827 -    EXPECT_EQ(ctx.delim_pos, 14);
  13.828 -    EXPECT_EQ(ctx.found, 2);
  13.829 -    cx_strupper(tok);
  13.830 -
  13.831 -    ret = cx_strtok_next_m(&ctx, &tok);
  13.832 -    ASSERT_TRUE(ret);
  13.833 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("")), 0);
  13.834 -    EXPECT_EQ(ctx.pos, 15);
  13.835 -    EXPECT_EQ(ctx.next_pos, 17);
  13.836 -    EXPECT_EQ(ctx.delim_pos, 15);
  13.837 -    EXPECT_EQ(ctx.found, 3);
  13.838 -    cx_strupper(tok);
  13.839 -
  13.840 -    ret = cx_strtok_next_m(&ctx, &tok);
  13.841 -    ASSERT_TRUE(ret);
  13.842 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("separated")), 0);
  13.843 -    EXPECT_EQ(ctx.pos, 17);
  13.844 -    EXPECT_EQ(ctx.next_pos, 27);
  13.845 -    EXPECT_EQ(ctx.delim_pos, 26);
  13.846 -    EXPECT_EQ(ctx.found, 4);
  13.847 -    cx_strupper(tok);
  13.848 -
  13.849 -    ret = cx_strtok_next_m(&ctx, &tok);
  13.850 -    ASSERT_TRUE(ret);
  13.851 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("string")), 0);
  13.852 -    EXPECT_EQ(ctx.pos, 27);
  13.853 -    EXPECT_EQ(ctx.next_pos, 33);
  13.854 -    EXPECT_EQ(ctx.delim_pos, 33);
  13.855 -    EXPECT_EQ(ctx.found, 5);
  13.856 -    cx_strupper(tok);
  13.857 -
  13.858 -    ret = cx_strtok_next_m(&ctx, &tok);
  13.859 -    ASSERT_FALSE(ret);
  13.860 -    EXPECT_EQ(ctx.pos, 27);
  13.861 -    EXPECT_EQ(ctx.next_pos, 33);
  13.862 -    EXPECT_EQ(ctx.delim_pos, 33);
  13.863 -    EXPECT_EQ(ctx.found, 5);
  13.864 -
  13.865 -    EXPECT_EQ(cx_strcmp(cx_strcast(str), cx_str("AN,ARBITRARILY;||SEPARATED;STRING")), 0);
  13.866 -
  13.867 -    cx_strfree(&str);
  13.868 -}
    14.1 --- a/test/test_tree.cpp	Tue Feb 07 21:53:06 2023 +0100
    14.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.3 @@ -1,122 +0,0 @@
    14.4 -/*
    14.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    14.6 - *
    14.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    14.8 - *
    14.9 - * Redistribution and use in source and binary forms, with or without
   14.10 - * modification, are permitted provided that the following conditions are met:
   14.11 - *
   14.12 - *   1. Redistributions of source code must retain the above copyright
   14.13 - *      notice, this list of conditions and the following disclaimer.
   14.14 - *
   14.15 - *   2. Redistributions in binary form must reproduce the above copyright
   14.16 - *      notice, this list of conditions and the following disclaimer in the
   14.17 - *      documentation and/or other materials provided with the distribution.
   14.18 - *
   14.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   14.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   14.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   14.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   14.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   14.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   14.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   14.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   14.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   14.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   14.29 - * POSSIBILITY OF SUCH DAMAGE.
   14.30 - */
   14.31 -
   14.32 -#include "cx/tree.h"
   14.33 -#include <gtest/gtest.h>
   14.34 -
   14.35 -struct TestNode {
   14.36 -    TestNode *parent = nullptr;
   14.37 -    TestNode *prev = nullptr;
   14.38 -    TestNode *next = nullptr;
   14.39 -
   14.40 -    TestNode *children_begin = nullptr;
   14.41 -    TestNode *children_end = nullptr;
   14.42 -};
   14.43 -
   14.44 -TEST(Tree, cx_tree_add_sibling) {
   14.45 -    // prepare test tree
   14.46 -    TestNode root, a;
   14.47 -    root.children_begin = &a;
   14.48 -    root.children_end = &a;
   14.49 -    a.parent = &root;
   14.50 -
   14.51 -    // new test nodes
   14.52 -    TestNode b, c;
   14.53 -
   14.54 -    // test
   14.55 -    cx_tree_add_sibling(&a, offsetof(TestNode, prev), offsetof(TestNode, next), offsetof(TestNode, parent), &b);
   14.56 -    EXPECT_EQ(b.parent, &root);
   14.57 -    EXPECT_EQ(b.prev, &a);
   14.58 -    EXPECT_EQ(b.next, nullptr);
   14.59 -    EXPECT_EQ(a.next, &b);
   14.60 -
   14.61 -    cx_tree_add_sibling(&a, -1, offsetof(TestNode, next), -1, &c);
   14.62 -    EXPECT_EQ(c.parent, nullptr);
   14.63 -    EXPECT_EQ(c.prev, nullptr);
   14.64 -    EXPECT_EQ(c.next, nullptr);
   14.65 -    EXPECT_EQ(b.next, &c);
   14.66 -}
   14.67 -
   14.68 -TEST(Tree, cx_tree_add_child) {
   14.69 -    TestNode root, a, b, c, a1;
   14.70 -
   14.71 -    cx_tree_add_child(
   14.72 -            (void **) &root.children_begin,
   14.73 -            (void **) &root.children_end,
   14.74 -            offsetof(TestNode, prev),
   14.75 -            offsetof(TestNode, next),
   14.76 -            &a,
   14.77 -            offsetof(TestNode, parent),
   14.78 -            &root);
   14.79 -    EXPECT_EQ(root.children_begin, &a);
   14.80 -    EXPECT_EQ(root.children_end, &a);
   14.81 -    EXPECT_EQ(a.parent, &root);
   14.82 -    EXPECT_EQ(a.prev, nullptr);
   14.83 -    EXPECT_EQ(a.next, nullptr);
   14.84 -
   14.85 -    cx_tree_add_child(
   14.86 -            (void **) &root.children_begin,
   14.87 -            (void **) &root.children_end,
   14.88 -            offsetof(TestNode, prev),
   14.89 -            offsetof(TestNode, next),
   14.90 -            &b,
   14.91 -            offsetof(TestNode, parent),
   14.92 -            &root);
   14.93 -    EXPECT_EQ(root.children_begin, &a);
   14.94 -    EXPECT_EQ(root.children_begin->next, &b);
   14.95 -    EXPECT_EQ(root.children_end, &b);
   14.96 -    EXPECT_EQ(b.parent, &root);
   14.97 -    EXPECT_EQ(b.prev, &a);
   14.98 -
   14.99 -    cx_tree_add_child(
  14.100 -            (void **) &root.children_begin,
  14.101 -            nullptr,
  14.102 -            -1,
  14.103 -            offsetof(TestNode, next),
  14.104 -            &c,
  14.105 -            -1,
  14.106 -            &root);
  14.107 -    EXPECT_EQ(root.children_end, &b); // children_end unchanged
  14.108 -    EXPECT_EQ(b.next, &c);
  14.109 -    EXPECT_EQ(c.prev, nullptr);
  14.110 -    EXPECT_EQ(c.next, nullptr);
  14.111 -    EXPECT_EQ(c.parent, nullptr);
  14.112 -
  14.113 -    cx_tree_add_child(
  14.114 -            (void **) &a.children_begin,
  14.115 -            (void **) &a.children_end,
  14.116 -            offsetof(TestNode, prev),
  14.117 -            offsetof(TestNode, next),
  14.118 -            &a1,
  14.119 -            offsetof(TestNode, parent),
  14.120 -            &a);
  14.121 -    EXPECT_EQ(a.children_begin, &a1);
  14.122 -    EXPECT_EQ(a1.parent, &a);
  14.123 -    EXPECT_EQ(root.children_begin, &a);
  14.124 -    EXPECT_EQ(root.children_begin->children_begin, &a1);
  14.125 -}
    15.1 --- a/test/test_utils.cpp	Tue Feb 07 21:53:06 2023 +0100
    15.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.3 @@ -1,155 +0,0 @@
    15.4 -/*
    15.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    15.6 - *
    15.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    15.8 - *
    15.9 - * Redistribution and use in source and binary forms, with or without
   15.10 - * modification, are permitted provided that the following conditions are met:
   15.11 - *
   15.12 - *   1. Redistributions of source code must retain the above copyright
   15.13 - *      notice, this list of conditions and the following disclaimer.
   15.14 - *
   15.15 - *   2. Redistributions in binary form must reproduce the above copyright
   15.16 - *      notice, this list of conditions and the following disclaimer in the
   15.17 - *      documentation and/or other materials provided with the distribution.
   15.18 - *
   15.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   15.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   15.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   15.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   15.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   15.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   15.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   15.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   15.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   15.29 - * POSSIBILITY OF SUCH DAMAGE.
   15.30 - */
   15.31 -
   15.32 -#include "cx/utils.h"
   15.33 -
   15.34 -#include <gtest/gtest.h>
   15.35 -
   15.36 -TEST(Utils, ForN) {
   15.37 -    unsigned j;
   15.38 -    j = 0;
   15.39 -    cx_for_n(i, 50) {
   15.40 -        EXPECT_EQ(i, j);
   15.41 -        j++;
   15.42 -    }
   15.43 -}
   15.44 -
   15.45 -TEST(Utils, szmul) {
   15.46 -    size_t r;
   15.47 -    int e;
   15.48 -    e = cx_szmul(5, 7, &r);
   15.49 -    EXPECT_EQ(0, e);
   15.50 -    EXPECT_EQ(35, r);
   15.51 -
   15.52 -    size_t s = SIZE_MAX & ~3;
   15.53 -
   15.54 -    e = cx_szmul(s / 4, 2, &r);
   15.55 -    EXPECT_EQ(0, e);
   15.56 -    EXPECT_EQ(s / 2, r);
   15.57 -    e = cx_szmul(2, s / 4, &r);
   15.58 -    EXPECT_EQ(0, e);
   15.59 -    EXPECT_EQ(s / 2, r);
   15.60 -
   15.61 -    e = cx_szmul(s / 4, 4, &r);
   15.62 -    EXPECT_EQ(0, e);
   15.63 -    EXPECT_EQ(s, r);
   15.64 -
   15.65 -    e = cx_szmul(4, s / 4, &r);
   15.66 -    EXPECT_EQ(0, e);
   15.67 -    EXPECT_EQ(s, r);
   15.68 -
   15.69 -    e = cx_szmul(s / 4, 5, &r);
   15.70 -    EXPECT_NE(0, e);
   15.71 -
   15.72 -    e = cx_szmul(5, s / 4, &r);
   15.73 -    EXPECT_NE(0, e);
   15.74 -
   15.75 -    e = cx_szmul(SIZE_MAX - 4, 0, &r);
   15.76 -    EXPECT_EQ(0, e);
   15.77 -    EXPECT_EQ(0, r);
   15.78 -
   15.79 -    e = cx_szmul(0, SIZE_MAX - 1, &r);
   15.80 -    EXPECT_EQ(0, e);
   15.81 -    EXPECT_EQ(0, r);
   15.82 -
   15.83 -    e = cx_szmul(SIZE_MAX, 0, &r);
   15.84 -    EXPECT_EQ(0, e);
   15.85 -    EXPECT_EQ(0, r);
   15.86 -
   15.87 -    e = cx_szmul(0, SIZE_MAX, &r);
   15.88 -    EXPECT_EQ(0, e);
   15.89 -    EXPECT_EQ(0, r);
   15.90 -
   15.91 -    e = cx_szmul(0, 0, &r);
   15.92 -    EXPECT_EQ(0, e);
   15.93 -    EXPECT_EQ(0, r);
   15.94 -}
   15.95 -
   15.96 -#ifdef CX_SZMUL_BUILTIN
   15.97 -
   15.98 -// also test the custom implementation
   15.99 -struct Utils_szmul_impl : ::testing::Test {
  15.100 -#undef CX_SZMUL_BUILTIN
  15.101 -
  15.102 -#include "../src/utils.c"
  15.103 -
  15.104 -#define CX_SZMUL_BUILTIN
  15.105 -};
  15.106 -
  15.107 -TEST_F(Utils_szmul_impl, Test) {
  15.108 -    size_t r;
  15.109 -    int e;
  15.110 -    e = cx_szmul_impl(5, 7, &r);
  15.111 -    EXPECT_EQ(0, e);
  15.112 -    EXPECT_EQ(35, r);
  15.113 -
  15.114 -    size_t s = SIZE_MAX & ~3;
  15.115 -
  15.116 -    e = cx_szmul_impl(s / 4, 2, &r);
  15.117 -    EXPECT_EQ(0, e);
  15.118 -    EXPECT_EQ(s / 2, r);
  15.119 -    e = cx_szmul_impl(2, s / 4, &r);
  15.120 -    EXPECT_EQ(0, e);
  15.121 -    EXPECT_EQ(s / 2, r);
  15.122 -
  15.123 -    e = cx_szmul_impl(s / 4, 4, &r);
  15.124 -    EXPECT_EQ(0, e);
  15.125 -    EXPECT_EQ(s, r);
  15.126 -
  15.127 -    e = cx_szmul_impl(4, s / 4, &r);
  15.128 -    EXPECT_EQ(0, e);
  15.129 -    EXPECT_EQ(s, r);
  15.130 -
  15.131 -    e = cx_szmul_impl(s / 4, 5, &r);
  15.132 -    EXPECT_NE(0, e);
  15.133 -
  15.134 -    e = cx_szmul_impl(5, s / 4, &r);
  15.135 -    EXPECT_NE(0, e);
  15.136 -
  15.137 -    e = cx_szmul_impl(SIZE_MAX - 4, 0, &r);
  15.138 -    EXPECT_EQ(0, e);
  15.139 -    EXPECT_EQ(0, r);
  15.140 -
  15.141 -    e = cx_szmul_impl(0, SIZE_MAX - 1, &r);
  15.142 -    EXPECT_EQ(0, e);
  15.143 -    EXPECT_EQ(0, r);
  15.144 -
  15.145 -    e = cx_szmul_impl(SIZE_MAX, 0, &r);
  15.146 -    EXPECT_EQ(0, e);
  15.147 -    EXPECT_EQ(0, r);
  15.148 -
  15.149 -    e = cx_szmul_impl(0, SIZE_MAX, &r);
  15.150 -    EXPECT_EQ(0, e);
  15.151 -    EXPECT_EQ(0, r);
  15.152 -
  15.153 -    e = cx_szmul_impl(0, 0, &r);
  15.154 -    EXPECT_EQ(0, e);
  15.155 -    EXPECT_EQ(0, r);
  15.156 -}
  15.157 -
  15.158 -#endif // CX_SZMUL_BUILTIN
    16.1 --- a/test/util_allocator.cpp	Tue Feb 07 21:53:06 2023 +0100
    16.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.3 @@ -1,167 +0,0 @@
    16.4 -/*
    16.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    16.6 - *
    16.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    16.8 - *
    16.9 - * Redistribution and use in source and binary forms, with or without
   16.10 - * modification, are permitted provided that the following conditions are met:
   16.11 - *
   16.12 - *   1. Redistributions of source code must retain the above copyright
   16.13 - *      notice, this list of conditions and the following disclaimer.
   16.14 - *
   16.15 - *   2. Redistributions in binary form must reproduce the above copyright
   16.16 - *      notice, this list of conditions and the following disclaimer in the
   16.17 - *      documentation and/or other materials provided with the distribution.
   16.18 - *
   16.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   16.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   16.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   16.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   16.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   16.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   16.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   16.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   16.29 - * POSSIBILITY OF SUCH DAMAGE.
   16.30 - */
   16.31 -
   16.32 -#include "util_allocator.h"
   16.33 -
   16.34 -void *cx_malloc_testing(void *d, size_t n) {
   16.35 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   16.36 -    void *ptr = malloc(n);
   16.37 -    data->alloc_total++;
   16.38 -    if (ptr == nullptr) {
   16.39 -        data->alloc_failed++;
   16.40 -    } else {
   16.41 -        data->tracked.insert(ptr);
   16.42 -    }
   16.43 -    return ptr;
   16.44 -}
   16.45 -
   16.46 -void *cx_realloc_testing(void *d, void *mem, size_t n) {
   16.47 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   16.48 -    void *ptr = realloc(mem, n);
   16.49 -    if (ptr == mem) {
   16.50 -        return ptr;
   16.51 -    } else {
   16.52 -        data->alloc_total++;
   16.53 -        if (ptr == nullptr) {
   16.54 -            data->alloc_failed++;
   16.55 -        } else {
   16.56 -            data->free_total++;
   16.57 -            if (data->tracked.erase(mem) == 0) {
   16.58 -                data->free_failed++;
   16.59 -            }
   16.60 -            data->tracked.insert(ptr);
   16.61 -        }
   16.62 -        return ptr;
   16.63 -    }
   16.64 -}
   16.65 -
   16.66 -void *cx_calloc_testing(void *d, size_t nelem, size_t n) {
   16.67 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   16.68 -    void *ptr = calloc(nelem, n);
   16.69 -    data->alloc_total++;
   16.70 -    if (ptr == nullptr) {
   16.71 -        data->alloc_failed++;
   16.72 -    } else {
   16.73 -        data->tracked.insert(ptr);
   16.74 -    }
   16.75 -    return ptr;
   16.76 -}
   16.77 -
   16.78 -void cx_free_testing(void *d, void *mem) {
   16.79 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   16.80 -    data->free_total++;
   16.81 -    if (data->tracked.erase(mem) == 0) {
   16.82 -        data->free_failed++;
   16.83 -        // do not even attempt to free mem, because it is likely to segfault
   16.84 -    } else {
   16.85 -        free(mem);
   16.86 -    }
   16.87 -}
   16.88 -
   16.89 -cx_allocator_class cx_testing_allocator_class = {
   16.90 -        cx_malloc_testing,
   16.91 -        cx_realloc_testing,
   16.92 -        cx_calloc_testing,
   16.93 -        cx_free_testing
   16.94 -};
   16.95 -
   16.96 -CxTestingAllocator::CxTestingAllocator() : CxAllocator() {
   16.97 -    cl = &cx_testing_allocator_class;
   16.98 -    data = this;
   16.99 -}
  16.100 -
  16.101 -bool CxTestingAllocator::used() const {
  16.102 -    return alloc_total > 0;
  16.103 -}
  16.104 -
  16.105 -bool CxTestingAllocator::verify() const {
  16.106 -    return tracked.empty() && alloc_failed == 0 && free_failed == 0 && alloc_total == free_total;
  16.107 -}
  16.108 -
  16.109 -// SELF-TEST
  16.110 -
  16.111 -#include <gtest/gtest.h>
  16.112 -
  16.113 -TEST(TestingAllocator, ExpectFree) {
  16.114 -    CxTestingAllocator allocator;
  16.115 -
  16.116 -    ASSERT_TRUE(allocator.verify());
  16.117 -    EXPECT_FALSE(allocator.used());
  16.118 -    auto ptr = cxMalloc(&allocator, 16);
  16.119 -    EXPECT_TRUE(allocator.used());
  16.120 -    ASSERT_NE(ptr, nullptr);
  16.121 -    EXPECT_FALSE(allocator.verify());
  16.122 -
  16.123 -    cxFree(&allocator, ptr);
  16.124 -    EXPECT_TRUE(allocator.verify());
  16.125 -}
  16.126 -
  16.127 -TEST(TestingAllocator, DetectDoubleFree) {
  16.128 -    CxTestingAllocator allocator;
  16.129 -
  16.130 -    ASSERT_TRUE(allocator.verify());
  16.131 -    auto ptr = cxMalloc(&allocator, 16);
  16.132 -    ASSERT_NE(ptr, nullptr);
  16.133 -
  16.134 -    cxFree(&allocator, ptr);
  16.135 -    EXPECT_TRUE(allocator.verify());
  16.136 -    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
  16.137 -    EXPECT_FALSE(allocator.verify());
  16.138 -}
  16.139 -
  16.140 -TEST(TestingAllocator, FreeUntracked) {
  16.141 -    CxTestingAllocator allocator;
  16.142 -
  16.143 -    auto ptr = malloc(16);
  16.144 -    ASSERT_TRUE(allocator.verify());
  16.145 -    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
  16.146 -    EXPECT_FALSE(allocator.verify());
  16.147 -    ASSERT_NO_FATAL_FAILURE(free(ptr));
  16.148 -}
  16.149 -
  16.150 -TEST(TestingAllocator, FullLifecycleWithRealloc) {
  16.151 -    CxTestingAllocator allocator;
  16.152 -    ASSERT_TRUE(allocator.verify());
  16.153 -    auto ptr = cxMalloc(&allocator, 16);
  16.154 -    ASSERT_NE(ptr, nullptr);
  16.155 -    EXPECT_EQ(allocator.tracked.size(), 1);
  16.156 -    ptr = cxRealloc(&allocator, ptr, 256);
  16.157 -    ASSERT_NE(ptr, nullptr);
  16.158 -    EXPECT_EQ(allocator.tracked.size(), 1);
  16.159 -    cxFree(&allocator, ptr);
  16.160 -    EXPECT_TRUE(allocator.verify());
  16.161 -}
  16.162 -
  16.163 -TEST(TestingAllocator, CallocInitializes) {
  16.164 -    CxTestingAllocator allocator;
  16.165 -    const char zeros[16] = {0};
  16.166 -    auto ptr = cxCalloc(&allocator, 16, 1);
  16.167 -    EXPECT_EQ(memcmp(ptr, zeros, 16), 0);
  16.168 -    cxFree(&allocator, ptr);
  16.169 -    EXPECT_TRUE(allocator.verify());
  16.170 -}
    17.1 --- a/test/util_allocator.h	Tue Feb 07 21:53:06 2023 +0100
    17.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.3 @@ -1,81 +0,0 @@
    17.4 -/*
    17.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    17.6 - *
    17.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    17.8 - *
    17.9 - * Redistribution and use in source and binary forms, with or without
   17.10 - * modification, are permitted provided that the following conditions are met:
   17.11 - *
   17.12 - *   1. Redistributions of source code must retain the above copyright
   17.13 - *      notice, this list of conditions and the following disclaimer.
   17.14 - *
   17.15 - *   2. Redistributions in binary form must reproduce the above copyright
   17.16 - *      notice, this list of conditions and the following disclaimer in the
   17.17 - *      documentation and/or other materials provided with the distribution.
   17.18 - *
   17.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   17.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   17.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   17.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   17.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   17.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   17.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   17.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   17.29 - * POSSIBILITY OF SUCH DAMAGE.
   17.30 - */
   17.31 -
   17.32 -#ifndef UCX_UTIL_ALLOCATOR_H
   17.33 -#define UCX_UTIL_ALLOCATOR_H
   17.34 -
   17.35 -#include "cx/allocator.h"
   17.36 -
   17.37 -#include <set>
   17.38 -
   17.39 -struct CxTestingAllocator : public CxAllocator {
   17.40 -    /**
   17.41 -     * Total number of all allocations (malloc, calloc, realloc).
   17.42 -     * A realloc() does only count when the memory has to be moved.
   17.43 -     */
   17.44 -    unsigned alloc_total = 0;
   17.45 -    /**
   17.46 -     * Number of failed allocations (malloc, calloc, realloc).
   17.47 -     */
   17.48 -    unsigned alloc_failed = 0;
   17.49 -    /**
   17.50 -     * Total number of freed pointers.
   17.51 -     * A reallocation also counts as a free when the memory has to be moved.
   17.52 -     */
   17.53 -    unsigned free_total = 0;
   17.54 -    /**
   17.55 -     * Number of failed free invocations.
   17.56 -     * A free() is considered failed, if it has not been performed on tracked memory.
   17.57 -     */
   17.58 -    unsigned free_failed = 0;
   17.59 -    /**
   17.60 -     * The set of tracked memory blocks.
   17.61 -     */
   17.62 -    std::set<void *> tracked;
   17.63 -
   17.64 -    /**
   17.65 -     * Constructs a new testing allocator.
   17.66 -     */
   17.67 -    CxTestingAllocator();
   17.68 -
   17.69 -    /**
   17.70 -     * Verifies that this allocator has been used.
   17.71 -     *
   17.72 -     * @return true if any allocation was attempted using this allocator
   17.73 -     */
   17.74 -    [[nodiscard]] bool used() const;
   17.75 -
   17.76 -    /**
   17.77 -     * Verifies that all allocated memory blocks are freed and no free occurred twice.
   17.78 -     *
   17.79 -     * @return true iff all tracked allocations / deallocations were valid
   17.80 -     */
   17.81 -    [[nodiscard]] bool verify() const;
   17.82 -};
   17.83 -
   17.84 -#endif // UCX_UTIL_ALLOCATOR_H
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tests/.clang-tidy	Tue Feb 07 21:55:37 2023 +0100
    18.3 @@ -0,0 +1,2 @@
    18.4 +# Disable static initialization warning for test code
    18.5 +Checks: '-cert-err58-cpp'
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tests/CMakeLists.txt	Tue Feb 07 21:55:37 2023 +0100
    19.3 @@ -0,0 +1,32 @@
    19.4 +# Load Google Test Framework
    19.5 +set(CMAKE_CXX_STANDARD 17)
    19.6 +
    19.7 +include(FetchContent)
    19.8 +FetchContent_Declare(
    19.9 +        googletest
   19.10 +        GIT_REPOSITORY https://github.com/google/googletest.git
   19.11 +        GIT_TAG e2239ee6043f73722e7aa812a459f54a28552929 # release 1.11.0
   19.12 +)
   19.13 +# For Windows: Prevent overriding the parent project's compiler/linker settings
   19.14 +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
   19.15 +FetchContent_MakeAvailable(googletest)
   19.16 +include(GoogleTest)
   19.17 +message(STATUS "Google Test made available")
   19.18 +
   19.19 +add_executable(ucxtest
   19.20 +        test_utils.cpp
   19.21 +        test_allocator.cpp
   19.22 +        test_compare.cpp
   19.23 +        test_string.cpp
   19.24 +        test_buffer.cpp
   19.25 +        test_list.cpp
   19.26 +        test_tree.cpp
   19.27 +        test_hash_key.cpp
   19.28 +        test_map.cpp
   19.29 +        test_basic_mempool.cpp
   19.30 +        test_printf.cpp
   19.31 +        selftest.cpp
   19.32 +        util_allocator.cpp
   19.33 +        )
   19.34 +target_link_libraries(ucxtest PRIVATE ucx_static gtest_main)
   19.35 +gtest_discover_tests(ucxtest)
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tests/selftest.cpp	Tue Feb 07 21:55:37 2023 +0100
    20.3 @@ -0,0 +1,39 @@
    20.4 +/*
    20.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    20.6 + *
    20.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    20.8 + *
    20.9 + * Redistribution and use in source and binary forms, with or without
   20.10 + * modification, are permitted provided that the following conditions are met:
   20.11 + *
   20.12 + *   1. Redistributions of source code must retain the above copyright
   20.13 + *      notice, this list of conditions and the following disclaimer.
   20.14 + *
   20.15 + *   2. Redistributions in binary form must reproduce the above copyright
   20.16 + *      notice, this list of conditions and the following disclaimer in the
   20.17 + *      documentation and/or other materials provided with the distribution.
   20.18 + *
   20.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   20.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   20.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   20.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   20.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   20.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   20.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   20.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   20.29 + * POSSIBILITY OF SUCH DAMAGE.
   20.30 + */
   20.31 +
   20.32 +#include <gtest/gtest.h>
   20.33 +#include <cx/common.h>
   20.34 +
   20.35 +TEST(SelfTest, BasicAssertion) {
   20.36 +    EXPECT_EQ(7 * 6, 42);
   20.37 +}
   20.38 +
   20.39 +TEST(SelfTest, UcxVersion) {
   20.40 +    EXPECT_GE(UCX_VERSION_MAJOR, 3);
   20.41 +    EXPECT_GE(UCX_VERSION, 3 << 16);
   20.42 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tests/test_allocator.cpp	Tue Feb 07 21:55:37 2023 +0100
    21.3 @@ -0,0 +1,96 @@
    21.4 +/*
    21.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    21.6 + *
    21.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    21.8 + *
    21.9 + * Redistribution and use in source and binary forms, with or without
   21.10 + * modification, are permitted provided that the following conditions are met:
   21.11 + *
   21.12 + *   1. Redistributions of source code must retain the above copyright
   21.13 + *      notice, this list of conditions and the following disclaimer.
   21.14 + *
   21.15 + *   2. Redistributions in binary form must reproduce the above copyright
   21.16 + *      notice, this list of conditions and the following disclaimer in the
   21.17 + *      documentation and/or other materials provided with the distribution.
   21.18 + *
   21.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   21.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   21.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   21.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   21.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   21.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   21.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   21.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   21.29 + * POSSIBILITY OF SUCH DAMAGE.
   21.30 + */
   21.31 +
   21.32 +#include "cx/allocator.h"
   21.33 +#include <gtest/gtest.h>
   21.34 +
   21.35 +TEST(Allocator, DefaultAllocator) {
   21.36 +    cx_allocator_class *clazz = cxDefaultAllocator->cl;
   21.37 +    ASSERT_NE(clazz, nullptr);
   21.38 +}
   21.39 +
   21.40 +TEST(Allocator, DefaultMalloc) {
   21.41 +    void *test = cxMalloc(cxDefaultAllocator, 16);
   21.42 +    ASSERT_NE(test, nullptr);
   21.43 +    free(test);
   21.44 +}
   21.45 +
   21.46 +TEST(Allocator, DefaultRealloc) {
   21.47 +    void *test = calloc(8, 1);
   21.48 +    memcpy(test, "Test", 5);
   21.49 +    test = cxRealloc(cxDefaultAllocator, test, 16);
   21.50 +    ASSERT_NE(test, nullptr);
   21.51 +    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
   21.52 +    free(test);
   21.53 +}
   21.54 +
   21.55 +TEST(Allocator, Reallocate) {
   21.56 +    void *test = calloc(8, 1);
   21.57 +    memcpy(test, "Test", 5);
   21.58 +    int ret = cxReallocate(cxDefaultAllocator, &test, 16);
   21.59 +    EXPECT_EQ(ret, 0);
   21.60 +    ASSERT_NE(test, nullptr);
   21.61 +    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
   21.62 +    free(test);
   21.63 +}
   21.64 +
   21.65 +TEST(Allocator, DefaultCalloc) {
   21.66 +    char *test = reinterpret_cast<char *>(cxCalloc(cxDefaultAllocator, 8, 2));
   21.67 +    ASSERT_NE(test, nullptr);
   21.68 +    for (int i = 0; i < 16; i++) ASSERT_EQ(test[i], 0);
   21.69 +    free(test);
   21.70 +}
   21.71 +
   21.72 +TEST(Allocator, DefaultFree) {
   21.73 +    void *test = malloc(16);
   21.74 +    EXPECT_NO_FATAL_FAILURE(
   21.75 +            cxFree(cxDefaultAllocator, test);
   21.76 +    );
   21.77 +}
   21.78 +
   21.79 +TEST(Allocator, FailingReallocate) {
   21.80 +    // Mock an allocator that always returns nullptr on realloc
   21.81 +    cx_allocator_class mock_cl;
   21.82 +    mock_cl.realloc = [](
   21.83 +            [[maybe_unused]]void *p,
   21.84 +            [[maybe_unused]]void *d,
   21.85 +            [[maybe_unused]]size_t n
   21.86 +    ) -> void * { return nullptr; };
   21.87 +    cx_allocator_s mock{&mock_cl, nullptr};
   21.88 +
   21.89 +    void *test = calloc(8, 1);
   21.90 +    memcpy(test, "Test", 5);
   21.91 +    void *original = test;
   21.92 +    int ret = cxReallocate(&mock, &test, 16);
   21.93 +    // non-zero return code because of the failure
   21.94 +    EXPECT_NE(ret, 0);
   21.95 +    // the test pointer was not changed and still points to the same memory
   21.96 +    EXPECT_EQ(test, original);
   21.97 +    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
   21.98 +    free(test);
   21.99 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/tests/test_basic_mempool.cpp	Tue Feb 07 21:55:37 2023 +0100
    22.3 @@ -0,0 +1,154 @@
    22.4 +/*
    22.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    22.6 + *
    22.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    22.8 + *
    22.9 + * Redistribution and use in source and binary forms, with or without
   22.10 + * modification, are permitted provided that the following conditions are met:
   22.11 + *
   22.12 + *   1. Redistributions of source code must retain the above copyright
   22.13 + *      notice, this list of conditions and the following disclaimer.
   22.14 + *
   22.15 + *   2. Redistributions in binary form must reproduce the above copyright
   22.16 + *      notice, this list of conditions and the following disclaimer in the
   22.17 + *      documentation and/or other materials provided with the distribution.
   22.18 + *
   22.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   22.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   22.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   22.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   22.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   22.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   22.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   22.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   22.29 + * POSSIBILITY OF SUCH DAMAGE.
   22.30 + */
   22.31 +
   22.32 +#include "cx/basic_mempool.h"
   22.33 +#include "util_allocator.h"
   22.34 +#include <gtest/gtest.h>
   22.35 +
   22.36 +class CxBasicMempool : public ::testing::Test {
   22.37 +protected:
   22.38 +    CxMempool *pool = nullptr;
   22.39 +
   22.40 +    void TearDown() override {
   22.41 +        if (pool != nullptr) {
   22.42 +            cxMempoolDestroy(pool);
   22.43 +        }
   22.44 +    }
   22.45 +};
   22.46 +
   22.47 +TEST_F(CxBasicMempool, Create) {
   22.48 +    pool = cxBasicMempoolCreate(16);
   22.49 +    ASSERT_NE(pool->allocator, nullptr);
   22.50 +    ASSERT_NE(pool->cl, nullptr);
   22.51 +    EXPECT_NE(pool->cl->destroy, nullptr);
   22.52 +    ASSERT_NE(pool->allocator->cl, nullptr);
   22.53 +    EXPECT_EQ(pool->allocator->data, pool);
   22.54 +    EXPECT_NE(pool->allocator->cl->malloc, nullptr);
   22.55 +    EXPECT_NE(pool->allocator->cl->calloc, nullptr);
   22.56 +    EXPECT_NE(pool->allocator->cl->realloc, nullptr);
   22.57 +    EXPECT_NE(pool->allocator->cl->free, nullptr);
   22.58 +
   22.59 +    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
   22.60 +    EXPECT_EQ(basic_pool->size, 16);
   22.61 +    EXPECT_EQ(basic_pool->ndata, 0);
   22.62 +    EXPECT_NE(basic_pool->data, nullptr);
   22.63 +}
   22.64 +
   22.65 +TEST_F(CxBasicMempool, malloc) {
   22.66 +    pool = cxBasicMempoolCreate(4);
   22.67 +    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
   22.68 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   22.69 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   22.70 +    EXPECT_EQ(basic_pool->ndata, 2);
   22.71 +    EXPECT_EQ(basic_pool->size, 4);
   22.72 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   22.73 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   22.74 +    EXPECT_EQ(basic_pool->ndata, 4);
   22.75 +    EXPECT_EQ(basic_pool->size, 4);
   22.76 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   22.77 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   22.78 +    EXPECT_EQ(basic_pool->ndata, 6);
   22.79 +    EXPECT_GE(basic_pool->size, 6);
   22.80 +}
   22.81 +
   22.82 +TEST_F(CxBasicMempool, calloc) {
   22.83 +    pool = cxBasicMempoolCreate(4);
   22.84 +
   22.85 +    auto test = (int *) cxCalloc(pool->allocator, 2, sizeof(int));
   22.86 +    ASSERT_NE(test, nullptr);
   22.87 +    EXPECT_EQ(test[0], 0);
   22.88 +    EXPECT_EQ(test[1], 0);
   22.89 +}
   22.90 +
   22.91 +static unsigned test_destructor_called = 0;
   22.92 +
   22.93 +static void test_destructor([[maybe_unused]] void *mem) {
   22.94 +    test_destructor_called++;
   22.95 +}
   22.96 +
   22.97 +TEST_F(CxBasicMempool, destructor) {
   22.98 +    pool = cxBasicMempoolCreate(4);
   22.99 +    auto data = cxMalloc(pool->allocator, sizeof(int));
  22.100 +    *((int *) data) = 13;
  22.101 +    cxMempoolSetDestructor(pool, data, test_destructor);
  22.102 +    EXPECT_EQ(*((int *) data), 13);
  22.103 +    test_destructor_called = 0;
  22.104 +    cxFree(pool->allocator, data);
  22.105 +    EXPECT_EQ(test_destructor_called, 1);
  22.106 +    data = cxMalloc(pool->allocator, sizeof(int));
  22.107 +    cxMempoolSetDestructor(pool, data, test_destructor);
  22.108 +    cxMempoolDestroy(pool);
  22.109 +    pool = nullptr;
  22.110 +    EXPECT_EQ(test_destructor_called, 2);
  22.111 +}
  22.112 +
  22.113 +TEST_F(CxBasicMempool, realloc) {
  22.114 +    pool = cxBasicMempoolCreate(4);
  22.115 +    auto data = cxMalloc(pool->allocator, sizeof(int));
  22.116 +    *((int *) data) = 13;
  22.117 +    cxMempoolSetDestructor(pool, data, test_destructor);
  22.118 +
  22.119 +    void *rdata = data;
  22.120 +    unsigned n = 1;
  22.121 +    while (rdata == data) {
  22.122 +        n <<= 1;
  22.123 +        ASSERT_LT(n, 65536); // eventually the memory should be moved elsewhere
  22.124 +        rdata = cxRealloc(pool->allocator, data, n * sizeof(intptr_t));
  22.125 +    }
  22.126 +
  22.127 +    EXPECT_EQ(*((int *) rdata), 13);
  22.128 +    // test if destructor is still intact
  22.129 +    test_destructor_called = 0;
  22.130 +    cxFree(pool->allocator, rdata);
  22.131 +    EXPECT_EQ(test_destructor_called, 1);
  22.132 +}
  22.133 +
  22.134 +
  22.135 +TEST_F(CxBasicMempool, free) {
  22.136 +    pool = cxBasicMempoolCreate(4);
  22.137 +    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
  22.138 +
  22.139 +    void *mem1;
  22.140 +    void *mem2;
  22.141 +
  22.142 +    mem1 = cxMalloc(pool->allocator, 16);
  22.143 +    cxFree(pool->allocator, mem1);
  22.144 +    EXPECT_EQ(basic_pool->ndata, 0);
  22.145 +
  22.146 +    cxMalloc(pool->allocator, 16);
  22.147 +    cxMalloc(pool->allocator, 16);
  22.148 +    mem1 = cxMalloc(pool->allocator, 16);
  22.149 +    cxMalloc(pool->allocator, 16);
  22.150 +    mem2 = cxMalloc(pool->allocator, 16);
  22.151 +
  22.152 +    EXPECT_EQ(basic_pool->ndata, 5);
  22.153 +    cxFree(pool->allocator, mem1);
  22.154 +    EXPECT_EQ(basic_pool->ndata, 4);
  22.155 +    cxFree(pool->allocator, mem2);
  22.156 +    EXPECT_EQ(basic_pool->ndata, 3);
  22.157 +}
  22.158 \ No newline at end of file
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/tests/test_buffer.cpp	Tue Feb 07 21:55:37 2023 +0100
    23.3 @@ -0,0 +1,815 @@
    23.4 +/*
    23.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    23.6 + *
    23.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    23.8 + *
    23.9 + * Redistribution and use in source and binary forms, with or without
   23.10 + * modification, are permitted provided that the following conditions are met:
   23.11 + *
   23.12 + *   1. Redistributions of source code must retain the above copyright
   23.13 + *      notice, this list of conditions and the following disclaimer.
   23.14 + *
   23.15 + *   2. Redistributions in binary form must reproduce the above copyright
   23.16 + *      notice, this list of conditions and the following disclaimer in the
   23.17 + *      documentation and/or other materials provided with the distribution.
   23.18 + *
   23.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   23.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   23.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   23.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   23.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   23.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   23.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   23.29 + * POSSIBILITY OF SUCH DAMAGE.
   23.30 + */
   23.31 +
   23.32 +#include "cx/buffer.h"
   23.33 +
   23.34 +#include <gtest/gtest.h>
   23.35 +#include "util_allocator.h"
   23.36 +
   23.37 +class BufferFixture : public ::testing::Test {
   23.38 +protected:
   23.39 +    void SetUp() override {
   23.40 +        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   23.41 +        buf.size = 6;
   23.42 +        buf.pos = 3;
   23.43 +    }
   23.44 +
   23.45 +    void TearDown() override {
   23.46 +        cxBufferDestroy(&buf);
   23.47 +    }
   23.48 +
   23.49 +    CxBuffer buf{};
   23.50 +};
   23.51 +
   23.52 +static void expect_default_flush_config(CxBuffer *buf) {
   23.53 +    EXPECT_EQ(buf->flush_blkmax, 0);
   23.54 +    EXPECT_EQ(buf->flush_blksize, 4096);
   23.55 +    EXPECT_EQ(buf->flush_threshold, SIZE_MAX);
   23.56 +    EXPECT_EQ(buf->flush_func, nullptr);
   23.57 +    EXPECT_EQ(buf->flush_target, nullptr);
   23.58 +}
   23.59 +
   23.60 +TEST(BufferInit, WrapSpace) {
   23.61 +    CxTestingAllocator alloc;
   23.62 +    CxBuffer buf;
   23.63 +    void *space = cxMalloc(&alloc, 16);
   23.64 +    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_DEFAULT);
   23.65 +    expect_default_flush_config(&buf);
   23.66 +    EXPECT_EQ(buf.space, space);
   23.67 +    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
   23.68 +    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
   23.69 +    EXPECT_EQ(buf.pos, 0);
   23.70 +    EXPECT_EQ(buf.size, 0);
   23.71 +    EXPECT_EQ(buf.capacity, 16);
   23.72 +    EXPECT_EQ(buf.allocator, &alloc);
   23.73 +    cxBufferDestroy(&buf);
   23.74 +    EXPECT_FALSE(alloc.verify());
   23.75 +    cxFree(&alloc, space);
   23.76 +    EXPECT_TRUE(alloc.verify());
   23.77 +}
   23.78 +
   23.79 +TEST(BufferInit, WrapSpaceAutoExtend) {
   23.80 +    CxTestingAllocator alloc;
   23.81 +    CxBuffer buf;
   23.82 +    void *space = cxMalloc(&alloc, 16);
   23.83 +    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_AUTO_EXTEND);
   23.84 +    expect_default_flush_config(&buf);
   23.85 +    EXPECT_EQ(buf.space, space);
   23.86 +    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, CX_BUFFER_AUTO_EXTEND);
   23.87 +    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
   23.88 +    EXPECT_EQ(buf.pos, 0);
   23.89 +    EXPECT_EQ(buf.size, 0);
   23.90 +    EXPECT_EQ(buf.capacity, 16);
   23.91 +    EXPECT_EQ(buf.allocator, &alloc);
   23.92 +    cxBufferDestroy(&buf);
   23.93 +    EXPECT_FALSE(alloc.verify());
   23.94 +    cxFree(&alloc, space);
   23.95 +    EXPECT_TRUE(alloc.verify());
   23.96 +}
   23.97 +
   23.98 +TEST(BufferInit, WrapSpaceAutoFree) {
   23.99 +    CxTestingAllocator alloc;
  23.100 +    CxBuffer buf;
  23.101 +    void *space = cxMalloc(&alloc, 16);
  23.102 +    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_FREE_CONTENTS);
  23.103 +    expect_default_flush_config(&buf);
  23.104 +    EXPECT_EQ(buf.space, space);
  23.105 +    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
  23.106 +    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
  23.107 +    EXPECT_EQ(buf.pos, 0);
  23.108 +    EXPECT_EQ(buf.size, 0);
  23.109 +    EXPECT_EQ(buf.capacity, 16);
  23.110 +    EXPECT_EQ(buf.allocator, &alloc);
  23.111 +    EXPECT_FALSE(alloc.verify());
  23.112 +    cxBufferDestroy(&buf);
  23.113 +    EXPECT_TRUE(alloc.verify());
  23.114 +}
  23.115 +
  23.116 +TEST(BufferInit, FreshSpace) {
  23.117 +    CxTestingAllocator alloc;
  23.118 +    CxBuffer buf;
  23.119 +    cxBufferInit(&buf, nullptr, 8, &alloc, CX_BUFFER_DEFAULT);
  23.120 +    expect_default_flush_config(&buf);
  23.121 +    EXPECT_NE(buf.space, nullptr);
  23.122 +    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
  23.123 +    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
  23.124 +    EXPECT_EQ(buf.pos, 0);
  23.125 +    EXPECT_EQ(buf.size, 0);
  23.126 +    EXPECT_EQ(buf.capacity, 8);
  23.127 +    EXPECT_EQ(buf.allocator, &alloc);
  23.128 +    EXPECT_FALSE(alloc.verify()); // space is still allocated
  23.129 +    cxBufferDestroy(&buf);
  23.130 +    EXPECT_TRUE(alloc.verify());
  23.131 +}
  23.132 +
  23.133 +class BufferShiftFixture : public ::testing::Test {
  23.134 +protected:
  23.135 +    void SetUp() override {
  23.136 +        ASSERT_TRUE(alloc.verify());
  23.137 +        cxBufferInit(&buf, nullptr, 16, &alloc, CX_BUFFER_DEFAULT);
  23.138 +        memcpy(buf.space, "test____________", 16);
  23.139 +        buf.capacity = 8; // purposely pretend that the buffer has less capacity s.t. we can test beyond the range
  23.140 +        buf.pos = 4;
  23.141 +        buf.size = 4;
  23.142 +    }
  23.143 +
  23.144 +    void TearDown() override {
  23.145 +        cxBufferDestroy(&buf);
  23.146 +        EXPECT_TRUE(alloc.verify());
  23.147 +    }
  23.148 +
  23.149 +    CxTestingAllocator alloc;
  23.150 +    CxBuffer buf{};
  23.151 +};
  23.152 +
  23.153 +class BufferShiftLeft : public BufferShiftFixture {
  23.154 +};
  23.155 +
  23.156 +TEST_F(BufferShiftLeft, Zero) {
  23.157 +    ASSERT_EQ(buf.pos, 4);
  23.158 +    ASSERT_EQ(buf.size, 4);
  23.159 +    int ret = cxBufferShiftLeft(&buf, 0);
  23.160 +    EXPECT_EQ(ret, 0);
  23.161 +    EXPECT_EQ(buf.pos, 4);
  23.162 +    EXPECT_EQ(buf.size, 4);
  23.163 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  23.164 +}
  23.165 +
  23.166 +TEST_F(BufferShiftLeft, ZeroOffsetInterface) {
  23.167 +    ASSERT_EQ(buf.pos, 4);
  23.168 +    ASSERT_EQ(buf.size, 4);
  23.169 +    int ret = cxBufferShift(&buf, -0);
  23.170 +    EXPECT_EQ(ret, 0);
  23.171 +    EXPECT_EQ(buf.pos, 4);
  23.172 +    EXPECT_EQ(buf.size, 4);
  23.173 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  23.174 +}
  23.175 +
  23.176 +TEST_F(BufferShiftLeft, Standard) {
  23.177 +    ASSERT_EQ(buf.pos, 4);
  23.178 +    ASSERT_EQ(buf.size, 4);
  23.179 +    int ret = cxBufferShiftLeft(&buf, 2);
  23.180 +    EXPECT_EQ(ret, 0);
  23.181 +    EXPECT_EQ(buf.pos, 2);
  23.182 +    EXPECT_EQ(buf.size, 2);
  23.183 +    EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
  23.184 +}
  23.185 +
  23.186 +TEST_F(BufferShiftLeft, Overshift) {
  23.187 +    ASSERT_LT(buf.pos, 6);
  23.188 +    ASSERT_LT(buf.size, 6);
  23.189 +    int ret = cxBufferShiftLeft(&buf, 6);
  23.190 +    EXPECT_EQ(ret, 0);
  23.191 +    EXPECT_EQ(buf.pos, 0);
  23.192 +    EXPECT_EQ(buf.size, 0);
  23.193 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  23.194 +}
  23.195 +
  23.196 +TEST_F(BufferShiftLeft, OvershiftPosOnly) {
  23.197 +    buf.pos = 2;
  23.198 +    ASSERT_EQ(buf.size, 4);
  23.199 +    int ret = cxBufferShiftLeft(&buf, 3);
  23.200 +    EXPECT_EQ(ret, 0);
  23.201 +    EXPECT_EQ(buf.pos, 0);
  23.202 +    EXPECT_EQ(buf.size, 1);
  23.203 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  23.204 +}
  23.205 +
  23.206 +TEST_F(BufferShiftLeft, OffsetInterface) {
  23.207 +    buf.pos = 3;
  23.208 +    ASSERT_EQ(buf.size, 4);
  23.209 +    int ret = cxBufferShift(&buf, -2);
  23.210 +    EXPECT_EQ(ret, 0);
  23.211 +    EXPECT_EQ(buf.pos, 1);
  23.212 +    EXPECT_EQ(buf.size, 2);
  23.213 +    EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
  23.214 +}
  23.215 +
  23.216 +class BufferShiftRight : public BufferShiftFixture {
  23.217 +};
  23.218 +
  23.219 +TEST_F(BufferShiftRight, Zero) {
  23.220 +    ASSERT_EQ(buf.pos, 4);
  23.221 +    ASSERT_EQ(buf.size, 4);
  23.222 +    int ret = cxBufferShiftRight(&buf, 0);
  23.223 +    EXPECT_EQ(ret, 0);
  23.224 +    EXPECT_EQ(buf.pos, 4);
  23.225 +    EXPECT_EQ(buf.size, 4);
  23.226 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  23.227 +}
  23.228 +
  23.229 +TEST_F(BufferShiftRight, ZeroOffsetInterface) {
  23.230 +    ASSERT_EQ(buf.pos, 4);
  23.231 +    ASSERT_EQ(buf.size, 4);
  23.232 +    int ret = cxBufferShift(&buf, +0);
  23.233 +    EXPECT_EQ(ret, 0);
  23.234 +    EXPECT_EQ(buf.pos, 4);
  23.235 +    EXPECT_EQ(buf.size, 4);
  23.236 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  23.237 +}
  23.238 +
  23.239 +TEST_F(BufferShiftRight, Standard) {
  23.240 +    ASSERT_EQ(buf.pos, 4);
  23.241 +    ASSERT_EQ(buf.size, 4);
  23.242 +    int ret = cxBufferShiftRight(&buf, 3);
  23.243 +    EXPECT_EQ(ret, 0);
  23.244 +    EXPECT_EQ(buf.pos, 7);
  23.245 +    EXPECT_EQ(buf.size, 7);
  23.246 +    EXPECT_TRUE(memcmp(buf.space, "testest_____", 8) == 0);
  23.247 +}
  23.248 +
  23.249 +TEST_F(BufferShiftRight, OvershiftDiscard) {
  23.250 +    ASSERT_EQ(buf.pos, 4);
  23.251 +    ASSERT_EQ(buf.size, 4);
  23.252 +    ASSERT_EQ(buf.capacity, 8);
  23.253 +    int ret = cxBufferShiftRight(&buf, 6);
  23.254 +    EXPECT_EQ(ret, 0);
  23.255 +    EXPECT_EQ(buf.pos, 8);
  23.256 +    EXPECT_EQ(buf.size, 8);
  23.257 +    EXPECT_EQ(buf.capacity, 8);
  23.258 +    EXPECT_TRUE(memcmp(buf.space, "test__te____", 8) == 0);
  23.259 +}
  23.260 +
  23.261 +TEST_F(BufferShiftRight, OvershiftExtend) {
  23.262 +    ASSERT_EQ(buf.pos, 4);
  23.263 +    ASSERT_EQ(buf.size, 4);
  23.264 +    ASSERT_EQ(buf.capacity, 8);
  23.265 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  23.266 +    int ret = cxBufferShiftRight(&buf, 6);
  23.267 +    EXPECT_EQ(ret, 0);
  23.268 +    EXPECT_EQ(buf.pos, 10);
  23.269 +    EXPECT_EQ(buf.size, 10);
  23.270 +    EXPECT_GE(buf.capacity, 10);
  23.271 +    EXPECT_TRUE(memcmp(buf.space, "test__test__", 8) == 0);
  23.272 +}
  23.273 +
  23.274 +TEST_F(BufferShiftRight, OffsetInterface) {
  23.275 +    buf.pos = 3;
  23.276 +    ASSERT_EQ(buf.size, 4);
  23.277 +    int ret = cxBufferShift(&buf, 2);
  23.278 +    EXPECT_EQ(ret, 0);
  23.279 +    EXPECT_EQ(buf.pos, 5);
  23.280 +    EXPECT_EQ(buf.size, 6);
  23.281 +    EXPECT_TRUE(memcmp(buf.space, "tetest______", 8) == 0);
  23.282 +}
  23.283 +
  23.284 +TEST(BufferMinimumCapacity, Sufficient) {
  23.285 +    CxTestingAllocator alloc;
  23.286 +    auto space = cxMalloc(&alloc, 8);
  23.287 +    CxBuffer buf;
  23.288 +    cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS);
  23.289 +    memcpy(space, "Testing", 8);
  23.290 +    buf.size = 8;
  23.291 +    cxBufferMinimumCapacity(&buf, 6);
  23.292 +    EXPECT_EQ(buf.capacity, 8);
  23.293 +    EXPECT_EQ(buf.size, 8);
  23.294 +    EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
  23.295 +    cxBufferDestroy(&buf);
  23.296 +    EXPECT_TRUE(alloc.verify());
  23.297 +}
  23.298 +
  23.299 +TEST(BufferMinimumCapacity, Extend) {
  23.300 +    CxTestingAllocator alloc;
  23.301 +    auto space = cxMalloc(&alloc, 8);
  23.302 +    CxBuffer buf;
  23.303 +    cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS); // NO auto extend!
  23.304 +    memcpy(space, "Testing", 8);
  23.305 +    buf.size = 8;
  23.306 +    cxBufferMinimumCapacity(&buf, 16);
  23.307 +    EXPECT_EQ(buf.capacity, 16);
  23.308 +    EXPECT_EQ(buf.size, 8);
  23.309 +    EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
  23.310 +    cxBufferDestroy(&buf);
  23.311 +    EXPECT_TRUE(alloc.verify());
  23.312 +}
  23.313 +
  23.314 +TEST(BufferClear, Test) {
  23.315 +    char space[16];
  23.316 +    strcpy(space, "clear test");
  23.317 +    CxBuffer buf;
  23.318 +    cxBufferInit(&buf, space, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
  23.319 +    ASSERT_EQ(buf.size, 0);
  23.320 +    // only clear the used part of the buffer
  23.321 +    cxBufferClear(&buf);
  23.322 +    EXPECT_EQ(memcmp(space, "clear test", 10), 0);
  23.323 +    buf.size = 5;
  23.324 +    buf.pos = 3;
  23.325 +    cxBufferClear(&buf);
  23.326 +    EXPECT_EQ(memcmp(space, "\0\0\0\0\0 test", 10), 0);
  23.327 +    EXPECT_EQ(buf.size, 0);
  23.328 +    EXPECT_EQ(buf.pos, 0);
  23.329 +    cxBufferDestroy(&buf);
  23.330 +}
  23.331 +
  23.332 +class BufferWrite : public ::testing::Test {
  23.333 +protected:
  23.334 +    CxBuffer buf{}, target{};
  23.335 +
  23.336 +    void SetUp() override {
  23.337 +        cxBufferInit(&target, nullptr, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
  23.338 +        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
  23.339 +        buf.capacity = 8; // artificially reduce capacity to check OOB writes
  23.340 +        memset(buf.space, 0, 16);
  23.341 +        memcpy(buf.space, "prep", 4);
  23.342 +        buf.size = buf.pos = 4;
  23.343 +    }
  23.344 +
  23.345 +    void TearDown() override {
  23.346 +        cxBufferDestroy(&buf);
  23.347 +        cxBufferDestroy(&target);
  23.348 +    }
  23.349 +
  23.350 +    void enableFlushing() {
  23.351 +        buf.flush_target = &target;
  23.352 +        buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
  23.353 +        buf.flush_blkmax = 1;
  23.354 +    }
  23.355 +};
  23.356 +
  23.357 +static size_t mock_write_limited_rate(
  23.358 +        void const *ptr,
  23.359 +        size_t size,
  23.360 +        __attribute__((unused)) size_t nitems,
  23.361 +        CxBuffer *buffer
  23.362 +) {
  23.363 +    // simulate limited target drain capacity
  23.364 +    static bool full = false;
  23.365 +    if (full) {
  23.366 +        full = false;
  23.367 +        return 0;
  23.368 +    } else {
  23.369 +        full = true;
  23.370 +        return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
  23.371 +    }
  23.372 +}
  23.373 +
  23.374 +TEST_F(BufferWrite, SizeOneFit) {
  23.375 +    const char *data = "test";
  23.376 +    ASSERT_EQ(buf.capacity, 8);
  23.377 +    ASSERT_EQ(buf.pos, 4);
  23.378 +    ASSERT_EQ(buf.size, 4);
  23.379 +    size_t written = cxBufferWrite(data, 1, 4, &buf);
  23.380 +    EXPECT_EQ(written, 4);
  23.381 +    EXPECT_EQ(buf.size, 8);
  23.382 +    EXPECT_EQ(buf.pos, 8);
  23.383 +    EXPECT_EQ(buf.capacity, 8);
  23.384 +    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
  23.385 +}
  23.386 +
  23.387 +TEST_F(BufferWrite, SizeOneDiscard) {
  23.388 +    const char *data = "testing";
  23.389 +    ASSERT_EQ(buf.capacity, 8);
  23.390 +    ASSERT_EQ(buf.pos, 4);
  23.391 +    ASSERT_EQ(buf.size, 4);
  23.392 +    size_t written = cxBufferWrite(data, 1, 7, &buf);
  23.393 +    EXPECT_EQ(written, 4);
  23.394 +    EXPECT_EQ(buf.size, 8);
  23.395 +    EXPECT_EQ(buf.pos, 8);
  23.396 +    EXPECT_EQ(buf.capacity, 8);
  23.397 +    EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
  23.398 +}
  23.399 +
  23.400 +TEST_F(BufferWrite, SizeOneExtend) {
  23.401 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  23.402 +    const char *data = "testing";
  23.403 +    ASSERT_EQ(buf.capacity, 8);
  23.404 +    ASSERT_EQ(buf.pos, 4);
  23.405 +    ASSERT_EQ(buf.size, 4);
  23.406 +    size_t written = cxBufferWrite(data, 1, 7, &buf);
  23.407 +    EXPECT_EQ(written, 7);
  23.408 +    EXPECT_EQ(buf.size, 11);
  23.409 +    EXPECT_EQ(buf.pos, 11);
  23.410 +    EXPECT_GE(buf.capacity, 11);
  23.411 +    EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
  23.412 +}
  23.413 +
  23.414 +TEST_F(BufferWrite, MultibyteFit) {
  23.415 +    const char *data = "test";
  23.416 +    ASSERT_EQ(buf.capacity, 8);
  23.417 +    ASSERT_EQ(buf.pos, 4);
  23.418 +    ASSERT_EQ(buf.size, 4);
  23.419 +    size_t written = cxBufferWrite(data, 2, 2, &buf);
  23.420 +    EXPECT_EQ(written, 2);
  23.421 +    EXPECT_EQ(buf.size, 8);
  23.422 +    EXPECT_EQ(buf.pos, 8);
  23.423 +    EXPECT_EQ(buf.capacity, 8);
  23.424 +    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
  23.425 +}
  23.426 +
  23.427 +TEST_F(BufferWrite, MultibyteDiscard) {
  23.428 +    const char *data = "testing";
  23.429 +    ASSERT_EQ(buf.capacity, 8);
  23.430 +    ASSERT_EQ(buf.size, 4);
  23.431 +    buf.pos = 3;
  23.432 +    size_t written = cxBufferWrite(data, 2, 4, &buf);
  23.433 +    // remember: whole elements are discarded if they do not fit
  23.434 +    EXPECT_EQ(written, 2);
  23.435 +    EXPECT_EQ(buf.size, 7);
  23.436 +    EXPECT_EQ(buf.pos, 7);
  23.437 +    EXPECT_EQ(buf.capacity, 8);
  23.438 +    EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0);
  23.439 +}
  23.440 +
  23.441 +TEST_F(BufferWrite, MultibyteExtend) {
  23.442 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  23.443 +    const char *data = "tester";
  23.444 +    ASSERT_EQ(buf.capacity, 8);
  23.445 +    ASSERT_EQ(buf.size, 4);
  23.446 +    buf.pos = 3;
  23.447 +    size_t written = cxBufferWrite(data, 2, 3, &buf);
  23.448 +    // remember: whole elements are discarded if they do not fit
  23.449 +    EXPECT_EQ(written, 3);
  23.450 +    EXPECT_EQ(buf.size, 9);
  23.451 +    EXPECT_EQ(buf.pos, 9);
  23.452 +    EXPECT_GE(buf.capacity, 9);
  23.453 +    EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0);
  23.454 +}
  23.455 +
  23.456 +TEST_F(BufferWrite, PutcWrapperFit) {
  23.457 +    ASSERT_EQ(buf.capacity, 8);
  23.458 +    ASSERT_EQ(buf.pos, 4);
  23.459 +    ASSERT_EQ(buf.size, 4);
  23.460 +    int c = cxBufferPut(&buf, 0x200 | 'a');
  23.461 +    EXPECT_EQ(c, 'a');
  23.462 +    EXPECT_EQ(buf.size, 5);
  23.463 +    EXPECT_EQ(buf.pos, 5);
  23.464 +    EXPECT_EQ(buf.capacity, 8);
  23.465 +    EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0);
  23.466 +}
  23.467 +
  23.468 +TEST_F(BufferWrite, PutcWrapperDiscard) {
  23.469 +    ASSERT_EQ(buf.capacity, 8);
  23.470 +    ASSERT_EQ(buf.size, 4);
  23.471 +    buf.pos = 8;
  23.472 +    int c = cxBufferPut(&buf, 0x200 | 'a');
  23.473 +    EXPECT_EQ(c, EOF);
  23.474 +    EXPECT_EQ(buf.size, 4);
  23.475 +    EXPECT_EQ(buf.pos, 8);
  23.476 +    EXPECT_EQ(buf.capacity, 8);
  23.477 +    EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0);
  23.478 +}
  23.479 +
  23.480 +TEST_F(BufferWrite, PutcWrapperExtend) {
  23.481 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  23.482 +    ASSERT_EQ(buf.capacity, 8);
  23.483 +    ASSERT_EQ(buf.size, 4);
  23.484 +    buf.pos = 8;
  23.485 +    int c = cxBufferPut(&buf, 0x200 | 'a');
  23.486 +    EXPECT_EQ(c, 'a');
  23.487 +    EXPECT_EQ(buf.size, 9);
  23.488 +    EXPECT_EQ(buf.pos, 9);
  23.489 +    EXPECT_GE(buf.capacity, 9);
  23.490 +    EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0);
  23.491 +}
  23.492 +
  23.493 +TEST_F(BufferWrite, PutStringWrapperFit) {
  23.494 +    const char *data = "test";
  23.495 +    ASSERT_EQ(buf.capacity, 8);
  23.496 +    ASSERT_EQ(buf.pos, 4);
  23.497 +    ASSERT_EQ(buf.size, 4);
  23.498 +    size_t written = cxBufferPutString(&buf, data);
  23.499 +    EXPECT_EQ(written, 4);
  23.500 +    EXPECT_EQ(buf.size, 8);
  23.501 +    EXPECT_EQ(buf.pos, 8);
  23.502 +    EXPECT_EQ(buf.capacity, 8);
  23.503 +    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
  23.504 +}
  23.505 +
  23.506 +TEST_F(BufferWrite, PutStringWrapperDiscard) {
  23.507 +    const char *data = "testing";
  23.508 +    ASSERT_EQ(buf.capacity, 8);
  23.509 +    ASSERT_EQ(buf.pos, 4);
  23.510 +    ASSERT_EQ(buf.size, 4);
  23.511 +    size_t written = cxBufferPutString(&buf, data);
  23.512 +    EXPECT_EQ(written, 4);
  23.513 +    EXPECT_EQ(buf.size, 8);
  23.514 +    EXPECT_EQ(buf.pos, 8);
  23.515 +    EXPECT_EQ(buf.capacity, 8);
  23.516 +    EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
  23.517 +}
  23.518 +
  23.519 +TEST_F(BufferWrite, PutStringWrapperExtend) {
  23.520 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  23.521 +    const char *data = "testing";
  23.522 +    ASSERT_EQ(buf.capacity, 8);
  23.523 +    ASSERT_EQ(buf.pos, 4);
  23.524 +    ASSERT_EQ(buf.size, 4);
  23.525 +    size_t written = cxBufferPutString(&buf, data);
  23.526 +    EXPECT_EQ(written, 7);
  23.527 +    EXPECT_EQ(buf.size, 11);
  23.528 +    EXPECT_EQ(buf.pos, 11);
  23.529 +    EXPECT_GE(buf.capacity, 11);
  23.530 +    EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
  23.531 +}
  23.532 +
  23.533 +TEST_F(BufferWrite, MultOverflow) {
  23.534 +    const char *data = "testing";
  23.535 +    ASSERT_EQ(buf.capacity, 8);
  23.536 +    ASSERT_EQ(buf.pos, 4);
  23.537 +    ASSERT_EQ(buf.size, 4);
  23.538 +    size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf);
  23.539 +    EXPECT_EQ(written, 0);
  23.540 +    EXPECT_EQ(buf.capacity, 8);
  23.541 +    EXPECT_EQ(buf.pos, 4);
  23.542 +    EXPECT_EQ(buf.size, 4);
  23.543 +    EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
  23.544 +}
  23.545 +
  23.546 +TEST_F(BufferWrite, MaxCapaOverflow) {
  23.547 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  23.548 +    const char *data = "testing";
  23.549 +    ASSERT_EQ(buf.capacity, 8);
  23.550 +    ASSERT_EQ(buf.pos, 4);
  23.551 +    ASSERT_EQ(buf.size, 4);
  23.552 +    size_t written = cxBufferWrite(data, 1, SIZE_MAX - 2, &buf);
  23.553 +    EXPECT_EQ(written, 0);
  23.554 +    EXPECT_EQ(buf.capacity, 8);
  23.555 +    EXPECT_EQ(buf.pos, 4);
  23.556 +    EXPECT_EQ(buf.size, 4);
  23.557 +    EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
  23.558 +}
  23.559 +
  23.560 +TEST_F(BufferWrite, OnlyOverwrite) {
  23.561 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  23.562 +    ASSERT_EQ(buf.capacity, 8);
  23.563 +    memcpy(buf.space, "preptest", 8);
  23.564 +    buf.pos = 3;
  23.565 +    buf.size = 8;
  23.566 +    size_t written = cxBufferWrite("XXX", 2, 2, &buf);
  23.567 +    EXPECT_EQ(written, 2);
  23.568 +    EXPECT_EQ(buf.capacity, 8);
  23.569 +    EXPECT_EQ(buf.size, 8);
  23.570 +    EXPECT_EQ(buf.pos, 7);
  23.571 +    EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0);
  23.572 +}
  23.573 +
  23.574 +TEST_F(BufferWrite, FlushAtCapacity) {
  23.575 +    enableFlushing();
  23.576 +    ASSERT_EQ(buf.capacity, 8);
  23.577 +    ASSERT_EQ(buf.pos, 4);
  23.578 +    size_t written = cxBufferWrite("foo", 1, 3, &buf);
  23.579 +    EXPECT_EQ(written, 3);
  23.580 +    ASSERT_EQ(buf.pos, 7);
  23.581 +    ASSERT_EQ(buf.size, 7);
  23.582 +    ASSERT_EQ(target.pos, 0);
  23.583 +    ASSERT_EQ(target.size, 0);
  23.584 +    written = cxBufferWrite("hello", 1, 5, &buf);
  23.585 +    EXPECT_EQ(written, 5);
  23.586 +    EXPECT_EQ(buf.pos, 0);
  23.587 +    EXPECT_EQ(buf.size, 0);
  23.588 +    EXPECT_EQ(buf.capacity, 8);
  23.589 +    EXPECT_EQ(target.pos, 12);
  23.590 +    ASSERT_EQ(target.size, 12);
  23.591 +    EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0);
  23.592 +}
  23.593 +
  23.594 +TEST_F(BufferWrite, FlushAtThreshold) {
  23.595 +    enableFlushing();
  23.596 +    buf.flush_threshold = 12;
  23.597 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  23.598 +    ASSERT_EQ(buf.capacity, 8);
  23.599 +    ASSERT_EQ(buf.pos, 4);
  23.600 +    size_t written = cxBufferWrite("foobar", 1, 6, &buf);
  23.601 +    EXPECT_EQ(written, 6);
  23.602 +    ASSERT_EQ(buf.pos, 10);
  23.603 +    ASSERT_EQ(buf.size, 10);
  23.604 +    ASSERT_GE(buf.capacity, 10);
  23.605 +    ASSERT_LE(buf.capacity, 12);
  23.606 +    ASSERT_EQ(target.pos, 0);
  23.607 +    ASSERT_EQ(target.size, 0);
  23.608 +    written = cxBufferWrite("hello", 1, 5, &buf);
  23.609 +    EXPECT_EQ(written, 5);
  23.610 +    EXPECT_EQ(buf.pos, 0);
  23.611 +    EXPECT_EQ(buf.size, 0);
  23.612 +    EXPECT_LE(buf.capacity, 12);
  23.613 +    EXPECT_EQ(target.pos, 15);
  23.614 +    ASSERT_EQ(target.size, 15);
  23.615 +    EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0);
  23.616 +}
  23.617 +
  23.618 +TEST_F(BufferWrite, FlushRateLimited) {
  23.619 +    enableFlushing();
  23.620 +    // limit the rate of the flush function and the capacity of the target
  23.621 +    target.capacity = 16;
  23.622 +    target.flags &= ~CX_BUFFER_AUTO_EXTEND;
  23.623 +    buf.flush_func = (cx_write_func) mock_write_limited_rate;
  23.624 +    ASSERT_EQ(buf.capacity, 8);
  23.625 +    ASSERT_EQ(buf.pos, 4);
  23.626 +    size_t written = cxBufferWrite("foo", 1, 3, &buf);
  23.627 +    EXPECT_EQ(written, 3);
  23.628 +    ASSERT_EQ(buf.pos, 7);
  23.629 +    ASSERT_EQ(buf.size, 7);
  23.630 +    ASSERT_EQ(target.pos, 0);
  23.631 +    ASSERT_EQ(target.size, 0);
  23.632 +    written = cxBufferWrite("hello, world!", 1, 13, &buf);
  23.633 +    // " world!" fits into this buffer, the remaining stuff is flushed out
  23.634 +    EXPECT_EQ(written, 13);
  23.635 +    EXPECT_EQ(buf.pos, 7);
  23.636 +    EXPECT_EQ(buf.size, 7);
  23.637 +    EXPECT_EQ(buf.capacity, 8);
  23.638 +    EXPECT_EQ(memcmp(buf.space, " world!", 7), 0);
  23.639 +    EXPECT_EQ(target.pos, 13);
  23.640 +    ASSERT_EQ(target.size, 13);
  23.641 +    EXPECT_EQ(target.capacity, 16);
  23.642 +    EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0);
  23.643 +}
  23.644 +
  23.645 +class BufferSeek : public BufferFixture {
  23.646 +};
  23.647 +
  23.648 +TEST_F(BufferSeek, SetZero) {
  23.649 +    int result = cxBufferSeek(&buf, 0, SEEK_SET);
  23.650 +    EXPECT_EQ(result, 0);
  23.651 +    EXPECT_EQ(buf.pos, 0);
  23.652 +}
  23.653 +
  23.654 +TEST_F(BufferSeek, SetValid) {
  23.655 +    int result = cxBufferSeek(&buf, 5, SEEK_SET);
  23.656 +    EXPECT_EQ(result, 0);
  23.657 +    EXPECT_EQ(buf.pos, 5);
  23.658 +}
  23.659 +
  23.660 +TEST_F(BufferSeek, SetInvalid) {
  23.661 +    ASSERT_EQ(buf.pos, 3);
  23.662 +    int result = cxBufferSeek(&buf, 6, SEEK_SET);
  23.663 +    EXPECT_NE(result, 0);
  23.664 +    EXPECT_EQ(buf.pos, 3);
  23.665 +}
  23.666 +
  23.667 +TEST_F(BufferSeek, CurZero) {
  23.668 +    ASSERT_EQ(buf.pos, 3);
  23.669 +    int result = cxBufferSeek(&buf, 0, SEEK_CUR);
  23.670 +    EXPECT_EQ(result, 0);
  23.671 +    EXPECT_EQ(buf.pos, 3);
  23.672 +}
  23.673 +
  23.674 +TEST_F(BufferSeek, CurValidPositive) {
  23.675 +    ASSERT_EQ(buf.pos, 3);
  23.676 +    int result = cxBufferSeek(&buf, 2, SEEK_CUR);
  23.677 +    EXPECT_EQ(result, 0);
  23.678 +    EXPECT_EQ(buf.pos, 5);
  23.679 +}
  23.680 +
  23.681 +TEST_F(BufferSeek, CurValidNegative) {
  23.682 +    ASSERT_EQ(buf.pos, 3);
  23.683 +    int result = cxBufferSeek(&buf, -3, SEEK_CUR);
  23.684 +    EXPECT_EQ(result, 0);
  23.685 +    EXPECT_EQ(buf.pos, 0);
  23.686 +}
  23.687 +
  23.688 +TEST_F(BufferSeek, CurInvalidPositive) {
  23.689 +    ASSERT_EQ(buf.pos, 3);
  23.690 +    int result = cxBufferSeek(&buf, 3, SEEK_CUR);
  23.691 +    EXPECT_NE(result, 0);
  23.692 +    EXPECT_EQ(buf.pos, 3);
  23.693 +}
  23.694 +
  23.695 +TEST_F(BufferSeek, CurInvalidNegative) {
  23.696 +    ASSERT_EQ(buf.pos, 3);
  23.697 +    int result = cxBufferSeek(&buf, -4, SEEK_CUR);
  23.698 +    EXPECT_NE(result, 0);
  23.699 +    EXPECT_EQ(buf.pos, 3);
  23.700 +}
  23.701 +
  23.702 +TEST_F(BufferSeek, EndZero) {
  23.703 +    ASSERT_EQ(buf.size, 6);
  23.704 +    int result = cxBufferSeek(&buf, 0, SEEK_END);
  23.705 +    // the (past-the-)end position is always invalid
  23.706 +    EXPECT_NE(result, 0);
  23.707 +    EXPECT_EQ(buf.pos, 3);
  23.708 +}
  23.709 +
  23.710 +TEST_F(BufferSeek, EndValid) {
  23.711 +    ASSERT_EQ(buf.size, 6);
  23.712 +    int result = cxBufferSeek(&buf, -6, SEEK_END);
  23.713 +    EXPECT_EQ(result, 0);
  23.714 +    EXPECT_EQ(buf.pos, 0);
  23.715 +}
  23.716 +
  23.717 +TEST_F(BufferSeek, EndInvalid) {
  23.718 +    ASSERT_EQ(buf.size, 6);
  23.719 +    int result = cxBufferSeek(&buf, 1, SEEK_END);
  23.720 +    EXPECT_NE(result, 0);
  23.721 +    EXPECT_EQ(buf.pos, 3);
  23.722 +}
  23.723 +
  23.724 +TEST_F(BufferSeek, WhenceInvalid) {
  23.725 +    ASSERT_EQ(buf.size, 6);
  23.726 +    ASSERT_EQ(buf.pos, 3);
  23.727 +    int result = cxBufferSeek(&buf, 2, 9000);
  23.728 +    EXPECT_NE(result, 0);
  23.729 +    EXPECT_EQ(buf.size, 6);
  23.730 +    EXPECT_EQ(buf.pos, 3);
  23.731 +}
  23.732 +
  23.733 +class BufferEof : public BufferFixture {
  23.734 +};
  23.735 +
  23.736 +TEST_F(BufferEof, Reached) {
  23.737 +    buf.pos = buf.size;
  23.738 +    EXPECT_TRUE(cxBufferEof(&buf));
  23.739 +    buf.pos = buf.size - 1;
  23.740 +    ASSERT_FALSE(cxBufferEof(&buf));
  23.741 +    cxBufferPut(&buf, 'a');
  23.742 +    EXPECT_TRUE(cxBufferEof(&buf));
  23.743 +}
  23.744 +
  23.745 +TEST_F(BufferEof, NotReached) {
  23.746 +    buf.pos = buf.size - 1;
  23.747 +    EXPECT_FALSE(cxBufferEof(&buf));
  23.748 +    buf.pos = 0;
  23.749 +    cxBufferWrite("test", 1, 5, &buf);
  23.750 +    EXPECT_FALSE(cxBufferEof(&buf));
  23.751 +}
  23.752 +
  23.753 +class BufferRead : public ::testing::Test {
  23.754 +protected:
  23.755 +    CxBuffer buf{};
  23.756 +
  23.757 +    void SetUp() override {
  23.758 +        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
  23.759 +        buf.capacity = 8; // artificially reduce capacity to check OOB writes
  23.760 +        memset(buf.space, 0, 16);
  23.761 +        memcpy(buf.space, "some data", 9);
  23.762 +        buf.size = 9;
  23.763 +    }
  23.764 +
  23.765 +    void TearDown() override {
  23.766 +        cxBufferDestroy(&buf);
  23.767 +    }
  23.768 +};
  23.769 +
  23.770 +TEST_F(BufferRead, GetByte) {
  23.771 +    buf.pos = 2;
  23.772 +    EXPECT_EQ(cxBufferGet(&buf), 'm');
  23.773 +    EXPECT_EQ(cxBufferGet(&buf), 'e');
  23.774 +    EXPECT_EQ(cxBufferGet(&buf), ' ');
  23.775 +    EXPECT_EQ(cxBufferGet(&buf), 'd');
  23.776 +    EXPECT_EQ(buf.pos, 6);
  23.777 +}
  23.778 +
  23.779 +TEST_F(BufferRead, GetEof) {
  23.780 +    buf.pos = buf.size;
  23.781 +    EXPECT_EQ(cxBufferGet(&buf), EOF);
  23.782 +}
  23.783 +
  23.784 +TEST_F(BufferRead, ReadWithinBounds) {
  23.785 +    buf.pos = 2;
  23.786 +    char target[4];
  23.787 +    auto read = cxBufferRead(&target, 1, 4, &buf);
  23.788 +    ASSERT_EQ(read, 4);
  23.789 +    EXPECT_EQ(memcmp(&target, "me d", 4), 0);
  23.790 +    EXPECT_EQ(buf.pos, 6);
  23.791 +}
  23.792 +
  23.793 +TEST_F(BufferRead, ReadOutOfBounds) {
  23.794 +    buf.pos = 6;
  23.795 +    char target[4];
  23.796 +    auto read = cxBufferRead(&target, 1, 4, &buf);
  23.797 +    ASSERT_EQ(read, 3);
  23.798 +    EXPECT_EQ(memcmp(&target, "ata", 3), 0);
  23.799 +    EXPECT_EQ(buf.pos, 9);
  23.800 +}
  23.801 +
  23.802 +TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
  23.803 +    buf.pos = 6;
  23.804 +    char target[4];
  23.805 +    target[2] = '\0';
  23.806 +    auto read = cxBufferRead(&target, 2, 2, &buf);
  23.807 +    ASSERT_EQ(read, 1);
  23.808 +    EXPECT_EQ(memcmp(&target, "at\0", 3), 0);
  23.809 +    EXPECT_EQ(buf.pos, 8);
  23.810 +}
  23.811 +
  23.812 +TEST_F(BufferRead, ReadEof) {
  23.813 +    buf.pos = 9;
  23.814 +    char target[4];
  23.815 +    auto read = cxBufferRead(&target, 1, 1, &buf);
  23.816 +    ASSERT_EQ(read, 0);
  23.817 +    EXPECT_EQ(buf.pos, 9);
  23.818 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/tests/test_compare.cpp	Tue Feb 07 21:55:37 2023 +0100
    24.3 @@ -0,0 +1,127 @@
    24.4 +/*
    24.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    24.6 + *
    24.7 + * Copyright 2022 Mike Becker, Olaf Wintermann All rights reserved.
    24.8 + *
    24.9 + * Redistribution and use in source and binary forms, with or without
   24.10 + * modification, are permitted provided that the following conditions are met:
   24.11 + *
   24.12 + *   1. Redistributions of source code must retain the above copyright
   24.13 + *      notice, this list of conditions and the following disclaimer.
   24.14 + *
   24.15 + *   2. Redistributions in binary form must reproduce the above copyright
   24.16 + *      notice, this list of conditions and the following disclaimer in the
   24.17 + *      documentation and/or other materials provided with the distribution.
   24.18 + *
   24.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   24.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   24.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   24.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   24.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   24.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   24.29 + * POSSIBILITY OF SUCH DAMAGE.
   24.30 + */
   24.31 +
   24.32 +#include "cx/compare.h"
   24.33 +
   24.34 +#include <gtest/gtest.h>
   24.35 +
   24.36 +template<typename T>
   24.37 +static void test_compare(
   24.38 +        int (*fnc)(
   24.39 +                void const *,
   24.40 +                void const *
   24.41 +        )
   24.42 +) {
   24.43 +    auto m = std::numeric_limits<T>::max() / 400;
   24.44 +    T x, y;
   24.45 +
   24.46 +    x = (std::is_signed_v<T> ? -3 : 3) * m;
   24.47 +    y = 5 * m;
   24.48 +    EXPECT_LT(fnc(&x, &y), 0);
   24.49 +    EXPECT_GT(fnc(&y, &x), 0);
   24.50 +
   24.51 +    x = 120 * m;
   24.52 +    y = 348 * m;
   24.53 +    EXPECT_LT(fnc(&x, &y), 0);
   24.54 +    EXPECT_GT(fnc(&y, &x), 0);
   24.55 +
   24.56 +    if constexpr (std::is_signed_v<T>) {
   24.57 +        x = -120 * m;
   24.58 +        y = -348 * m;
   24.59 +        EXPECT_GT(fnc(&x, &y), 0);
   24.60 +        EXPECT_LT(fnc(&y, &x), 0);
   24.61 +    }
   24.62 +
   24.63 +    x = y;
   24.64 +    EXPECT_EQ(fnc(&x, &y), 0);
   24.65 +    EXPECT_EQ(fnc(&y, &x), 0);
   24.66 +}
   24.67 +
   24.68 +TEST(Compare, Int) {
   24.69 +    test_compare<int>(cx_cmp_int);
   24.70 +}
   24.71 +
   24.72 +TEST(Compare, Longint) {
   24.73 +    test_compare<long int>(cx_cmp_longint);
   24.74 +}
   24.75 +
   24.76 +TEST(Compare, Longlong) {
   24.77 +    test_compare<long long>(cx_cmp_longlong);
   24.78 +}
   24.79 +
   24.80 +TEST(Compare, Int16) {
   24.81 +    test_compare<int16_t>(cx_cmp_int16);
   24.82 +}
   24.83 +
   24.84 +TEST(Compare, Int32) {
   24.85 +    test_compare<int32_t>(cx_cmp_int32);
   24.86 +}
   24.87 +
   24.88 +TEST(Compare, Int64) {
   24.89 +    test_compare<int64_t>(cx_cmp_int64);
   24.90 +}
   24.91 +
   24.92 +TEST(Compare, Uint) {
   24.93 +    test_compare<unsigned int>(cx_cmp_uint);
   24.94 +}
   24.95 +
   24.96 +TEST(Compare, Ulongint) {
   24.97 +    test_compare<unsigned long int>(cx_cmp_ulongint);
   24.98 +}
   24.99 +
  24.100 +TEST(Compare, Ulonglong) {
  24.101 +    test_compare<unsigned long long>(cx_cmp_ulonglong);
  24.102 +}
  24.103 +
  24.104 +TEST(Compare, Uint16) {
  24.105 +    test_compare<uint16_t>(cx_cmp_uint16);
  24.106 +}
  24.107 +
  24.108 +TEST(Compare, Uint32) {
  24.109 +    test_compare<uint32_t>(cx_cmp_uint32);
  24.110 +}
  24.111 +
  24.112 +TEST(Compare, Uint64) {
  24.113 +    test_compare<uint64_t>(cx_cmp_uint64);
  24.114 +}
  24.115 +
  24.116 +TEST(Compare, Float) {
  24.117 +    test_compare<float>(cx_cmp_float);
  24.118 +}
  24.119 +
  24.120 +TEST(Compare, Double) {
  24.121 +    test_compare<double>(cx_cmp_double);
  24.122 +}
  24.123 +
  24.124 +TEST(Compare, IntPtr) {
  24.125 +    test_compare<intptr_t>(cx_cmp_intptr);
  24.126 +}
  24.127 +
  24.128 +TEST(Compare, UintPtr) {
  24.129 +    test_compare<uintptr_t>(cx_cmp_uintptr);
  24.130 +}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/tests/test_hash_key.cpp	Tue Feb 07 21:55:37 2023 +0100
    25.3 @@ -0,0 +1,87 @@
    25.4 +/*
    25.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    25.6 + *
    25.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    25.8 + *
    25.9 + * Redistribution and use in source and binary forms, with or without
   25.10 + * modification, are permitted provided that the following conditions are met:
   25.11 + *
   25.12 + *   1. Redistributions of source code must retain the above copyright
   25.13 + *      notice, this list of conditions and the following disclaimer.
   25.14 + *
   25.15 + *   2. Redistributions in binary form must reproduce the above copyright
   25.16 + *      notice, this list of conditions and the following disclaimer in the
   25.17 + *      documentation and/or other materials provided with the distribution.
   25.18 + *
   25.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   25.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   25.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   25.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   25.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   25.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   25.29 + * POSSIBILITY OF SUCH DAMAGE.
   25.30 + */
   25.31 +
   25.32 +#include "cx/hash_key.h"
   25.33 +
   25.34 +#include <gtest/gtest.h>
   25.35 +
   25.36 +TEST(cx_hash_key, functions) {
   25.37 +    auto str = "my key";
   25.38 +    auto len = strlen(str);
   25.39 +
   25.40 +    auto str_key = cx_hash_key_str(str);
   25.41 +    auto bytes_key = cx_hash_key_bytes(
   25.42 +            reinterpret_cast<unsigned char const *>(str), len);
   25.43 +    auto obj_key = cx_hash_key(
   25.44 +            reinterpret_cast<void const *>(str), len);
   25.45 +
   25.46 +    EXPECT_EQ(str_key.hash, bytes_key.hash);
   25.47 +    EXPECT_EQ(obj_key.hash, bytes_key.hash);
   25.48 +    EXPECT_EQ(str_key.len, len);
   25.49 +    EXPECT_EQ(bytes_key.len, len);
   25.50 +    EXPECT_EQ(bytes_key.len, len);
   25.51 +    EXPECT_EQ(str_key.data.cstr, str);
   25.52 +    EXPECT_EQ(bytes_key.data.cbytes, reinterpret_cast<unsigned char const *>(str));
   25.53 +    EXPECT_EQ(bytes_key.data.cobj, reinterpret_cast<void const *>(str));
   25.54 +}
   25.55 +
   25.56 +TEST(cx_hash_key, empty_string) {
   25.57 +    auto str = "";
   25.58 +
   25.59 +    auto str_key = cx_hash_key_str(str);
   25.60 +    auto bytes_key = cx_hash_key_bytes(
   25.61 +            reinterpret_cast<unsigned char const *>(str), 0);
   25.62 +    auto obj_key = cx_hash_key(
   25.63 +            reinterpret_cast<void const *>(str), 0);
   25.64 +
   25.65 +    EXPECT_EQ(bytes_key.hash, 4152238450u);
   25.66 +    EXPECT_EQ(str_key.hash, 4152238450u);
   25.67 +    EXPECT_EQ(obj_key.hash, 4152238450u);
   25.68 +    EXPECT_EQ(str_key.len, 0);
   25.69 +    EXPECT_EQ(bytes_key.len, 0);
   25.70 +    EXPECT_EQ(bytes_key.len, 0);
   25.71 +    EXPECT_EQ(str_key.data.cstr, str);
   25.72 +    EXPECT_EQ(bytes_key.data.cbytes, reinterpret_cast<unsigned char const *>(str));
   25.73 +    EXPECT_EQ(bytes_key.data.cobj, reinterpret_cast<void const *>(str));
   25.74 +}
   25.75 +
   25.76 +TEST(cx_hash_key, null_ptr) {
   25.77 +    auto str_key = cx_hash_key_str(nullptr);
   25.78 +    auto bytes_key = cx_hash_key_bytes(nullptr, 0);
   25.79 +    auto obj_key = cx_hash_key(nullptr, 0);
   25.80 +
   25.81 +    EXPECT_EQ(bytes_key.hash, 1574210520u);
   25.82 +    EXPECT_EQ(str_key.hash, 1574210520u);
   25.83 +    EXPECT_EQ(obj_key.hash, 1574210520u);
   25.84 +    EXPECT_EQ(str_key.len, 0);
   25.85 +    EXPECT_EQ(bytes_key.len, 0);
   25.86 +    EXPECT_EQ(bytes_key.len, 0);
   25.87 +    EXPECT_EQ(str_key.data.cstr, nullptr);
   25.88 +    EXPECT_EQ(bytes_key.data.cbytes, nullptr);
   25.89 +    EXPECT_EQ(bytes_key.data.cobj, nullptr);
   25.90 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/tests/test_list.cpp	Tue Feb 07 21:55:37 2023 +0100
    26.3 @@ -0,0 +1,1077 @@
    26.4 +/*
    26.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    26.6 + *
    26.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    26.8 + *
    26.9 + * Redistribution and use in source and binary forms, with or without
   26.10 + * modification, are permitted provided that the following conditions are met:
   26.11 + *
   26.12 + *   1. Redistributions of source code must retain the above copyright
   26.13 + *      notice, this list of conditions and the following disclaimer.
   26.14 + *
   26.15 + *   2. Redistributions in binary form must reproduce the above copyright
   26.16 + *      notice, this list of conditions and the following disclaimer in the
   26.17 + *      documentation and/or other materials provided with the distribution.
   26.18 + *
   26.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   26.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   26.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   26.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   26.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26.29 + * POSSIBILITY OF SUCH DAMAGE.
   26.30 + */
   26.31 +
   26.32 +#include "cx/linked_list.h"
   26.33 +#include "cx/array_list.h"
   26.34 +#include "cx/utils.h"
   26.35 +#include "cx/compare.h"
   26.36 +#include "util_allocator.h"
   26.37 +
   26.38 +#include <gtest/gtest.h>
   26.39 +#include <array>
   26.40 +#include <vector>
   26.41 +#include <unordered_set>
   26.42 +#include <algorithm>
   26.43 +
   26.44 +struct node {
   26.45 +    node *next = nullptr;
   26.46 +    node *prev = nullptr;
   26.47 +    int data = 0;
   26.48 +};
   26.49 +
   26.50 +const ptrdiff_t loc_prev = offsetof(struct node, prev);
   26.51 +const ptrdiff_t loc_next = offsetof(struct node, next);
   26.52 +const ptrdiff_t loc_data = offsetof(struct node, data);
   26.53 +
   26.54 +struct node_test_data {
   26.55 +    node *begin = nullptr;
   26.56 +
   26.57 +    explicit node_test_data(node *begin) : begin(begin) {
   26.58 +        auto n = begin;
   26.59 +        while (n != nullptr) {
   26.60 +            nodes.push_back(n);
   26.61 +            n = n->next;
   26.62 +        }
   26.63 +    }
   26.64 +
   26.65 +    node_test_data(node_test_data &) = delete;
   26.66 +
   26.67 +    node_test_data(node_test_data &&) = default;
   26.68 +
   26.69 +    ~node_test_data() {
   26.70 +        for (auto &&n: nodes) delete n;
   26.71 +    }
   26.72 +
   26.73 +private:
   26.74 +    std::vector<node *> nodes;
   26.75 +};
   26.76 +
   26.77 +static node_test_data create_nodes_test_data(size_t len) {
   26.78 +    if (len == 0) return node_test_data{nullptr};
   26.79 +    auto begin = new node;
   26.80 +    auto prev = begin;
   26.81 +    for (size_t i = 1; i < len; i++) {
   26.82 +        auto n = new node;
   26.83 +        cx_linked_list_link(prev, n, loc_prev, loc_next);
   26.84 +        prev = n;
   26.85 +    }
   26.86 +    return node_test_data{begin};
   26.87 +}
   26.88 +
   26.89 +template<typename InputIter>
   26.90 +static node_test_data create_nodes_test_data(
   26.91 +        InputIter begin,
   26.92 +        InputIter end
   26.93 +) {
   26.94 +    if (begin == end) return node_test_data{nullptr};
   26.95 +    node *first = new node;
   26.96 +    first->data = *begin;
   26.97 +    node *prev = first;
   26.98 +    begin++;
   26.99 +    for (; begin != end; begin++) {
  26.100 +        auto n = new node;
  26.101 +        n->data = *begin;
  26.102 +        cx_linked_list_link(prev, n, loc_prev, loc_next);
  26.103 +        prev = n;
  26.104 +    }
  26.105 +    return node_test_data{first};
  26.106 +}
  26.107 +
  26.108 +static node_test_data create_nodes_test_data(std::initializer_list<int> data) {
  26.109 +    return create_nodes_test_data(data.begin(), data.end());
  26.110 +}
  26.111 +
  26.112 +template<size_t N>
  26.113 +struct int_test_data {
  26.114 +    std::array<int, N> data;
  26.115 +
  26.116 +    int_test_data() {
  26.117 +        cx_for_n (i, N) data[i] = ::rand(); // NOLINT(cert-msc50-cpp)
  26.118 +    }
  26.119 +};
  26.120 +
  26.121 +TEST(LinkedList_LowLevel, link_unlink) {
  26.122 +    node a, b, c;
  26.123 +
  26.124 +    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  26.125 +    EXPECT_EQ(a.prev, nullptr);
  26.126 +    EXPECT_EQ(a.next, &b);
  26.127 +    EXPECT_EQ(b.prev, &a);
  26.128 +    EXPECT_EQ(b.next, nullptr);
  26.129 +
  26.130 +    cx_linked_list_unlink(&a, &b, loc_prev, loc_next);
  26.131 +    EXPECT_EQ(a.prev, nullptr);
  26.132 +    EXPECT_EQ(a.next, nullptr);
  26.133 +    EXPECT_EQ(b.prev, nullptr);
  26.134 +    EXPECT_EQ(b.next, nullptr);
  26.135 +
  26.136 +    cx_linked_list_link(&b, &c, loc_prev, loc_next);
  26.137 +    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  26.138 +    cx_linked_list_unlink(&b, &c, loc_prev, loc_next);
  26.139 +    EXPECT_EQ(a.prev, nullptr);
  26.140 +    EXPECT_EQ(a.next, &b);
  26.141 +    EXPECT_EQ(b.prev, &a);
  26.142 +    EXPECT_EQ(b.next, nullptr);
  26.143 +    EXPECT_EQ(c.prev, nullptr);
  26.144 +    EXPECT_EQ(c.next, nullptr);
  26.145 +}
  26.146 +
  26.147 +TEST(LinkedList_LowLevel, cx_linked_list_at) {
  26.148 +    node a, b, c, d;
  26.149 +    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  26.150 +    cx_linked_list_link(&b, &c, loc_prev, loc_next);
  26.151 +    cx_linked_list_link(&c, &d, loc_prev, loc_next);
  26.152 +
  26.153 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 0), &a);
  26.154 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 1), &b);
  26.155 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 2), &c);
  26.156 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 3), &d);
  26.157 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 4), nullptr);
  26.158 +
  26.159 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_prev, 0), &a);
  26.160 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 1), &b);
  26.161 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 2), &c);
  26.162 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 3), &d);
  26.163 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 4), nullptr);
  26.164 +
  26.165 +    EXPECT_EQ(cx_linked_list_at(&d, 3, loc_prev, 0), &a);
  26.166 +    EXPECT_EQ(cx_linked_list_at(&d, 3, loc_prev, 1), &b);
  26.167 +}
  26.168 +
  26.169 +TEST(LinkedList_LowLevel, cx_linked_list_find) {
  26.170 +    auto testdata = create_nodes_test_data({2, 4, 6, 8});
  26.171 +    auto list = testdata.begin;
  26.172 +    int s;
  26.173 +
  26.174 +    s = 2;
  26.175 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 0);
  26.176 +    s = 4;
  26.177 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 1);
  26.178 +    s = 6;
  26.179 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 2);
  26.180 +    s = 8;
  26.181 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 3);
  26.182 +    s = 10;
  26.183 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 4);
  26.184 +    s = -2;
  26.185 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 4);
  26.186 +}
  26.187 +
  26.188 +TEST(LinkedList_LowLevel, cx_linked_list_compare) {
  26.189 +    auto ta = create_nodes_test_data({2, 4, 6, 8});
  26.190 +    auto tb = create_nodes_test_data({2, 4, 6});
  26.191 +    auto tc = create_nodes_test_data({2, 4, 6, 9});
  26.192 +    auto la = ta.begin, lb = tb.begin, lc = tc.begin;
  26.193 +
  26.194 +    EXPECT_GT(cx_linked_list_compare(la, lb, loc_next, loc_data, cx_cmp_int), 0);
  26.195 +    EXPECT_LT(cx_linked_list_compare(lb, la, loc_next, loc_data, cx_cmp_int), 0);
  26.196 +    EXPECT_GT(cx_linked_list_compare(lc, la, loc_next, loc_data, cx_cmp_int), 0);
  26.197 +    EXPECT_LT(cx_linked_list_compare(la, lc, loc_next, loc_data, cx_cmp_int), 0);
  26.198 +    EXPECT_EQ(cx_linked_list_compare(la, la, loc_next, loc_data, cx_cmp_int), 0);
  26.199 +}
  26.200 +
  26.201 +TEST(LinkedList_LowLevel, cx_linked_list_add) {
  26.202 +    // test with begin, end / prev, next
  26.203 +    {
  26.204 +        node nodes[4];
  26.205 +        void *begin = nullptr, *end = nullptr;
  26.206 +
  26.207 +        cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[0]);
  26.208 +        EXPECT_EQ(begin, &nodes[0]);
  26.209 +        EXPECT_EQ(end, &nodes[0]);
  26.210 +        EXPECT_EQ(nodes[0].prev, nullptr);
  26.211 +        EXPECT_EQ(nodes[0].next, nullptr);
  26.212 +
  26.213 +        cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[1]);
  26.214 +        EXPECT_EQ(begin, &nodes[0]);
  26.215 +        EXPECT_EQ(end, &nodes[1]);
  26.216 +        EXPECT_EQ(nodes[0].next, &nodes[1]);
  26.217 +        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  26.218 +    }
  26.219 +
  26.220 +    // test with begin only / prev, next
  26.221 +    {
  26.222 +        node nodes[4];
  26.223 +        void *begin = nullptr;
  26.224 +
  26.225 +        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[0]);
  26.226 +        EXPECT_EQ(begin, &nodes[0]);
  26.227 +        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[1]);
  26.228 +        EXPECT_EQ(begin, &nodes[0]);
  26.229 +        EXPECT_EQ(nodes[0].next, &nodes[1]);
  26.230 +        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  26.231 +
  26.232 +        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[2]);
  26.233 +        EXPECT_EQ(nodes[1].next, &nodes[2]);
  26.234 +        EXPECT_EQ(nodes[2].prev, &nodes[1]);
  26.235 +    }
  26.236 +
  26.237 +    // test with end only / prev, next
  26.238 +    {
  26.239 +        node nodes[4];
  26.240 +        void *end = nullptr;
  26.241 +
  26.242 +        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[0]);
  26.243 +        EXPECT_EQ(end, &nodes[0]);
  26.244 +        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[1]);
  26.245 +        EXPECT_EQ(end, &nodes[1]);
  26.246 +        EXPECT_EQ(nodes[0].next, &nodes[1]);
  26.247 +        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  26.248 +
  26.249 +        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[2]);
  26.250 +        EXPECT_EQ(end, &nodes[2]);
  26.251 +        EXPECT_EQ(nodes[1].next, &nodes[2]);
  26.252 +        EXPECT_EQ(nodes[2].prev, &nodes[1]);
  26.253 +    }
  26.254 +
  26.255 +    // test with begin, end / next
  26.256 +    {
  26.257 +        node nodes[4];
  26.258 +        void *begin = nullptr, *end = nullptr;
  26.259 +
  26.260 +        cx_linked_list_add(&begin, &end, -1, loc_next, &nodes[0]);
  26.261 +        EXPECT_EQ(begin, &nodes[0]);
  26.262 +        EXPECT_EQ(end, &nodes[0]);
  26.263 +        cx_linked_list_add(&begin, &end, -1, loc_next, &nodes[1]);
  26.264 +        EXPECT_EQ(end, &nodes[1]);
  26.265 +        EXPECT_EQ(nodes[0].next, &nodes[1]);
  26.266 +        EXPECT_EQ(nodes[1].prev, nullptr);
  26.267 +    }
  26.268 +}
  26.269 +
  26.270 +TEST(LinkedList_LowLevel, cx_linked_list_prepend) {
  26.271 +    // test with begin, end / prev, next
  26.272 +    {
  26.273 +        node nodes[4];
  26.274 +        void *begin = nullptr, *end = nullptr;
  26.275 +
  26.276 +        cx_linked_list_prepend(&begin, &end, loc_prev, loc_next, &nodes[0]);
  26.277 +        EXPECT_EQ(begin, &nodes[0]);
  26.278 +        EXPECT_EQ(end, &nodes[0]);
  26.279 +        EXPECT_EQ(nodes[0].prev, nullptr);
  26.280 +        EXPECT_EQ(nodes[0].next, nullptr);
  26.281 +
  26.282 +        cx_linked_list_prepend(&begin, &end, loc_prev, loc_next, &nodes[1]);
  26.283 +        EXPECT_EQ(begin, &nodes[1]);
  26.284 +        EXPECT_EQ(end, &nodes[0]);
  26.285 +        EXPECT_EQ(nodes[1].next, &nodes[0]);
  26.286 +        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  26.287 +    }
  26.288 +
  26.289 +    // test with begin only / prev, next
  26.290 +    {
  26.291 +        node nodes[4];
  26.292 +        void *begin = nullptr;
  26.293 +
  26.294 +        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[0]);
  26.295 +        EXPECT_EQ(begin, &nodes[0]);
  26.296 +        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[1]);
  26.297 +        EXPECT_EQ(begin, &nodes[1]);
  26.298 +        EXPECT_EQ(nodes[1].next, &nodes[0]);
  26.299 +        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  26.300 +
  26.301 +        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[2]);
  26.302 +        EXPECT_EQ(begin, &nodes[2]);
  26.303 +        EXPECT_EQ(nodes[2].next, &nodes[1]);
  26.304 +        EXPECT_EQ(nodes[1].prev, &nodes[2]);
  26.305 +    }
  26.306 +
  26.307 +    // test with end only / prev, next
  26.308 +    {
  26.309 +        node nodes[4];
  26.310 +        void *end = nullptr;
  26.311 +
  26.312 +        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[0]);
  26.313 +        EXPECT_EQ(end, &nodes[0]);
  26.314 +        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[1]);
  26.315 +        EXPECT_EQ(end, &nodes[0]);
  26.316 +        EXPECT_EQ(nodes[1].next, &nodes[0]);
  26.317 +        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  26.318 +
  26.319 +        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[2]);
  26.320 +        EXPECT_EQ(end, &nodes[0]);
  26.321 +        EXPECT_EQ(nodes[2].next, &nodes[1]);
  26.322 +        EXPECT_EQ(nodes[1].prev, &nodes[2]);
  26.323 +    }
  26.324 +
  26.325 +    // test with begin, end / next
  26.326 +    {
  26.327 +        node nodes[4];
  26.328 +        void *begin = nullptr, *end = nullptr;
  26.329 +
  26.330 +        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[0]);
  26.331 +        EXPECT_EQ(begin, &nodes[0]);
  26.332 +        EXPECT_EQ(end, &nodes[0]);
  26.333 +        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[1]);
  26.334 +        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[2]);
  26.335 +        EXPECT_EQ(begin, &nodes[2]);
  26.336 +        EXPECT_EQ(end, &nodes[0]);
  26.337 +        EXPECT_EQ(nodes[1].next, &nodes[0]);
  26.338 +        EXPECT_EQ(nodes[2].next, &nodes[1]);
  26.339 +        EXPECT_EQ(nodes[1].prev, nullptr);
  26.340 +        EXPECT_EQ(nodes[0].prev, nullptr);
  26.341 +    }
  26.342 +}
  26.343 +
  26.344 +TEST(LinkedList_LowLevel, cx_linked_list_insert) {
  26.345 +    // insert mid list
  26.346 +    {
  26.347 +        node nodes[4];
  26.348 +        void *begin = &nodes[0], *end = &nodes[2];
  26.349 +
  26.350 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  26.351 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  26.352 +
  26.353 +        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, &nodes[1], &nodes[3]);
  26.354 +        EXPECT_EQ(begin, &nodes[0]);
  26.355 +        EXPECT_EQ(end, &nodes[2]);
  26.356 +        EXPECT_EQ(nodes[1].next, &nodes[3]);
  26.357 +        EXPECT_EQ(nodes[2].prev, &nodes[3]);
  26.358 +        EXPECT_EQ(nodes[3].prev, &nodes[1]);
  26.359 +        EXPECT_EQ(nodes[3].next, &nodes[2]);
  26.360 +    }
  26.361 +
  26.362 +    // insert end
  26.363 +    {
  26.364 +        node nodes[4];
  26.365 +        void *begin = &nodes[0], *end = &nodes[2];
  26.366 +
  26.367 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  26.368 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  26.369 +
  26.370 +        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, &nodes[2], &nodes[3]);
  26.371 +        EXPECT_EQ(begin, &nodes[0]);
  26.372 +        EXPECT_EQ(end, &nodes[3]);
  26.373 +        EXPECT_EQ(nodes[2].next, &nodes[3]);
  26.374 +        EXPECT_EQ(nodes[3].prev, &nodes[2]);
  26.375 +        EXPECT_EQ(nodes[3].next, nullptr);
  26.376 +    }
  26.377 +
  26.378 +    // insert begin
  26.379 +    {
  26.380 +        node nodes[4];
  26.381 +        void *begin = &nodes[0], *end = &nodes[2];
  26.382 +
  26.383 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  26.384 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  26.385 +
  26.386 +        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, nullptr, &nodes[3]);
  26.387 +        EXPECT_EQ(begin, &nodes[3]);
  26.388 +        EXPECT_EQ(end, &nodes[2]);
  26.389 +        EXPECT_EQ(nodes[0].prev, &nodes[3]);
  26.390 +        EXPECT_EQ(nodes[3].prev, nullptr);
  26.391 +        EXPECT_EQ(nodes[3].next, &nodes[0]);
  26.392 +    }
  26.393 +}
  26.394 +
  26.395 +TEST(LinkedList_LowLevel, cx_linked_list_insert_chain) {
  26.396 +    // insert mid list
  26.397 +    {
  26.398 +        node nodes[5];
  26.399 +        void *begin = &nodes[0], *end = &nodes[2];
  26.400 +
  26.401 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  26.402 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  26.403 +        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  26.404 +
  26.405 +        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, &nodes[1], &nodes[3], nullptr);
  26.406 +        EXPECT_EQ(begin, &nodes[0]);
  26.407 +        EXPECT_EQ(end, &nodes[2]);
  26.408 +        EXPECT_EQ(nodes[1].next, &nodes[3]);
  26.409 +        EXPECT_EQ(nodes[2].prev, &nodes[4]);
  26.410 +        EXPECT_EQ(nodes[3].prev, &nodes[1]);
  26.411 +        EXPECT_EQ(nodes[4].next, &nodes[2]);
  26.412 +    }
  26.413 +
  26.414 +    // insert end
  26.415 +    {
  26.416 +        node nodes[5];
  26.417 +        void *begin = &nodes[0], *end = &nodes[2];
  26.418 +
  26.419 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  26.420 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  26.421 +        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  26.422 +
  26.423 +        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, &nodes[2], &nodes[3], nullptr);
  26.424 +        EXPECT_EQ(begin, &nodes[0]);
  26.425 +        EXPECT_EQ(end, &nodes[4]);
  26.426 +        EXPECT_EQ(nodes[2].next, &nodes[3]);
  26.427 +        EXPECT_EQ(nodes[3].prev, &nodes[2]);
  26.428 +        EXPECT_EQ(nodes[4].next, nullptr);
  26.429 +    }
  26.430 +
  26.431 +    // insert begin
  26.432 +    {
  26.433 +        node nodes[5];
  26.434 +        void *begin = &nodes[0], *end = &nodes[2];
  26.435 +
  26.436 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  26.437 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  26.438 +        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  26.439 +
  26.440 +        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, nullptr, &nodes[3], nullptr);
  26.441 +        EXPECT_EQ(begin, &nodes[3]);
  26.442 +        EXPECT_EQ(end, &nodes[2]);
  26.443 +        EXPECT_EQ(nodes[0].prev, &nodes[4]);
  26.444 +        EXPECT_EQ(nodes[3].prev, nullptr);
  26.445 +        EXPECT_EQ(nodes[4].next, &nodes[0]);
  26.446 +    }
  26.447 +}
  26.448 +
  26.449 +TEST(LinkedList_LowLevel, cx_linked_list_first) {
  26.450 +    auto testdata = create_nodes_test_data(3);
  26.451 +    auto begin = testdata.begin;
  26.452 +    EXPECT_EQ(cx_linked_list_first(begin, loc_prev), begin);
  26.453 +    EXPECT_EQ(cx_linked_list_first(begin->next, loc_prev), begin);
  26.454 +    EXPECT_EQ(cx_linked_list_first(begin->next->next, loc_prev), begin);
  26.455 +}
  26.456 +
  26.457 +TEST(LinkedList_LowLevel, cx_linked_list_last) {
  26.458 +    auto testdata = create_nodes_test_data(3);
  26.459 +    auto begin = testdata.begin;
  26.460 +    auto end = begin->next->next;
  26.461 +    EXPECT_EQ(cx_linked_list_last(begin, loc_next), end);
  26.462 +    EXPECT_EQ(cx_linked_list_last(begin->next, loc_next), end);
  26.463 +    EXPECT_EQ(cx_linked_list_last(begin->next->next, loc_next), end);
  26.464 +}
  26.465 +
  26.466 +TEST(LinkedList_LowLevel, cx_linked_list_prev) {
  26.467 +    auto testdata = create_nodes_test_data(3);
  26.468 +    auto begin = testdata.begin;
  26.469 +    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin), nullptr);
  26.470 +    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin->next), begin);
  26.471 +    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin->next->next), begin->next);
  26.472 +}
  26.473 +
  26.474 +TEST(LinkedList_LowLevel, cx_linked_list_remove) {
  26.475 +    auto testdata = create_nodes_test_data({2, 4, 6});
  26.476 +    auto begin = reinterpret_cast<void *>(testdata.begin);
  26.477 +    auto first = testdata.begin;
  26.478 +    auto second = first->next;
  26.479 +    auto third = second->next;
  26.480 +    auto end = reinterpret_cast<void *>(third);
  26.481 +
  26.482 +    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, second);
  26.483 +    EXPECT_EQ(begin, first);
  26.484 +    EXPECT_EQ(end, third);
  26.485 +    EXPECT_EQ(first->prev, nullptr);
  26.486 +    EXPECT_EQ(first->next, third);
  26.487 +    EXPECT_EQ(third->prev, first);
  26.488 +    EXPECT_EQ(third->next, nullptr);
  26.489 +
  26.490 +    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, third);
  26.491 +    EXPECT_EQ(begin, first);
  26.492 +    EXPECT_EQ(end, first);
  26.493 +    EXPECT_EQ(first->prev, nullptr);
  26.494 +    EXPECT_EQ(first->next, nullptr);
  26.495 +
  26.496 +    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, first);
  26.497 +    EXPECT_EQ(begin, nullptr);
  26.498 +    EXPECT_EQ(end, nullptr);
  26.499 +}
  26.500 +
  26.501 +TEST(LinkedList_LowLevel, cx_linked_list_size) {
  26.502 +    EXPECT_EQ(cx_linked_list_size(nullptr, loc_next), 0);
  26.503 +
  26.504 +    {
  26.505 +        auto testdata = create_nodes_test_data(5);
  26.506 +        EXPECT_EQ(cx_linked_list_size(testdata.begin, loc_next), 5);
  26.507 +    }
  26.508 +
  26.509 +    {
  26.510 +        auto testdata = create_nodes_test_data(13);
  26.511 +        EXPECT_EQ(cx_linked_list_size(testdata.begin, loc_next), 13);
  26.512 +    }
  26.513 +}
  26.514 +
  26.515 +TEST(LinkedList_LowLevel, cx_linked_list_sort) {
  26.516 +    int_test_data<1500> testdata;
  26.517 +    std::array<int, 1500> sorted{};
  26.518 +    std::partial_sort_copy(testdata.data.begin(), testdata.data.end(), sorted.begin(), sorted.end());
  26.519 +
  26.520 +    auto scrambled = create_nodes_test_data(testdata.data.begin(), testdata.data.end());
  26.521 +    void *begin = scrambled.begin;
  26.522 +    void *end = cx_linked_list_last(begin, loc_next);
  26.523 +
  26.524 +    cx_linked_list_sort(&begin, &end, loc_prev, loc_next, loc_data, cx_cmp_int);
  26.525 +
  26.526 +    node *check = reinterpret_cast<node *>(begin);
  26.527 +    node *check_last = nullptr;
  26.528 +    cx_for_n (i, sorted.size()) {
  26.529 +        EXPECT_EQ(check->data, sorted[i]);
  26.530 +        EXPECT_EQ(check->prev, check_last);
  26.531 +        if (i < sorted.size() - 1) {
  26.532 +            ASSERT_NE(check->next, nullptr);
  26.533 +        }
  26.534 +        check_last = check;
  26.535 +        check = check->next;
  26.536 +    }
  26.537 +    EXPECT_EQ(check, nullptr);
  26.538 +    EXPECT_EQ(end, check_last);
  26.539 +}
  26.540 +
  26.541 +TEST(LinkedList_LowLevel, cx_linked_list_reverse) {
  26.542 +    auto testdata = create_nodes_test_data({2, 4, 6, 8});
  26.543 +    auto expected = create_nodes_test_data({8, 6, 4, 2});
  26.544 +
  26.545 +    auto begin = reinterpret_cast<void *>(testdata.begin);
  26.546 +    auto end = cx_linked_list_last(begin, loc_next);
  26.547 +    auto orig_begin = begin, orig_end = end;
  26.548 +
  26.549 +    cx_linked_list_reverse(&begin, &end, loc_prev, loc_next);
  26.550 +    EXPECT_EQ(end, orig_begin);
  26.551 +    EXPECT_EQ(begin, orig_end);
  26.552 +    EXPECT_EQ(cx_linked_list_compare(begin, expected.begin, loc_next, loc_data, cx_cmp_int), 0);
  26.553 +}
  26.554 +
  26.555 +class HighLevelTest : public ::testing::Test {
  26.556 +    mutable std::unordered_set<CxList *> lists;
  26.557 +protected:
  26.558 +    CxTestingAllocator testingAllocator;
  26.559 +
  26.560 +    void TearDown() override {
  26.561 +        for (auto &&l: lists) cxListDestroy(l);
  26.562 +        EXPECT_TRUE(testingAllocator.verify());
  26.563 +    }
  26.564 +
  26.565 +    static constexpr size_t testdata_len = 250;
  26.566 +    int_test_data<testdata_len> testdata;
  26.567 +
  26.568 +    auto autofree(CxList *list) const -> CxList * {
  26.569 +        if (list != nullptr) lists.insert(list);
  26.570 +        return list;
  26.571 +    }
  26.572 +
  26.573 +    auto linkedListFromTestData() const -> CxList * {
  26.574 +        auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  26.575 +        cxListAddArray(list, testdata.data.data(), testdata_len);
  26.576 +        return list;
  26.577 +    }
  26.578 +
  26.579 +    auto pointerLinkedListFromTestData() const -> CxList * {
  26.580 +        auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  26.581 +        cxListStorePointers(list);
  26.582 +        // note: cannot use cxListAddArray() because we don't have a list of pointers
  26.583 +        cx_for_n(i, testdata_len) cxListAdd(list, &testdata.data[i]);
  26.584 +        return list;
  26.585 +    }
  26.586 +
  26.587 +    auto arrayListFromTestData() const -> CxList * {
  26.588 +        auto list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), testdata_len));
  26.589 +        cxListAddArray(list, testdata.data.data(), testdata_len);
  26.590 +        return list;
  26.591 +    }
  26.592 +
  26.593 +    void verifyCreate(CxList *list) const {
  26.594 +        EXPECT_EQ(list->content_destructor_type, CX_DESTRUCTOR_NONE);
  26.595 +        EXPECT_EQ(list->size, 0);
  26.596 +        EXPECT_EQ(list->allocator, &testingAllocator);
  26.597 +        EXPECT_EQ(list->cmpfunc, cx_cmp_int);
  26.598 +    }
  26.599 +
  26.600 +    void verifyAdd(
  26.601 +            CxList *list,
  26.602 +            bool as_pointer
  26.603 +    ) {
  26.604 +        auto len = testdata_len;
  26.605 +        cx_for_n (i, len) EXPECT_EQ(cxListAdd(list, &testdata.data[i]), 0);
  26.606 +        EXPECT_EQ(list->size, len);
  26.607 +        EXPECT_GE(list->capacity, list->size);
  26.608 +        cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  26.609 +        cx_for_n (i, len) ++testdata.data[i];
  26.610 +        if (as_pointer) {
  26.611 +            cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  26.612 +        } else {
  26.613 +            cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i] - 1);
  26.614 +        }
  26.615 +    }
  26.616 +
  26.617 +    static void verifyInsert(CxList *list) {
  26.618 +        int a = 5, b = 47, c = 13, d = 42;
  26.619 +
  26.620 +        EXPECT_NE(cxListInsert(list, 1, &a), 0);
  26.621 +        EXPECT_EQ(list->size, 0);
  26.622 +        EXPECT_EQ(cxListInsert(list, 0, &a), 0);
  26.623 +        EXPECT_EQ(list->size, 1);
  26.624 +        EXPECT_EQ(cxListInsert(list, 0, &b), 0);
  26.625 +        EXPECT_EQ(list->size, 2);
  26.626 +        EXPECT_EQ(cxListInsert(list, 1, &c), 0);
  26.627 +        EXPECT_EQ(list->size, 3);
  26.628 +        EXPECT_EQ(cxListInsert(list, 3, &d), 0);
  26.629 +
  26.630 +        ASSERT_EQ(list->size, 4);
  26.631 +        EXPECT_GE(list->capacity, list->size);
  26.632 +
  26.633 +        EXPECT_EQ(*(int *) cxListAt(list, 0), 47);
  26.634 +        EXPECT_EQ(*(int *) cxListAt(list, 1), 13);
  26.635 +        EXPECT_EQ(*(int *) cxListAt(list, 2), 5);
  26.636 +        EXPECT_EQ(*(int *) cxListAt(list, 3), 42);
  26.637 +    }
  26.638 +
  26.639 +    static void verifyInsertArray(
  26.640 +            CxList *list,
  26.641 +            bool pointers = false
  26.642 +    ) {
  26.643 +        int a[5] = {5, 47, 11, 13, 42};
  26.644 +        int b[5] = {9, 18, 72, 50, 7};
  26.645 +        int *aptr[5];
  26.646 +        int *bptr[5];
  26.647 +        cx_for_n(i, 5) {
  26.648 +            aptr[i] = &a[i];
  26.649 +            bptr[i] = &b[i];
  26.650 +        }
  26.651 +
  26.652 +        size_t inserted;
  26.653 +
  26.654 +        if (pointers) {
  26.655 +            inserted = cxListInsertArray(list, 0, aptr, 5);
  26.656 +        } else {
  26.657 +            inserted = cxListInsertArray(list, 0, a, 5);
  26.658 +        }
  26.659 +        EXPECT_EQ(inserted, 5);
  26.660 +        EXPECT_EQ(*(int *) cxListAt(list, 0), 5);
  26.661 +        EXPECT_EQ(*(int *) cxListAt(list, 1), 47);
  26.662 +        EXPECT_EQ(*(int *) cxListAt(list, 2), 11);
  26.663 +        EXPECT_EQ(*(int *) cxListAt(list, 3), 13);
  26.664 +        EXPECT_EQ(*(int *) cxListAt(list, 4), 42);
  26.665 +        if (pointers) {
  26.666 +            inserted = cxListInsertArray(list, 3, bptr, 5);
  26.667 +        } else {
  26.668 +            inserted = cxListInsertArray(list, 3, b, 5);
  26.669 +        }
  26.670 +        EXPECT_EQ(inserted, 5);
  26.671 +        EXPECT_EQ(*(int *) cxListAt(list, 0), 5);
  26.672 +        EXPECT_EQ(*(int *) cxListAt(list, 1), 47);
  26.673 +        EXPECT_EQ(*(int *) cxListAt(list, 2), 11);
  26.674 +        EXPECT_EQ(*(int *) cxListAt(list, 3), 9);
  26.675 +        EXPECT_EQ(*(int *) cxListAt(list, 4), 18);
  26.676 +        EXPECT_EQ(*(int *) cxListAt(list, 5), 72);
  26.677 +        EXPECT_EQ(*(int *) cxListAt(list, 6), 50);
  26.678 +        EXPECT_EQ(*(int *) cxListAt(list, 7), 7);
  26.679 +        EXPECT_EQ(*(int *) cxListAt(list, 8), 13);
  26.680 +        EXPECT_EQ(*(int *) cxListAt(list, 9), 42);
  26.681 +    }
  26.682 +
  26.683 +    void verifyRemove(CxList *list) const {
  26.684 +        EXPECT_EQ(cxListRemove(list, 2), 0);
  26.685 +        EXPECT_EQ(cxListRemove(list, 4), 0);
  26.686 +        EXPECT_EQ(list->size, testdata_len - 2);
  26.687 +        EXPECT_GE(list->capacity, list->size);
  26.688 +        EXPECT_EQ(*(int *) cxListAt(list, 0), testdata.data[0]);
  26.689 +        EXPECT_EQ(*(int *) cxListAt(list, 1), testdata.data[1]);
  26.690 +        EXPECT_EQ(*(int *) cxListAt(list, 2), testdata.data[3]);
  26.691 +        EXPECT_EQ(*(int *) cxListAt(list, 3), testdata.data[4]);
  26.692 +        EXPECT_EQ(*(int *) cxListAt(list, 4), testdata.data[6]);
  26.693 +
  26.694 +        EXPECT_EQ(cxListRemove(list, 0), 0);
  26.695 +        EXPECT_EQ(list->size, testdata_len - 3);
  26.696 +        EXPECT_GE(list->capacity, list->size);
  26.697 +        EXPECT_EQ(*(int *) cxListAt(list, 0), testdata.data[1]);
  26.698 +        EXPECT_EQ(*(int *) cxListAt(list, 1), testdata.data[3]);
  26.699 +
  26.700 +        EXPECT_NE(cxListRemove(list, testdata_len), 0);
  26.701 +    }
  26.702 +
  26.703 +    void verifyAt(CxList *list) const {
  26.704 +        auto len = testdata_len;
  26.705 +        EXPECT_EQ(list->size, len);
  26.706 +        cx_for_n (i, len) {
  26.707 +            EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  26.708 +        }
  26.709 +        EXPECT_EQ(cxListAt(list, list->size), nullptr);
  26.710 +    }
  26.711 +
  26.712 +    void verifyFind(CxList *list) const {
  26.713 +        cx_for_n (attempt, 25) {
  26.714 +            size_t exp = rand() % testdata_len; // NOLINT(cert-msc50-cpp)
  26.715 +            int val = testdata.data[exp];
  26.716 +            // randomly picked number could occur earlier in list - find first position
  26.717 +            cx_for_n (i, exp) {
  26.718 +                if (testdata.data[i] == val) {
  26.719 +                    exp = i;
  26.720 +                    break;
  26.721 +                }
  26.722 +            }
  26.723 +            EXPECT_EQ(cxListFind(list, &val), exp);
  26.724 +        }
  26.725 +    }
  26.726 +
  26.727 +    void verifySort(CxList *list) const {
  26.728 +        std::array<int, testdata_len> expected{};
  26.729 +        std::partial_sort_copy(testdata.data.begin(), testdata.data.end(), expected.begin(), expected.end());
  26.730 +        cxListSort(list);
  26.731 +        cx_for_n (i, testdata_len) ASSERT_EQ(*(int *) cxListAt(list, i), expected[i]);
  26.732 +    }
  26.733 +
  26.734 +    void verifyIterator(CxList *list) const {
  26.735 +        int i = 0;
  26.736 +        auto iter = cxListBeginMut(list);
  26.737 +        cx_foreach(int*, x, iter) {
  26.738 +            ASSERT_EQ(iter.index, (size_t) (i + 1) / 2);
  26.739 +            ASSERT_EQ(*x, testdata.data[i]);
  26.740 +            if (i % 2 == 1) cxIteratorFlagRemoval(iter);
  26.741 +            i++;
  26.742 +        }
  26.743 +        auto len = testdata_len;
  26.744 +        EXPECT_EQ(i, len);
  26.745 +        ASSERT_EQ(list->size, len / 2);
  26.746 +        cx_for_n(j, len / 2) ASSERT_EQ(*(int *) cxListAt(list, j), testdata.data[j * 2]);
  26.747 +    }
  26.748 +
  26.749 +    static void verifyInsertViaIterator(CxList *list) {
  26.750 +        int newdata[] = {10, 20, 30, 40, 50};
  26.751 +
  26.752 +        auto iter = cxListMutIterator(list, 2);
  26.753 +        EXPECT_TRUE(cxIteratorValid(iter));
  26.754 +        EXPECT_EQ(iter.index, 2);
  26.755 +        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  26.756 +        cxListInsertAfter(&iter, &newdata[0]);
  26.757 +        EXPECT_TRUE(cxIteratorValid(iter));
  26.758 +        EXPECT_EQ(iter.index, 2);
  26.759 +        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  26.760 +        cxListInsertBefore(&iter, &newdata[1]);
  26.761 +        EXPECT_TRUE(cxIteratorValid(iter));
  26.762 +        EXPECT_EQ(iter.index, 3);
  26.763 +        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  26.764 +
  26.765 +        iter = cxListBeginMut(list);
  26.766 +        cxListInsertBefore(&iter, &newdata[2]);
  26.767 +        EXPECT_TRUE(cxIteratorValid(iter));
  26.768 +        EXPECT_EQ(iter.index, 1);
  26.769 +        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 0);
  26.770 +        iter = cxListMutIterator(list, list->size);
  26.771 +        cxListInsertBefore(&iter, &newdata[3]);
  26.772 +        EXPECT_FALSE(cxIteratorValid(iter));
  26.773 +        EXPECT_EQ(iter.index, 9);
  26.774 +        iter = cxListMutIterator(list, list->size);
  26.775 +        cxListInsertAfter(&iter, &newdata[4]);
  26.776 +        EXPECT_FALSE(cxIteratorValid(iter));
  26.777 +        EXPECT_EQ(iter.index, 10);
  26.778 +
  26.779 +        int expdata[] = {30, 0, 1, 20, 2, 10, 3, 4, 40, 50};
  26.780 +        cx_for_n (j, 10) EXPECT_EQ(*(int *) cxListAt(list, j), expdata[j]);
  26.781 +    }
  26.782 +
  26.783 +    void verifyReverse(CxList *list) const {
  26.784 +        cxListReverse(list);
  26.785 +        cx_for_n(i, testdata_len) {
  26.786 +            ASSERT_EQ(*(int *) cxListAt(list, i), testdata.data[testdata_len - 1 - i]);
  26.787 +        }
  26.788 +    }
  26.789 +
  26.790 +    static void verifyCompare(
  26.791 +            CxList *left,
  26.792 +            CxList *right
  26.793 +    ) {
  26.794 +        EXPECT_EQ(cxListCompare(left, right), 0);
  26.795 +        int x = 42;
  26.796 +        cxListAdd(left, &x);
  26.797 +        ASSERT_GT(left->size, right->size);
  26.798 +        EXPECT_GT(cxListCompare(left, right), 0);
  26.799 +        EXPECT_LT(cxListCompare(right, left), 0);
  26.800 +        cxListAdd(right, &x);
  26.801 +        ASSERT_EQ(left->size, right->size);
  26.802 +        EXPECT_EQ(cxListCompare(left, right), 0);
  26.803 +        int a = 5, b = 10;
  26.804 +        cxListInsert(left, 15, &a);
  26.805 +        cxListInsert(right, 15, &b);
  26.806 +        ASSERT_EQ(left->size, right->size);
  26.807 +        EXPECT_LT(cxListCompare(left, right), 0);
  26.808 +        EXPECT_GT(cxListCompare(right, left), 0);
  26.809 +        *(int *) cxListAt(left, 15) = 10;
  26.810 +        EXPECT_EQ(cxListCompare(left, right), 0);
  26.811 +    }
  26.812 +};
  26.813 +
  26.814 +class LinkedList : public HighLevelTest {
  26.815 +};
  26.816 +
  26.817 +class PointerLinkedList : public HighLevelTest {
  26.818 +};
  26.819 +
  26.820 +class ArrayList : public HighLevelTest {
  26.821 +};
  26.822 +
  26.823 +TEST_F(PointerLinkedList, cxListStorePointers) {
  26.824 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, 47));
  26.825 +    EXPECT_FALSE(cxListIsStoringPointers(list));
  26.826 +    cxListStorePointers(list);
  26.827 +    EXPECT_EQ(list->itemsize, sizeof(void *));
  26.828 +    EXPECT_NE(list->cl, nullptr);
  26.829 +    EXPECT_NE(list->climpl, nullptr);
  26.830 +    EXPECT_TRUE(cxListIsStoringPointers(list));
  26.831 +    cxListStoreObjects(list);
  26.832 +    EXPECT_NE(list->cl, nullptr);
  26.833 +    EXPECT_EQ(list->climpl, nullptr);
  26.834 +    EXPECT_FALSE(cxListIsStoringPointers(list));
  26.835 +}
  26.836 +
  26.837 +TEST_F(LinkedList, cxLinkedListCreate) {
  26.838 +    CxList *list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  26.839 +    ASSERT_NE(list, nullptr);
  26.840 +    EXPECT_EQ(list->itemsize, sizeof(int));
  26.841 +    EXPECT_EQ(list->capacity, (size_t) -1);
  26.842 +    verifyCreate(list);
  26.843 +}
  26.844 +
  26.845 +TEST_F(ArrayList, cxArrayListCreate) {
  26.846 +    CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8));
  26.847 +    ASSERT_NE(list, nullptr);
  26.848 +    EXPECT_EQ(list->itemsize, sizeof(int));
  26.849 +    EXPECT_EQ(list->capacity, 8);
  26.850 +    verifyCreate(list);
  26.851 +}
  26.852 +
  26.853 +TEST_F(LinkedList, cxListAdd) {
  26.854 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  26.855 +    verifyAdd(list, false);
  26.856 +}
  26.857 +
  26.858 +TEST_F(PointerLinkedList, cxListAdd) {
  26.859 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  26.860 +    cxListStorePointers(list);
  26.861 +    verifyAdd(list, true);
  26.862 +}
  26.863 +
  26.864 +TEST_F(ArrayList, cxListAdd) {
  26.865 +    auto list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8));
  26.866 +    verifyAdd(list, false);
  26.867 +}
  26.868 +
  26.869 +TEST_F(LinkedList, cxListInsert) {
  26.870 +    verifyInsert(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  26.871 +}
  26.872 +
  26.873 +TEST_F(PointerLinkedList, cxListInsert) {
  26.874 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  26.875 +    cxListStorePointers(list);
  26.876 +    verifyInsert(list);
  26.877 +}
  26.878 +
  26.879 +TEST_F(ArrayList, cxListInsert) {
  26.880 +    verifyInsert(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 2)));
  26.881 +}
  26.882 +
  26.883 +TEST_F(LinkedList, cxListInsertArray) {
  26.884 +    verifyInsertArray(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  26.885 +}
  26.886 +
  26.887 +TEST_F(PointerLinkedList, cxListInsertArray) {
  26.888 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  26.889 +    cxListStorePointers(list);
  26.890 +    verifyInsertArray(list, true);
  26.891 +}
  26.892 +
  26.893 +TEST_F(ArrayList, cxListInsertArray) {
  26.894 +    verifyInsertArray(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 4)));
  26.895 +}
  26.896 +
  26.897 +TEST_F(LinkedList, cxListRemove) {
  26.898 +    verifyRemove(linkedListFromTestData());
  26.899 +}
  26.900 +
  26.901 +TEST_F(PointerLinkedList, cxListRemove) {
  26.902 +    verifyRemove(pointerLinkedListFromTestData());
  26.903 +}
  26.904 +
  26.905 +TEST_F(ArrayList, cxListRemove) {
  26.906 +    verifyRemove(arrayListFromTestData());
  26.907 +}
  26.908 +
  26.909 +TEST_F(LinkedList, cxListAt) {
  26.910 +    verifyAt(linkedListFromTestData());
  26.911 +}
  26.912 +
  26.913 +TEST_F(PointerLinkedList, cxListAt) {
  26.914 +    verifyAt(pointerLinkedListFromTestData());
  26.915 +}
  26.916 +
  26.917 +TEST_F(ArrayList, cxListAt) {
  26.918 +    verifyAt(arrayListFromTestData());
  26.919 +}
  26.920 +
  26.921 +TEST_F(LinkedList, cxListFind) {
  26.922 +    verifyFind(linkedListFromTestData());
  26.923 +}
  26.924 +
  26.925 +TEST_F(PointerLinkedList, cxListFind) {
  26.926 +    verifyFind(pointerLinkedListFromTestData());
  26.927 +}
  26.928 +
  26.929 +TEST_F(ArrayList, cxListFind) {
  26.930 +    verifyFind(arrayListFromTestData());
  26.931 +}
  26.932 +
  26.933 +TEST_F(LinkedList, cxListSort) {
  26.934 +    verifySort(linkedListFromTestData());
  26.935 +}
  26.936 +
  26.937 +TEST_F(PointerLinkedList, cxListSort) {
  26.938 +    verifySort(pointerLinkedListFromTestData());
  26.939 +}
  26.940 +
  26.941 +TEST_F(ArrayList, cxListSort) {
  26.942 +    verifySort(arrayListFromTestData());
  26.943 +}
  26.944 +
  26.945 +TEST_F(LinkedList, Iterator) {
  26.946 +    verifyIterator(linkedListFromTestData());
  26.947 +}
  26.948 +
  26.949 +TEST_F(PointerLinkedList, Iterator) {
  26.950 +    verifyIterator(pointerLinkedListFromTestData());
  26.951 +}
  26.952 +
  26.953 +TEST_F(ArrayList, Iterator) {
  26.954 +    verifyIterator(arrayListFromTestData());
  26.955 +}
  26.956 +
  26.957 +TEST_F(LinkedList, InsertViaIterator) {
  26.958 +    int fivenums[] = {0, 1, 2, 3, 4, 5};
  26.959 +    CxList *list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  26.960 +    cxListAddArray(list, fivenums, 5);
  26.961 +    verifyInsertViaIterator(list);
  26.962 +}
  26.963 +
  26.964 +TEST_F(PointerLinkedList, InsertViaIterator) {
  26.965 +    int fivenums[] = {0, 1, 2, 3, 4, 5};
  26.966 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  26.967 +    cxListStorePointers(list);
  26.968 +    // note: cannot use cxListAddArray() because we don't have a list of pointers
  26.969 +    cx_for_n(i, 5) cxListAdd(list, &fivenums[i]);
  26.970 +    verifyInsertViaIterator(list);
  26.971 +}
  26.972 +
  26.973 +TEST_F(ArrayList, InsertViaIterator) {
  26.974 +    int fivenums[] = {0, 1, 2, 3, 4, 5};
  26.975 +    CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 4));
  26.976 +    cxListAddArray(list, fivenums, 5);
  26.977 +    verifyInsertViaIterator(list);
  26.978 +}
  26.979 +
  26.980 +TEST_F(LinkedList, cxListReverse) {
  26.981 +    verifyReverse(linkedListFromTestData());
  26.982 +}
  26.983 +
  26.984 +TEST_F(PointerLinkedList, cxListReverse) {
  26.985 +    verifyReverse(pointerLinkedListFromTestData());
  26.986 +}
  26.987 +
  26.988 +TEST_F(ArrayList, cxListReverse) {
  26.989 +    verifyReverse(arrayListFromTestData());
  26.990 +}
  26.991 +
  26.992 +TEST_F(LinkedList, cxListCompare) {
  26.993 +    auto left = linkedListFromTestData();
  26.994 +    auto right = linkedListFromTestData();
  26.995 +    verifyCompare(left, right);
  26.996 +}
  26.997 +
  26.998 +TEST_F(LinkedList, cxListCompareWithPtrList) {
  26.999 +    auto left = linkedListFromTestData();
 26.1000 +    auto right = pointerLinkedListFromTestData();
 26.1001 +    verifyCompare(left, right);
 26.1002 +}
 26.1003 +
 26.1004 +TEST_F(LinkedList, cxListCompareWithArrayList) {
 26.1005 +    auto left = linkedListFromTestData();
 26.1006 +    auto right = arrayListFromTestData();
 26.1007 +    verifyCompare(left, right);
 26.1008 +}
 26.1009 +
 26.1010 +TEST_F(PointerLinkedList, cxListCompare) {
 26.1011 +    auto left = pointerLinkedListFromTestData();
 26.1012 +    auto right = pointerLinkedListFromTestData();
 26.1013 +    verifyCompare(left, right);
 26.1014 +}
 26.1015 +
 26.1016 +TEST_F(PointerLinkedList, cxListCompareWithNormalList) {
 26.1017 +    auto left = pointerLinkedListFromTestData();
 26.1018 +    auto right = linkedListFromTestData();
 26.1019 +    verifyCompare(left, right);
 26.1020 +}
 26.1021 +
 26.1022 +TEST_F(PointerLinkedList, cxListCompareWithArrayList) {
 26.1023 +    auto left = pointerLinkedListFromTestData();
 26.1024 +    auto right = arrayListFromTestData();
 26.1025 +    verifyCompare(left, right);
 26.1026 +}
 26.1027 +
 26.1028 +TEST_F(ArrayList, cxListCompare) {
 26.1029 +    auto left = arrayListFromTestData();
 26.1030 +    auto right = arrayListFromTestData();
 26.1031 +    verifyCompare(left, right);
 26.1032 +}
 26.1033 +
 26.1034 +TEST_F(ArrayList, cxListCompareWithPtrList) {
 26.1035 +    auto left = arrayListFromTestData();
 26.1036 +    auto right = pointerLinkedListFromTestData();
 26.1037 +    verifyCompare(left, right);
 26.1038 +}
 26.1039 +
 26.1040 +TEST_F(ArrayList, cxListCompareWithNormalList) {
 26.1041 +    auto left = arrayListFromTestData();
 26.1042 +    auto right = linkedListFromTestData();
 26.1043 +    verifyCompare(left, right);
 26.1044 +}
 26.1045 +
 26.1046 +TEST_F(PointerLinkedList, NoDestructor) {
 26.1047 +    void *item = cxMalloc(&testingAllocator, sizeof(int));
 26.1048 +    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 26.1049 +    cxListStorePointers(list);
 26.1050 +    cxListAdd(list, item);
 26.1051 +    ASSERT_FALSE(testingAllocator.verify());
 26.1052 +    cxListDestroy(list);
 26.1053 +    EXPECT_FALSE(testingAllocator.verify());
 26.1054 +    cxFree(&testingAllocator, item);
 26.1055 +    EXPECT_TRUE(testingAllocator.verify());
 26.1056 +}
 26.1057 +
 26.1058 +TEST_F(PointerLinkedList, SimpleDestructor) {
 26.1059 +    int item = 0;
 26.1060 +    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 26.1061 +    cxListStorePointers(list);
 26.1062 +    list->content_destructor_type = CX_DESTRUCTOR_SIMPLE;
 26.1063 +    list->simple_destructor = [](void *elem) { *(int *) elem = 42; };
 26.1064 +    cxListAdd(list, &item);
 26.1065 +    cxListDestroy(list);
 26.1066 +    EXPECT_EQ(item, 42);
 26.1067 +}
 26.1068 +
 26.1069 +TEST_F(PointerLinkedList, AdvancedDestructor) {
 26.1070 +    void *item = cxMalloc(&testingAllocator, sizeof(int));
 26.1071 +    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 26.1072 +    cxListStorePointers(list);
 26.1073 +    list->content_destructor_type = CX_DESTRUCTOR_ADVANCED;
 26.1074 +    list->advanced_destructor.data = &testingAllocator;
 26.1075 +    list->advanced_destructor.func = (cx_destructor_func2) cxFree;
 26.1076 +    cxListAdd(list, item);
 26.1077 +    ASSERT_FALSE(testingAllocator.verify());
 26.1078 +    cxListDestroy(list);
 26.1079 +    EXPECT_TRUE(testingAllocator.verify());
 26.1080 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/tests/test_map.cpp	Tue Feb 07 21:55:37 2023 +0100
    27.3 @@ -0,0 +1,272 @@
    27.4 +/*
    27.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    27.6 + *
    27.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    27.8 + *
    27.9 + * Redistribution and use in source and binary forms, with or without
   27.10 + * modification, are permitted provided that the following conditions are met:
   27.11 + *
   27.12 + *   1. Redistributions of source code must retain the above copyright
   27.13 + *      notice, this list of conditions and the following disclaimer.
   27.14 + *
   27.15 + *   2. Redistributions in binary form must reproduce the above copyright
   27.16 + *      notice, this list of conditions and the following disclaimer in the
   27.17 + *      documentation and/or other materials provided with the distribution.
   27.18 + *
   27.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   27.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   27.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   27.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   27.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   27.29 + * POSSIBILITY OF SUCH DAMAGE.
   27.30 + */
   27.31 +
   27.32 +#include "cx/hash_map.h"
   27.33 +#include "cx/utils.h"
   27.34 +#include "util_allocator.h"
   27.35 +
   27.36 +#include <gtest/gtest.h>
   27.37 +#include <unordered_map>
   27.38 +#include <unordered_set>
   27.39 +
   27.40 +struct map_operation {
   27.41 +    enum {
   27.42 +        put, rm
   27.43 +    } op;
   27.44 +    char const *key;
   27.45 +    char const *value;
   27.46 +};
   27.47 +
   27.48 +auto generate_map_operations() -> std::vector<map_operation> {
   27.49 +    return {
   27.50 +            {map_operation::put, "key 1",          "test"},
   27.51 +            {map_operation::put, "key 2",          "blub"},
   27.52 +            {map_operation::put, "key 3",          "hallo"},
   27.53 +            {map_operation::put, "key 2",          "foobar"},
   27.54 +            {map_operation::put, "key 4",          "value 4"},
   27.55 +            {map_operation::put, "key 5",          "value 5"},
   27.56 +            {map_operation::put, "key 6",          "value 6"},
   27.57 +            {map_operation::rm,  "key 4",          nullptr},
   27.58 +            {map_operation::put, "key 7",          "value 7"},
   27.59 +            {map_operation::put, "key 8",          "value 8"},
   27.60 +            {map_operation::rm,  "does not exist", nullptr},
   27.61 +            {map_operation::put, "key 9",          "value 9"},
   27.62 +            {map_operation::put, "key 6",          "other value"},
   27.63 +            {map_operation::put, "key 7",          "something else"},
   27.64 +            {map_operation::rm,  "key 8",          nullptr},
   27.65 +            {map_operation::rm,  "key 2",          nullptr},
   27.66 +            {map_operation::put, "key 8",          "new value"},
   27.67 +    };
   27.68 +}
   27.69 +
   27.70 +static void verify_map_contents(
   27.71 +        CxMap *map,
   27.72 +        std::unordered_map<std::string, std::string> const &refmap
   27.73 +) {
   27.74 +    // verify key iterator
   27.75 +    {
   27.76 +        auto keyiter = cxMapIteratorKeys(map);
   27.77 +        std::unordered_set<std::string> keys;
   27.78 +        cx_foreach(CxHashKey*, elem, keyiter) {
   27.79 +            keys.insert(std::string(elem->data.cstr, elem->len));
   27.80 +        }
   27.81 +        EXPECT_EQ(keyiter.index, map->size);
   27.82 +        ASSERT_EQ(keys.size(), map->size);
   27.83 +        for (auto &&k: keys) {
   27.84 +            EXPECT_NE(refmap.find(k), refmap.end());
   27.85 +        }
   27.86 +    }
   27.87 +
   27.88 +    // verify value iterator
   27.89 +    {
   27.90 +        auto valiter = cxMapIteratorValues(map);
   27.91 +        std::unordered_set<std::string> values; // we use that the values in our test data are unique strings
   27.92 +        cx_foreach(char const*, elem, valiter) {
   27.93 +            values.insert(std::string(elem));
   27.94 +        }
   27.95 +        EXPECT_EQ(valiter.index, map->size);
   27.96 +        ASSERT_EQ(values.size(), map->size);
   27.97 +        for (auto &&v: values) {
   27.98 +            EXPECT_NE(std::find_if(refmap.begin(), refmap.end(),
   27.99 +                                   [v](auto const &e) { return e.second == v; }), refmap.end());
  27.100 +        }
  27.101 +    }
  27.102 +
  27.103 +    // verify pair iterator
  27.104 +    {
  27.105 +        auto pairiter = cxMapIterator(map);
  27.106 +        std::unordered_map<std::string, std::string> pairs;
  27.107 +        cx_foreach(CxMapEntry*, entry, pairiter) {
  27.108 +            pairs[std::string(entry->key->data.cstr, entry->key->len)] = std::string((char *) entry->value);
  27.109 +        }
  27.110 +        EXPECT_EQ(pairiter.index, map->size);
  27.111 +        ASSERT_EQ(pairs.size(), refmap.size());
  27.112 +        for (auto &&p: pairs) {
  27.113 +            ASSERT_EQ(p.second, refmap.at(p.first));
  27.114 +        }
  27.115 +    }
  27.116 +}
  27.117 +
  27.118 +TEST(CxHashMap, Create) {
  27.119 +    CxTestingAllocator allocator;
  27.120 +    auto map = cxHashMapCreate(&allocator, 0);
  27.121 +    auto hmap = reinterpret_cast<struct cx_hash_map_s *>(map);
  27.122 +    EXPECT_GT(hmap->bucket_count, 0);
  27.123 +    cx_for_n(i, hmap->bucket_count) {
  27.124 +        EXPECT_EQ(hmap->buckets[i], nullptr);
  27.125 +    }
  27.126 +    EXPECT_EQ(map->size, 0);
  27.127 +    EXPECT_EQ(map->allocator, &allocator);
  27.128 +
  27.129 +    cxMapDestroy(map);
  27.130 +    EXPECT_TRUE(allocator.verify());
  27.131 +}
  27.132 +
  27.133 +TEST(CxHashMap, BasicOperations) {
  27.134 +    // create the map
  27.135 +    CxTestingAllocator allocator;
  27.136 +    auto map = cxHashMapCreate(&allocator, 8);
  27.137 +
  27.138 +    // create a reference map
  27.139 +    std::unordered_map<std::string, std::string> refmap;
  27.140 +
  27.141 +    // generate operations
  27.142 +    auto ops = generate_map_operations();
  27.143 +
  27.144 +    // verify iterators for empty map
  27.145 +    verify_map_contents(map, refmap);
  27.146 +
  27.147 +    // execute operations and verify results
  27.148 +    for (auto &&op: ops) {
  27.149 +        CxHashKey key = cx_hash_key_str(op.key);
  27.150 +        key.hash = 0; // force the hash map to compute the hash
  27.151 +        if (op.op == map_operation::put) {
  27.152 +            // execute a put operation and verify that the exact value can be read back
  27.153 +            refmap[std::string(op.key)] = std::string(op.value);
  27.154 +            int result = cxMapPut(map, key, (void *) op.value);
  27.155 +            EXPECT_EQ(result, 0);
  27.156 +            auto added = cxMapGet(map, key);
  27.157 +            EXPECT_EQ(memcmp(op.value, added, strlen(op.value)), 0);
  27.158 +        } else {
  27.159 +            // execute a remove and verify that the removed element was returned (or nullptr)
  27.160 +            auto found = refmap.find(op.key);
  27.161 +            auto removed = cxMapRemove(map, key);
  27.162 +            if (found == refmap.end()) {
  27.163 +                EXPECT_EQ(removed, nullptr);
  27.164 +            } else {
  27.165 +                EXPECT_EQ(std::string((char *) removed), found->second);
  27.166 +                refmap.erase(found);
  27.167 +            }
  27.168 +        }
  27.169 +        // compare the current map state with the reference map
  27.170 +        verify_map_contents(map, refmap);
  27.171 +    }
  27.172 +
  27.173 +    // destroy the map and verify the memory (de)allocations
  27.174 +    cxMapDestroy(map);
  27.175 +    EXPECT_TRUE(allocator.verify());
  27.176 +}
  27.177 +
  27.178 +TEST(CxHashMap, RemoveViaIterator) {
  27.179 +    CxTestingAllocator allocator;
  27.180 +    auto map = cxHashMapCreate(&allocator, 4);
  27.181 +
  27.182 +    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  27.183 +    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  27.184 +    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  27.185 +    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  27.186 +    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  27.187 +    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  27.188 +
  27.189 +    auto iter = cxMapMutIterator(map);
  27.190 +    cx_foreach(CxMapEntry*, entry, iter) {
  27.191 +        if (entry->key->data.cstr[4] % 2 == 1) cxIteratorFlagRemoval(iter);
  27.192 +    }
  27.193 +    EXPECT_EQ(map->size, 3);
  27.194 +    EXPECT_EQ(iter.index, map->size);
  27.195 +
  27.196 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
  27.197 +    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
  27.198 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
  27.199 +    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 4")), nullptr);
  27.200 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 5")), nullptr);
  27.201 +    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 6")), nullptr);
  27.202 +
  27.203 +    cxMapDestroy(map);
  27.204 +    EXPECT_TRUE(allocator.verify());
  27.205 +}
  27.206 +
  27.207 +TEST(CxHashMap, RehashNotRequired) {
  27.208 +    CxTestingAllocator allocator;
  27.209 +    auto map = cxHashMapCreate(&allocator, 8);
  27.210 +
  27.211 +    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  27.212 +    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  27.213 +    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  27.214 +    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  27.215 +    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  27.216 +    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  27.217 +
  27.218 +    // 6/8 does not exceed 0.75, therefore the function should not rehash
  27.219 +    int result = cxMapRehash(map);
  27.220 +    EXPECT_EQ(result, 0);
  27.221 +    EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 8);
  27.222 +
  27.223 +    cxMapDestroy(map);
  27.224 +    EXPECT_TRUE(allocator.verify());
  27.225 +}
  27.226 +
  27.227 +TEST(CxHashMap, Rehash) {
  27.228 +    CxTestingAllocator allocator;
  27.229 +    auto map = cxHashMapCreate(&allocator, 8);
  27.230 +
  27.231 +    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  27.232 +    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  27.233 +    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  27.234 +    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  27.235 +    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  27.236 +    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  27.237 +    cxMapPut(map, cx_hash_key_str("key 7"), (void *) "val 7");
  27.238 +
  27.239 +    int result = cxMapRehash(map);
  27.240 +    EXPECT_EQ(result, 0);
  27.241 +    EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 17);
  27.242 +    EXPECT_EQ(map->size, 7);
  27.243 +
  27.244 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 1")), "val 1"), 0);
  27.245 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 2")), "val 2"), 0);
  27.246 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 3")), "val 3"), 0);
  27.247 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 4")), "val 4"), 0);
  27.248 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 5")), "val 5"), 0);
  27.249 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 6")), "val 6"), 0);
  27.250 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 7")), "val 7"), 0);
  27.251 +
  27.252 +    cxMapDestroy(map);
  27.253 +    EXPECT_TRUE(allocator.verify());
  27.254 +}
  27.255 +
  27.256 +TEST(CxHashMap, Clear) {
  27.257 +    CxTestingAllocator allocator;
  27.258 +    auto map = cxHashMapCreate(&allocator, 0);
  27.259 +    
  27.260 +    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  27.261 +    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  27.262 +    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  27.263 +
  27.264 +    EXPECT_EQ(map->size, 3);
  27.265 +
  27.266 +    cxMapClear(map);
  27.267 +
  27.268 +    EXPECT_EQ(map->size, 0);
  27.269 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
  27.270 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
  27.271 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
  27.272 +
  27.273 +    cxMapDestroy(map);
  27.274 +    EXPECT_TRUE(allocator.verify());
  27.275 +}
  27.276 \ No newline at end of file
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/tests/test_printf.cpp	Tue Feb 07 21:55:37 2023 +0100
    28.3 @@ -0,0 +1,248 @@
    28.4 +/*
    28.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    28.6 + *
    28.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    28.8 + *
    28.9 + * Redistribution and use in source and binary forms, with or without
   28.10 + * modification, are permitted provided that the following conditions are met:
   28.11 + *
   28.12 + *   1. Redistributions of source code must retain the above copyright
   28.13 + *      notice, this list of conditions and the following disclaimer.
   28.14 + *
   28.15 + *   2. Redistributions in binary form must reproduce the above copyright
   28.16 + *      notice, this list of conditions and the following disclaimer in the
   28.17 + *      documentation and/or other materials provided with the distribution.
   28.18 + *
   28.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   28.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   28.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   28.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   28.29 + * POSSIBILITY OF SUCH DAMAGE.
   28.30 + */
   28.31 +
   28.32 +#include "cx/printf.h"
   28.33 +#include "cx/buffer.h"
   28.34 +
   28.35 +#include <gtest/gtest.h>
   28.36 +#include "util_allocator.h"
   28.37 +
   28.38 +class PrintfFixture : public ::testing::Test {
   28.39 +protected:
   28.40 +    std::string buf;
   28.41 +    CxTestingAllocator alloc;
   28.42 +
   28.43 +    void TearDown() override {
   28.44 +        buf.clear();
   28.45 +        ASSERT_TRUE(alloc.verify());
   28.46 +    }
   28.47 +
   28.48 +    static size_t write_func(
   28.49 +            void const *src,
   28.50 +            size_t esize,
   28.51 +            size_t ecount,
   28.52 +            void *target
   28.53 +    ) {
   28.54 +        auto str = reinterpret_cast<char const *>(src);
   28.55 +        auto buf = reinterpret_cast<std::string *>(target);
   28.56 +        EXPECT_EQ(esize, 1);
   28.57 +        EXPECT_EQ(strlen(str), ecount);
   28.58 +        *buf = str;
   28.59 +        return ecount;
   28.60 +    }
   28.61 +};
   28.62 +
   28.63 +
   28.64 +TEST_F(PrintfFixture, BPrintf) {
   28.65 +    CxBuffer buf;
   28.66 +    cxBufferInit(&buf, nullptr, 64, &alloc, 0);
   28.67 +
   28.68 +    auto r = cx_bprintf(&buf, "This %s aged %u years in a %2XSK.", "Test", 10, 0xca);
   28.69 +    EXPECT_EQ(r, 34);
   28.70 +    EXPECT_EQ(buf.size, 34);
   28.71 +    buf.space[r] = '\0';
   28.72 +    EXPECT_STREQ(buf.space, "This Test aged 10 years in a CASK.");
   28.73 +
   28.74 +    cxBufferDestroy(&buf);
   28.75 +}
   28.76 +
   28.77 +TEST_F(PrintfFixture, FPrintf) {
   28.78 +    auto h = "Hello";
   28.79 +    size_t r;
   28.80 +
   28.81 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "teststring");
   28.82 +    EXPECT_EQ(r, 10);
   28.83 +    EXPECT_EQ(buf, "teststring");
   28.84 +
   28.85 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%10s]", h);
   28.86 +    EXPECT_EQ(r, 12);
   28.87 +    EXPECT_EQ(buf, "[     Hello]");
   28.88 +
   28.89 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-10s]", h);
   28.90 +    EXPECT_EQ(r, 12);
   28.91 +    EXPECT_EQ(buf, "[Hello     ]");
   28.92 +
   28.93 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%*s]", 10, h);
   28.94 +    EXPECT_EQ(r, 12);
   28.95 +    EXPECT_EQ(buf, "[     Hello]");
   28.96 +
   28.97 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-10.*s]", 4, h);
   28.98 +    EXPECT_EQ(r, 12);
   28.99 +    EXPECT_EQ(buf, "[Hell      ]");
  28.100 +
  28.101 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-*.*s]", 10, 4, h);
  28.102 +    EXPECT_EQ(r, 12);
  28.103 +    EXPECT_EQ(buf, "[Hell      ]");
  28.104 +
  28.105 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%c", 'A');
  28.106 +    EXPECT_EQ(r, 1);
  28.107 +    EXPECT_EQ(buf, "A");
  28.108 +
  28.109 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
  28.110 +    EXPECT_EQ(r, 19);
  28.111 +    EXPECT_EQ(buf, "1 2 000003 0  +4 -4");
  28.112 +
  28.113 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%x %x %X %#x", 5, 10, 10, 6);
  28.114 +    EXPECT_EQ(r, 9);
  28.115 +    EXPECT_EQ(buf, "5 a A 0x6");
  28.116 +
  28.117 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%o %#o %#o", 10, 10, 4);
  28.118 +    EXPECT_EQ(r, 9);
  28.119 +    EXPECT_EQ(buf, "12 012 04");
  28.120 +
  28.121 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
  28.122 +    EXPECT_EQ(r, 16);
  28.123 +    EXPECT_EQ(buf, "01.50 1.50  1.50");
  28.124 +
  28.125 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "'%*c'", 5, 'x');
  28.126 +    EXPECT_EQ(r, 7);
  28.127 +    EXPECT_EQ(buf, "'    x'");
  28.128 +
  28.129 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "'%*c'", -5, 'x');
  28.130 +    EXPECT_EQ(r, 7);
  28.131 +    EXPECT_EQ(buf, "'x    '");
  28.132 +}
  28.133 +
  28.134 +TEST_F(PrintfFixture, BPrintfLargeString) {
  28.135 +    CxBuffer buf;
  28.136 +    cxBufferInit(&buf, nullptr, 64, &alloc, CX_BUFFER_AUTO_EXTEND);
  28.137 +
  28.138 +    auto aaa = std::string(512, 'a');
  28.139 +    auto bbb = std::string(512, 'b');
  28.140 +
  28.141 +    auto r = cx_bprintf(&buf, "After %s comes %s.", aaa.data(), bbb.data());
  28.142 +    EXPECT_EQ(r, 1038);
  28.143 +    EXPECT_EQ(buf.size, 1038);
  28.144 +    cxBufferPut(&buf, 0);
  28.145 +    EXPECT_EQ(buf.space, std::string("After ") + aaa + " comes " + bbb + ".");
  28.146 +
  28.147 +    cxBufferDestroy(&buf);
  28.148 +}
  28.149 +
  28.150 +TEST_F(PrintfFixture, BPrintfNoCap) {
  28.151 +    CxBuffer buf;
  28.152 +    char space[20];
  28.153 +    memset(space, 'a', 20);
  28.154 +    cxBufferInit(&buf, space, 16, &alloc, 0);
  28.155 +
  28.156 +    auto r = cx_bprintf(&buf, "Hello %s with more than %d chars.", "string", 16);
  28.157 +    EXPECT_EQ(r, 16);
  28.158 +    EXPECT_EQ(buf.size, 16);
  28.159 +    EXPECT_EQ(0, memcmp(space, "Hello string witaaaa", 20));
  28.160 +
  28.161 +    cxBufferDestroy(&buf);
  28.162 +}
  28.163 +
  28.164 +TEST_F(PrintfFixture, SPrintf) {
  28.165 +    auto h = "Hello";
  28.166 +
  28.167 +    std::vector<char *> fl;
  28.168 +    cxmutstr r;
  28.169 +
  28.170 +    r = cx_asprintf_a(&alloc, "teststring");
  28.171 +    EXPECT_EQ(r.length, 10);
  28.172 +    EXPECT_STREQ(r.ptr, "teststring");
  28.173 +    fl.push_back(r.ptr);
  28.174 +
  28.175 +    r = cx_asprintf_a(&alloc, "[%10s]", h);
  28.176 +    EXPECT_EQ(r.length, 12);
  28.177 +    EXPECT_STREQ(r.ptr, "[     Hello]");
  28.178 +    fl.push_back(r.ptr);
  28.179 +
  28.180 +    r = cx_asprintf_a(&alloc, "[%-10s]", h);
  28.181 +    EXPECT_EQ(r.length, 12);
  28.182 +    EXPECT_STREQ(r.ptr, "[Hello     ]");
  28.183 +    fl.push_back(r.ptr);
  28.184 +
  28.185 +    r = cx_asprintf_a(&alloc, "[%*s]", 10, h);
  28.186 +    EXPECT_EQ(r.length, 12);
  28.187 +    EXPECT_STREQ(r.ptr, "[     Hello]");
  28.188 +    fl.push_back(r.ptr);
  28.189 +
  28.190 +    r = cx_asprintf_a(&alloc, "[%-10.*s]", 4, h);
  28.191 +    EXPECT_EQ(r.length, 12);
  28.192 +    EXPECT_STREQ(r.ptr, "[Hell      ]");
  28.193 +    fl.push_back(r.ptr);
  28.194 +
  28.195 +    r = cx_asprintf_a(&alloc, "[%-*.*s]", 10, 4, h);
  28.196 +    EXPECT_EQ(r.length, 12);
  28.197 +    EXPECT_STREQ(r.ptr, "[Hell      ]");
  28.198 +    fl.push_back(r.ptr);
  28.199 +
  28.200 +    r = cx_asprintf_a(&alloc, "%c", 'A');
  28.201 +    EXPECT_EQ(r.length, 1);
  28.202 +    EXPECT_STREQ(r.ptr, "A");
  28.203 +    fl.push_back(r.ptr);
  28.204 +
  28.205 +    r = cx_asprintf_a(&alloc, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
  28.206 +    EXPECT_EQ(r.length, 19);
  28.207 +    EXPECT_STREQ(r.ptr, "1 2 000003 0  +4 -4");
  28.208 +    fl.push_back(r.ptr);
  28.209 +
  28.210 +    r = cx_asprintf_a(&alloc, "%x %x %X %#x", 5, 10, 10, 6);
  28.211 +    EXPECT_EQ(r.length, 9);
  28.212 +    EXPECT_STREQ(r.ptr, "5 a A 0x6");
  28.213 +    fl.push_back(r.ptr);
  28.214 +
  28.215 +    r = cx_asprintf_a(&alloc, "%o %#o %#o", 10, 10, 4);
  28.216 +    EXPECT_EQ(r.length, 9);
  28.217 +    EXPECT_STREQ(r.ptr, "12 012 04");
  28.218 +    fl.push_back(r.ptr);
  28.219 +
  28.220 +    r = cx_asprintf_a(&alloc, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
  28.221 +    EXPECT_EQ(r.length, 16);
  28.222 +    EXPECT_STREQ(r.ptr, "01.50 1.50  1.50");
  28.223 +    fl.push_back(r.ptr);
  28.224 +
  28.225 +    r = cx_asprintf_a(&alloc, "'%*c'", 5, 'x');
  28.226 +    EXPECT_EQ(r.length, 7);
  28.227 +    EXPECT_STREQ(r.ptr, "'    x'");
  28.228 +    fl.push_back(r.ptr);
  28.229 +
  28.230 +    r = cx_asprintf_a(&alloc, "'%*c'", -5, 'x');
  28.231 +    EXPECT_EQ(r.length, 7);
  28.232 +    EXPECT_STREQ(r.ptr, "'x    '");
  28.233 +    fl.push_back(r.ptr);
  28.234 +
  28.235 +    for (auto c: fl) {
  28.236 +        auto s = cx_mutstrn(c, 0);
  28.237 +        cx_strfree_a(&alloc, &s);
  28.238 +    }
  28.239 +}
  28.240 +
  28.241 +TEST_F(PrintfFixture, SPrintfLargeString) {
  28.242 +    auto aaa = std::string(512, 'a');
  28.243 +    auto bbb = std::string(512, 'b');
  28.244 +
  28.245 +    auto r = cx_asprintf_a(&alloc, "After %s comes %s.", aaa.data(), bbb.data());
  28.246 +    EXPECT_EQ(r.length, 1038);
  28.247 +    EXPECT_EQ(r.ptr, std::string("After ") + aaa + " comes " + bbb + ".");
  28.248 +    EXPECT_EQ(r.ptr[1038], '\0');
  28.249 +
  28.250 +    cx_strfree_a(&alloc, &r);
  28.251 +}
  28.252 \ No newline at end of file
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/tests/test_string.cpp	Tue Feb 07 21:55:37 2023 +0100
    29.3 @@ -0,0 +1,865 @@
    29.4 +/*
    29.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    29.6 + *
    29.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    29.8 + *
    29.9 + * Redistribution and use in source and binary forms, with or without
   29.10 + * modification, are permitted provided that the following conditions are met:
   29.11 + *
   29.12 + *   1. Redistributions of source code must retain the above copyright
   29.13 + *      notice, this list of conditions and the following disclaimer.
   29.14 + *
   29.15 + *   2. Redistributions in binary form must reproduce the above copyright
   29.16 + *      notice, this list of conditions and the following disclaimer in the
   29.17 + *      documentation and/or other materials provided with the distribution.
   29.18 + *
   29.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   29.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   29.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   29.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   29.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   29.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29.29 + * POSSIBILITY OF SUCH DAMAGE.
   29.30 + */
   29.31 +
   29.32 +#include "cx/string.h"
   29.33 +#include "util_allocator.h"
   29.34 +
   29.35 +#include <gtest/gtest.h>
   29.36 +
   29.37 +#define EXPECT_ZERO_TERMINATED(str) EXPECT_EQ((str).ptr[(str).length], '\0')
   29.38 +
   29.39 +TEST(String, construct) {
   29.40 +    cxstring s1 = cx_str("1234");
   29.41 +    cxstring s2 = cx_strn("abcd", 2);
   29.42 +    cxmutstr s3 = cx_mutstr((char *) "1234");
   29.43 +    cxmutstr s4 = cx_mutstrn((char *) "abcd", 2);
   29.44 +
   29.45 +    EXPECT_EQ(s1.length, 4);
   29.46 +    EXPECT_EQ(s2.length, 2);
   29.47 +    EXPECT_EQ(s3.length, 4);
   29.48 +    EXPECT_EQ(s4.length, 2);
   29.49 +}
   29.50 +
   29.51 +TEST(String, strfree) {
   29.52 +    CxTestingAllocator alloc;
   29.53 +    auto test = (char *) cxMalloc(&alloc, 16);
   29.54 +    cxmutstr str = cx_mutstrn(test, 16);
   29.55 +    ASSERT_EQ(str.ptr, test);
   29.56 +    EXPECT_EQ(str.length, 16);
   29.57 +    cx_strfree_a(&alloc, &str);
   29.58 +    EXPECT_EQ(str.ptr, nullptr);
   29.59 +    EXPECT_EQ(str.length, 0);
   29.60 +    EXPECT_TRUE(alloc.verify());
   29.61 +}
   29.62 +
   29.63 +TEST(String, strdup) {
   29.64 +    cxstring str = CX_STR("test");
   29.65 +    cxmutstr dup = cx_strdup(str);
   29.66 +    ASSERT_EQ(dup.length, str.length);
   29.67 +    EXPECT_STREQ(dup.ptr, str.ptr);
   29.68 +    EXPECT_ZERO_TERMINATED(dup);
   29.69 +    cx_strfree(&dup);
   29.70 +
   29.71 +    str.length = 2;
   29.72 +    dup = cx_strdup(str);
   29.73 +    ASSERT_EQ(dup.length, str.length);
   29.74 +    EXPECT_STREQ(dup.ptr, "te");
   29.75 +    EXPECT_ZERO_TERMINATED(dup);
   29.76 +    cx_strfree(&dup);
   29.77 +}
   29.78 +
   29.79 +TEST(String, strlen) {
   29.80 +    cxstring s1 = CX_STR("1234");
   29.81 +    cxstring s2 = CX_STR(".:.:.");
   29.82 +    cxstring s3 = CX_STR("X");
   29.83 +
   29.84 +    size_t len0 = cx_strlen(0);
   29.85 +    size_t len1 = cx_strlen(1, s1);
   29.86 +    size_t len2 = cx_strlen(2, s1, s2);
   29.87 +    size_t len3 = cx_strlen(3, s1, s2, s3);
   29.88 +
   29.89 +    EXPECT_EQ(len0, 0);
   29.90 +    EXPECT_EQ(len1, 4);
   29.91 +    EXPECT_EQ(len2, 9);
   29.92 +    EXPECT_EQ(len3, 10);
   29.93 +}
   29.94 +
   29.95 +TEST(String, strsubs) {
   29.96 +    cxstring str = CX_STR("A test string");
   29.97 +
   29.98 +    cxstring sub = cx_strsubs(str, 0);
   29.99 +    EXPECT_EQ(cx_strcmp(sub, str), 0);
  29.100 +
  29.101 +    sub = cx_strsubs(str, 2);
  29.102 +    EXPECT_EQ(cx_strcmp(sub, cx_str("test string")), 0);
  29.103 +
  29.104 +    sub = cx_strsubs(str, 7);
  29.105 +    EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
  29.106 +
  29.107 +    sub = cx_strsubs(str, 15);
  29.108 +    EXPECT_EQ(cx_strcmp(sub, cx_str("")), 0);
  29.109 +
  29.110 +    sub = cx_strsubsl(str, 2, 4);
  29.111 +    EXPECT_EQ(cx_strcmp(sub, cx_str("test")), 0);
  29.112 +
  29.113 +    sub = cx_strsubsl(str, 7, 3);
  29.114 +    EXPECT_EQ(cx_strcmp(sub, cx_str("str")), 0);
  29.115 +
  29.116 +    sub = cx_strsubsl(str, 7, 20);
  29.117 +    EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
  29.118 +
  29.119 +    // just for coverage, call the _m variant
  29.120 +    auto m = cx_strsubs_m(cx_mutstrn(nullptr, 0), 0);
  29.121 +    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  29.122 +}
  29.123 +
  29.124 +TEST(String, strchr) {
  29.125 +    cxstring str = CX_STR("I will find you - and I will kill you");
  29.126 +
  29.127 +    cxstring notfound = cx_strchr(str, 'x');
  29.128 +    EXPECT_EQ(notfound.length, 0);
  29.129 +
  29.130 +    cxstring result = cx_strchr(str, 'w');
  29.131 +    EXPECT_EQ(result.length, 35);
  29.132 +    EXPECT_STREQ(result.ptr, "will find you - and I will kill you");
  29.133 +
  29.134 +    // just for coverage, call the _m variant
  29.135 +    auto m = cx_strchr_m(cx_mutstrn(nullptr, 0), 'a');
  29.136 +    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  29.137 +}
  29.138 +
  29.139 +TEST(String, strrchr) {
  29.140 +    cxstring str = CX_STR("I will find you - and I will kill you");
  29.141 +
  29.142 +    cxstring notfound = cx_strrchr(str, 'x');
  29.143 +    EXPECT_EQ(notfound.length, 0);
  29.144 +
  29.145 +    cxstring result = cx_strrchr(str, 'w');
  29.146 +    EXPECT_EQ(result.length, 13);
  29.147 +    EXPECT_STREQ(result.ptr, "will kill you");
  29.148 +
  29.149 +    // just for coverage, call the _m variant
  29.150 +    auto m = cx_strrchr_m(cx_mutstrn(nullptr, 0), 'a');
  29.151 +    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  29.152 +}
  29.153 +
  29.154 +TEST(String, strstr) {
  29.155 +    cxstring str = CX_STR("find the match in this string");
  29.156 +    cxstring longstr = CX_STR(
  29.157 +            "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl"
  29.158 +            "mnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx"
  29.159 +            "yzabcdeababababnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij"
  29.160 +            "klmnopqrstuvwxyzaababababababababrstuvwxyzabcdefghijklmnopqrstuv"
  29.161 +            "abababababababababababababababababababababababababababababababab"
  29.162 +            "abababababababababababababababababababababababababababababababab"
  29.163 +            "abababababababababababababababababababababababababababababababab"
  29.164 +            "abababababababababababababababababababababababababababababababab"
  29.165 +            "abababababababababababababababababababababababababababababababab"
  29.166 +            "abababababababababababababababababababababababababababababababab"
  29.167 +            "wxyz1234567890");
  29.168 +    cxstring longstrpattern = CX_STR(
  29.169 +            "abababababababababababababababababababababababababababababababab"
  29.170 +            "abababababababababababababababababababababababababababababababab"
  29.171 +            "abababababababababababababababababababababababababababababababab"
  29.172 +            "abababababababababababababababababababababababababababababababab"
  29.173 +            "abababababababababababababababababababababababababababababababab"
  29.174 +    );
  29.175 +    cxstring longstrresult = CX_STR(
  29.176 +            "abababababababababababababababababababababababababababababababab"
  29.177 +            "abababababababababababababababababababababababababababababababab"
  29.178 +            "abababababababababababababababababababababababababababababababab"
  29.179 +            "abababababababababababababababababababababababababababababababab"
  29.180 +            "abababababababababababababababababababababababababababababababab"
  29.181 +            "abababababababababababababababababababababababababababababababab"
  29.182 +            "wxyz1234567890"
  29.183 +    );
  29.184 +
  29.185 +    cxstring notfound = cx_strstr(str, cx_str("no match"));
  29.186 +    EXPECT_EQ(notfound.length, 0);
  29.187 +
  29.188 +    cxstring result = cx_strstr(str, cx_str("match"));
  29.189 +    EXPECT_EQ(result.length, 20);
  29.190 +    EXPECT_STREQ(result.ptr, "match in this string");
  29.191 +
  29.192 +    result = cx_strstr(str, cx_str(""));
  29.193 +    EXPECT_EQ(result.length, str.length);
  29.194 +    EXPECT_STREQ(result.ptr, str.ptr);
  29.195 +
  29.196 +    result = cx_strstr(longstr, longstrpattern);
  29.197 +    EXPECT_EQ(result.length, longstrresult.length);
  29.198 +    EXPECT_STREQ(result.ptr, longstrresult.ptr);
  29.199 +
  29.200 +    // just for coverage, call the _m variant
  29.201 +    auto mstr = cx_strdup(longstr);
  29.202 +    auto m = cx_strstr_m(mstr, longstrpattern);
  29.203 +    EXPECT_EQ(m.length, longstrresult.length);
  29.204 +    EXPECT_STREQ(m.ptr, longstrresult.ptr);
  29.205 +    cx_strfree(&mstr);
  29.206 +}
  29.207 +
  29.208 +TEST(String, strcmp) {
  29.209 +    cxstring str = CX_STR("compare this");
  29.210 +
  29.211 +    EXPECT_EQ(cx_strcmp(cx_str(""), cx_str("")), 0);
  29.212 +    EXPECT_GT(cx_strcmp(str, cx_str("")), 0);
  29.213 +    EXPECT_EQ(cx_strcmp(str, cx_str("compare this")), 0);
  29.214 +    EXPECT_NE(cx_strcmp(str, cx_str("Compare This")), 0);
  29.215 +    EXPECT_LT(cx_strcmp(str, cx_str("compare tool")), 0);
  29.216 +    EXPECT_GT(cx_strcmp(str, cx_str("compare shit")), 0);
  29.217 +    EXPECT_LT(cx_strcmp(str, cx_str("compare this not")), 0);
  29.218 +    EXPECT_GT(cx_strcmp(str, cx_str("compare")), 0);
  29.219 +}
  29.220 +
  29.221 +TEST(String, strcasecmp) {
  29.222 +    cxstring str = CX_STR("compare this");
  29.223 +
  29.224 +    EXPECT_EQ(cx_strcasecmp(cx_str(""), cx_str("")), 0);
  29.225 +    EXPECT_GT(cx_strcasecmp(str, cx_str("")), 0);
  29.226 +    EXPECT_EQ(cx_strcasecmp(str, cx_str("compare this")), 0);
  29.227 +    EXPECT_EQ(cx_strcasecmp(str, cx_str("Compare This")), 0);
  29.228 +    EXPECT_LT(cx_strcasecmp(str, cx_str("compare tool")), 0);
  29.229 +    EXPECT_GT(cx_strcasecmp(str, cx_str("compare shit")), 0);
  29.230 +    EXPECT_LT(cx_strcasecmp(str, cx_str("compare this not")), 0);
  29.231 +    EXPECT_GT(cx_strcasecmp(str, cx_str("compare")), 0);
  29.232 +}
  29.233 +
  29.234 +TEST(String, strcat) {
  29.235 +    cxstring s1 = CX_STR("12");
  29.236 +    cxstring s2 = CX_STR("34");
  29.237 +    cxstring s3 = CX_STR("56");
  29.238 +    cxstring sn = {nullptr, 0};
  29.239 +
  29.240 +    CxTestingAllocator alloc;
  29.241 +
  29.242 +    cxmutstr t1 = cx_strcat_a(&alloc, 2, s1, s2);
  29.243 +    EXPECT_EQ(cx_strcmp(cx_strcast(t1), cx_str("1234")), 0);
  29.244 +    EXPECT_ZERO_TERMINATED(t1);
  29.245 +    cx_strfree_a(&alloc, &t1);
  29.246 +
  29.247 +    cxmutstr t2 = cx_strcat_a(&alloc, 3, s1, s2, s3);
  29.248 +    EXPECT_EQ(cx_strcmp(cx_strcast(t2), cx_str("123456")), 0);
  29.249 +    EXPECT_ZERO_TERMINATED(t2);
  29.250 +    cx_strfree_a(&alloc, &t2);
  29.251 +
  29.252 +    cxmutstr t3 = cx_strcat_a(&alloc, 6, s1, sn, s2, sn, s3, sn);
  29.253 +    EXPECT_EQ(cx_strcmp(cx_strcast(t3), cx_str("123456")), 0);
  29.254 +    EXPECT_ZERO_TERMINATED(t3);
  29.255 +    cx_strfree_a(&alloc, &t3);
  29.256 +
  29.257 +    cxmutstr t4 = cx_strcat_a(&alloc, 2, sn, sn);
  29.258 +    EXPECT_EQ(cx_strcmp(cx_strcast(t4), cx_str("")), 0);
  29.259 +    EXPECT_ZERO_TERMINATED(t4);
  29.260 +    cx_strfree_a(&alloc, &t4);
  29.261 +
  29.262 +    EXPECT_TRUE(alloc.verify());
  29.263 +
  29.264 +    // use the macro
  29.265 +    cxmutstr t5 = cx_strcat(3, s3, s1, s2);
  29.266 +    EXPECT_EQ(cx_strcmp(cx_strcast(t5), cx_str("561234")), 0);
  29.267 +    EXPECT_ZERO_TERMINATED(t5);
  29.268 +    cx_strfree(&t5);
  29.269 +}
  29.270 +
  29.271 +TEST(String, strsplit) {
  29.272 +
  29.273 +    cxstring test = cx_str("this,is,a,csv,string");
  29.274 +    size_t capa = 8;
  29.275 +    cxstring list[8];
  29.276 +    size_t n;
  29.277 +
  29.278 +    // special case: empty string
  29.279 +    n = cx_strsplit(test, cx_str(""), capa, list);
  29.280 +    ASSERT_EQ(n, 1);
  29.281 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  29.282 +
  29.283 +    // no delimiter occurrence
  29.284 +    n = cx_strsplit(test, cx_str("z"), capa, list);
  29.285 +    ASSERT_EQ(n, 1);
  29.286 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  29.287 +
  29.288 +    // partially matching delimiter
  29.289 +    n = cx_strsplit(test, cx_str("is,not"), capa, list);
  29.290 +    ASSERT_EQ(n, 1);
  29.291 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  29.292 +
  29.293 +    // matching single-char delimiter
  29.294 +    n = cx_strsplit(test, cx_str(","), capa, list);
  29.295 +    ASSERT_EQ(n, 5);
  29.296 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  29.297 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  29.298 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
  29.299 +    EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
  29.300 +    EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
  29.301 +
  29.302 +    // matching multi-char delimiter
  29.303 +    n = cx_strsplit(test, cx_str("is"), capa, list);
  29.304 +    ASSERT_EQ(n, 3);
  29.305 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  29.306 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
  29.307 +    EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
  29.308 +
  29.309 +    // bounded list using single-char delimiter
  29.310 +    n = cx_strsplit(test, cx_str(","), 3, list);
  29.311 +    ASSERT_EQ(n, 3);
  29.312 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  29.313 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  29.314 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  29.315 +
  29.316 +    // bounded list using multi-char delimiter
  29.317 +    n = cx_strsplit(test, cx_str("is"), 2, list);
  29.318 +    ASSERT_EQ(n, 2);
  29.319 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  29.320 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  29.321 +
  29.322 +    // start with delimiter
  29.323 +    n = cx_strsplit(test, cx_str("this"), capa, list);
  29.324 +    ASSERT_EQ(n, 2);
  29.325 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  29.326 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  29.327 +
  29.328 +    // end with delimiter
  29.329 +    n = cx_strsplit(test, cx_str("string"), capa, list);
  29.330 +    ASSERT_EQ(n, 2);
  29.331 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
  29.332 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  29.333 +
  29.334 +
  29.335 +    // end with delimiter exceed bound
  29.336 +    n = cx_strsplit(cx_str("a,b,c,"), cx_str(","), 3, list);
  29.337 +    ASSERT_EQ(n, 3);
  29.338 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
  29.339 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
  29.340 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
  29.341 +
  29.342 +    // exact match
  29.343 +    n = cx_strsplit(test, cx_str("this,is,a,csv,string"), capa, list);
  29.344 +    ASSERT_EQ(n, 2);
  29.345 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  29.346 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  29.347 +
  29.348 +    // string to be split is only substring
  29.349 +    n = cx_strsplit(test, cx_str("this,is,a,csv,string,with,extension"), capa, list);
  29.350 +    ASSERT_EQ(n, 1);
  29.351 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  29.352 +
  29.353 +    // subsequent encounter of delimiter (the string between is empty)
  29.354 +    n = cx_strsplit(test, cx_str("is,"), capa, list);
  29.355 +    ASSERT_EQ(n, 3);
  29.356 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  29.357 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  29.358 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  29.359 +
  29.360 +    // call the _m variant just for coverage
  29.361 +    auto mtest = cx_strdup(test);
  29.362 +    cxmutstr mlist[4];
  29.363 +    n = cx_strsplit_m(mtest, cx_str("is,"), 4, mlist);
  29.364 +    ASSERT_EQ(n, 3);
  29.365 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
  29.366 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
  29.367 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
  29.368 +    cx_strfree(&mtest);
  29.369 +}
  29.370 +
  29.371 +TEST(String, strsplit_a) {
  29.372 +    CxTestingAllocator alloc;
  29.373 +
  29.374 +    cxstring test = cx_str("this,is,a,csv,string");
  29.375 +    size_t capa = 8;
  29.376 +    cxstring *list;
  29.377 +    size_t n;
  29.378 +
  29.379 +    // special case: empty string
  29.380 +    n = cx_strsplit_a(&alloc, test, cx_str(""), capa, &list);
  29.381 +    ASSERT_EQ(n, 1);
  29.382 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  29.383 +    cxFree(&alloc, list);
  29.384 +
  29.385 +    // no delimiter occurrence
  29.386 +    n = cx_strsplit_a(&alloc, test, cx_str("z"), capa, &list);
  29.387 +    ASSERT_EQ(n, 1);
  29.388 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  29.389 +    cxFree(&alloc, list);
  29.390 +
  29.391 +    // partially matching delimiter
  29.392 +    n = cx_strsplit_a(&alloc, test, cx_str("is,not"), capa, &list);
  29.393 +    ASSERT_EQ(n, 1);
  29.394 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  29.395 +    cxFree(&alloc, list);
  29.396 +
  29.397 +    // matching single-char delimiter
  29.398 +    n = cx_strsplit_a(&alloc, test, cx_str(","), capa, &list);
  29.399 +    ASSERT_EQ(n, 5);
  29.400 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  29.401 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  29.402 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
  29.403 +    EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
  29.404 +    EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
  29.405 +    cxFree(&alloc, list);
  29.406 +
  29.407 +    // matching multi-char delimiter
  29.408 +    n = cx_strsplit_a(&alloc, test, cx_str("is"), capa, &list);
  29.409 +    ASSERT_EQ(n, 3);
  29.410 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  29.411 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
  29.412 +    EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
  29.413 +    cxFree(&alloc, list);
  29.414 +
  29.415 +    // bounded list using single-char delimiter
  29.416 +    n = cx_strsplit_a(&alloc, test, cx_str(","), 3, &list);
  29.417 +    ASSERT_EQ(n, 3);
  29.418 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  29.419 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  29.420 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  29.421 +    cxFree(&alloc, list);
  29.422 +
  29.423 +    // bounded list using multi-char delimiter
  29.424 +    n = cx_strsplit_a(&alloc, test, cx_str("is"), 2, &list);
  29.425 +    ASSERT_EQ(n, 2);
  29.426 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  29.427 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  29.428 +    cxFree(&alloc, list);
  29.429 +
  29.430 +    // start with delimiter
  29.431 +    n = cx_strsplit_a(&alloc, test, cx_str("this"), capa, &list);
  29.432 +    ASSERT_EQ(n, 2);
  29.433 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  29.434 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  29.435 +    cxFree(&alloc, list);
  29.436 +
  29.437 +    // end with delimiter
  29.438 +    n = cx_strsplit_a(&alloc, test, cx_str("string"), capa, &list);
  29.439 +    ASSERT_EQ(n, 2);
  29.440 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
  29.441 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  29.442 +    cxFree(&alloc, list);
  29.443 +
  29.444 +    // end with delimiter exceed bound
  29.445 +    n = cx_strsplit_a(&alloc, cx_str("a,b,c,"), cx_str(","), 3, &list);
  29.446 +    ASSERT_EQ(n, 3);
  29.447 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
  29.448 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
  29.449 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
  29.450 +    cxFree(&alloc, list);
  29.451 +
  29.452 +    // exact match
  29.453 +    n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string"), capa, &list);
  29.454 +    ASSERT_EQ(n, 2);
  29.455 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  29.456 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  29.457 +    cxFree(&alloc, list);
  29.458 +
  29.459 +    // string to be split is only substring
  29.460 +    n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string,with,extension"), capa, &list);
  29.461 +    ASSERT_EQ(n, 1);
  29.462 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  29.463 +    cxFree(&alloc, list);
  29.464 +
  29.465 +    // subsequent encounter of delimiter (the string between is empty)
  29.466 +    n = cx_strsplit_a(&alloc, test, cx_str("is,"), capa, &list);
  29.467 +    ASSERT_EQ(n, 3);
  29.468 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  29.469 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  29.470 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  29.471 +    cxFree(&alloc, list);
  29.472 +
  29.473 +    // call the _m variant just for coverage
  29.474 +    auto mtest = cx_strdup(test);
  29.475 +    cxmutstr *mlist;
  29.476 +    n = cx_strsplit_ma(&alloc, mtest, cx_str("is,"), 4, &mlist);
  29.477 +    ASSERT_EQ(n, 3);
  29.478 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
  29.479 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
  29.480 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
  29.481 +    cxFree(&alloc, mlist);
  29.482 +    cx_strfree(&mtest);
  29.483 +
  29.484 +    EXPECT_TRUE(alloc.verify());
  29.485 +}
  29.486 +
  29.487 +TEST(String, strtrim) {
  29.488 +    cxstring t1 = cx_strtrim(cx_str("  ein test  \t "));
  29.489 +    cxstring t2 = cx_strtrim(cx_str("abc"));
  29.490 +    cxstring t3 = cx_strtrim(cx_str(" 123"));
  29.491 +    cxstring t4 = cx_strtrim(cx_str("xyz "));
  29.492 +    cxstring t5 = cx_strtrim(cx_str("   "));
  29.493 +    cxstring empty = cx_strtrim(cx_str(""));
  29.494 +
  29.495 +    EXPECT_EQ(cx_strcmp(t1, cx_str("ein test")), 0);
  29.496 +    EXPECT_EQ(cx_strcmp(t2, cx_str("abc")), 0);
  29.497 +    EXPECT_EQ(cx_strcmp(t3, cx_str("123")), 0);
  29.498 +    EXPECT_EQ(cx_strcmp(t4, cx_str("xyz")), 0);
  29.499 +    EXPECT_EQ(cx_strcmp(t5, cx_str("")), 0);
  29.500 +    EXPECT_EQ(cx_strcmp(empty, cx_str("")), 0);
  29.501 +
  29.502 +    // call the _m variant just for coverage
  29.503 +    cxmutstr m1 = cx_strtrim_m(cx_mutstr((char *) "  ein test  \t "));
  29.504 +    EXPECT_EQ(cx_strcmp(cx_strcast(m1), cx_str("ein test")), 0);
  29.505 +}
  29.506 +
  29.507 +TEST(String, strprefix) {
  29.508 +    cxstring str = CX_STR("test my prefix and my suffix");
  29.509 +    cxstring empty = CX_STR("");
  29.510 +    EXPECT_FALSE(cx_strprefix(empty, cx_str("pref")));
  29.511 +    EXPECT_TRUE(cx_strprefix(str, empty));
  29.512 +    EXPECT_TRUE(cx_strprefix(empty, empty));
  29.513 +    EXPECT_TRUE(cx_strprefix(str, cx_str("test ")));
  29.514 +    EXPECT_FALSE(cx_strprefix(str, cx_str("8-) fsck ")));
  29.515 +}
  29.516 +
  29.517 +TEST(String, strsuffix) {
  29.518 +    cxstring str = CX_STR("test my prefix and my suffix");
  29.519 +    cxstring empty = CX_STR("");
  29.520 +    EXPECT_FALSE(cx_strsuffix(empty, cx_str("suf")));
  29.521 +    EXPECT_TRUE(cx_strsuffix(str, empty));
  29.522 +    EXPECT_TRUE(cx_strsuffix(empty, empty));
  29.523 +    EXPECT_TRUE(cx_strsuffix(str, cx_str("fix")));
  29.524 +    EXPECT_FALSE(cx_strsuffix(str, cx_str("fox")));
  29.525 +}
  29.526 +
  29.527 +TEST(String, strcaseprefix) {
  29.528 +    cxstring str = CX_STR("test my prefix and my suffix");
  29.529 +    cxstring empty = CX_STR("");
  29.530 +    EXPECT_FALSE(cx_strcaseprefix(empty, cx_str("pREf")));
  29.531 +    EXPECT_TRUE(cx_strcaseprefix(str, empty));
  29.532 +    EXPECT_TRUE(cx_strcaseprefix(empty, empty));
  29.533 +    EXPECT_TRUE(cx_strcaseprefix(str, cx_str("TEST ")));
  29.534 +    EXPECT_FALSE(cx_strcaseprefix(str, cx_str("8-) fsck ")));
  29.535 +}
  29.536 +
  29.537 +TEST(String, strcasesuffix) {
  29.538 +    cxstring str = CX_STR("test my prefix and my suffix");
  29.539 +    cxstring empty = CX_STR("");
  29.540 +    EXPECT_FALSE(cx_strcasesuffix(empty, cx_str("sUf")));
  29.541 +    EXPECT_TRUE(cx_strcasesuffix(str, empty));
  29.542 +    EXPECT_TRUE(cx_strcasesuffix(empty, empty));
  29.543 +    EXPECT_TRUE(cx_strcasesuffix(str, cx_str("FIX")));
  29.544 +    EXPECT_FALSE(cx_strcasesuffix(str, cx_str("fox")));
  29.545 +}
  29.546 +
  29.547 +TEST(String, strreplace) {
  29.548 +    CxTestingAllocator alloc;
  29.549 +    cxstring str = CX_STR("test ababab string aba");
  29.550 +    cxstring longstr = CX_STR(
  29.551 +            "xyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacd");
  29.552 +    cxstring notrail = CX_STR("test abab");
  29.553 +    cxstring empty = CX_STR("");
  29.554 +    cxstring astr = CX_STR("aaaaaaaaaa");
  29.555 +    cxstring csstr = CX_STR("test AB ab TEST xyz");
  29.556 +
  29.557 +    cxmutstr repl = cx_strreplace(str, cx_str("abab"), cx_str("muchlonger"));
  29.558 +    auto expected = "test muchlongerab string aba";
  29.559 +
  29.560 +    cxmutstr repln = cx_strreplacen(str, cx_str("ab"), cx_str("c"), 2);
  29.561 +    auto expectedn = "test ccab string aba";
  29.562 +
  29.563 +    cxmutstr longrepl = cx_strreplace(longstr, cx_str("a"), cx_str("z"));
  29.564 +    auto longexpect = "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd";
  29.565 +
  29.566 +    cxmutstr replnotrail = cx_strreplace(notrail, cx_str("ab"), cx_str("z"));
  29.567 +    auto notrailexpect = "test zz";
  29.568 +
  29.569 +    cxmutstr repleq = cx_strreplace(str, str, cx_str("hello"));
  29.570 +    auto eqexpect = "hello";
  29.571 +
  29.572 +    cxmutstr replempty1 = cx_strreplace(empty, cx_str("ab"), cx_str("c")); // expect: empty
  29.573 +    cxmutstr replempty2 = cx_strreplace(str, cx_str("abab"), empty);
  29.574 +    auto emptyexpect2 = "test ab string aba";
  29.575 +
  29.576 +    cxmutstr replpre = cx_strreplace(str, cx_str("test "), cx_str("TEST "));
  29.577 +    auto preexpected = "TEST ababab string aba";
  29.578 +
  29.579 +    cxmutstr replan1 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 1);
  29.580 +    auto an1expected = "xaaaaaaaaa";
  29.581 +
  29.582 +    cxmutstr replan4 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 4);
  29.583 +    auto an4expected = "xxxxaaaaaa";
  29.584 +
  29.585 +    cxmutstr replan9 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 9);
  29.586 +    auto an9expected = "xxxxxxxxxa";
  29.587 +
  29.588 +    cxmutstr replan10 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 10);
  29.589 +    auto an10expected = "xxxxxxxxxx";
  29.590 +
  29.591 +    cxmutstr repl1_a = cx_strreplace_a(&alloc, csstr, cx_str("AB"), cx_str("*"));
  29.592 +    auto expeced1_a = "test * ab TEST xyz";
  29.593 +
  29.594 +    cxmutstr repl2_a = cx_strreplace_a(&alloc, csstr, cx_str("test"), cx_str("TEST"));
  29.595 +    auto expected2_a = "TEST AB ab TEST xyz";
  29.596 +
  29.597 +
  29.598 +    EXPECT_NE(repl.ptr, str.ptr);
  29.599 +    EXPECT_ZERO_TERMINATED(repl);
  29.600 +    EXPECT_STREQ(repl.ptr, expected);
  29.601 +    EXPECT_ZERO_TERMINATED(repln);
  29.602 +    EXPECT_STREQ(repln.ptr, expectedn);
  29.603 +    EXPECT_ZERO_TERMINATED(longrepl);
  29.604 +    EXPECT_STREQ(longrepl.ptr, longexpect);
  29.605 +    EXPECT_ZERO_TERMINATED(replnotrail);
  29.606 +    EXPECT_STREQ(replnotrail.ptr, notrailexpect);
  29.607 +    EXPECT_ZERO_TERMINATED(repleq);
  29.608 +    EXPECT_STREQ(repleq.ptr, eqexpect);
  29.609 +    EXPECT_ZERO_TERMINATED(replempty1);
  29.610 +    EXPECT_STREQ(replempty1.ptr, "");
  29.611 +    EXPECT_ZERO_TERMINATED(replempty2);
  29.612 +    EXPECT_STREQ(replempty2.ptr, emptyexpect2);
  29.613 +    EXPECT_ZERO_TERMINATED(replpre);
  29.614 +    EXPECT_STREQ(replpre.ptr, preexpected);
  29.615 +    EXPECT_ZERO_TERMINATED(replan1);
  29.616 +    EXPECT_STREQ(replan1.ptr, an1expected);
  29.617 +    EXPECT_ZERO_TERMINATED(replan4);
  29.618 +    EXPECT_STREQ(replan4.ptr, an4expected);
  29.619 +    EXPECT_ZERO_TERMINATED(replan9);
  29.620 +    EXPECT_STREQ(replan9.ptr, an9expected);
  29.621 +    EXPECT_ZERO_TERMINATED(replan10);
  29.622 +    EXPECT_STREQ(replan10.ptr, an10expected);
  29.623 +    EXPECT_ZERO_TERMINATED(repl1_a);
  29.624 +    EXPECT_STREQ(repl1_a.ptr, expeced1_a);
  29.625 +    EXPECT_ZERO_TERMINATED(repl2_a);
  29.626 +    EXPECT_STREQ(repl2_a.ptr, expected2_a);
  29.627 +
  29.628 +    cx_strfree(&repl);
  29.629 +    cx_strfree(&repln);
  29.630 +    cx_strfree(&longrepl);
  29.631 +    cx_strfree(&replnotrail);
  29.632 +    cx_strfree(&repleq);
  29.633 +    cx_strfree(&replempty1);
  29.634 +    cx_strfree(&replempty2);
  29.635 +    cx_strfree(&replpre);
  29.636 +    cx_strfree(&replan1);
  29.637 +    cx_strfree(&replan4);
  29.638 +    cx_strfree(&replan9);
  29.639 +    cx_strfree(&replan10);
  29.640 +
  29.641 +    cx_strfree_a(&alloc, &repl1_a);
  29.642 +    cx_strfree_a(&alloc, &repl2_a);
  29.643 +    EXPECT_TRUE(alloc.verify());
  29.644 +}
  29.645 +
  29.646 +TEST(String, strupper) {
  29.647 +    cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
  29.648 +    cx_strupper(str);
  29.649 +    EXPECT_STREQ(str.ptr, "THIS 1S @ TE$T");
  29.650 +    cx_strfree(&str);
  29.651 +}
  29.652 +
  29.653 +TEST(String, strlower) {
  29.654 +    cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
  29.655 +    cx_strlower(str);
  29.656 +    EXPECT_STREQ(str.ptr, "this 1s @ te$t");
  29.657 +    cx_strfree(&str);
  29.658 +}
  29.659 +
  29.660 +TEST(String, strtok) {
  29.661 +    cxstring str = cx_str("a,comma,separated,string");
  29.662 +    cxstring delim = cx_str(",");
  29.663 +    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  29.664 +    EXPECT_EQ(ctx.str.ptr, str.ptr);
  29.665 +    EXPECT_EQ(ctx.str.length, str.length);
  29.666 +    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  29.667 +    EXPECT_EQ(ctx.delim.length, delim.length);
  29.668 +    EXPECT_EQ(ctx.limit, 3);
  29.669 +    EXPECT_EQ(ctx.found, 0);
  29.670 +    EXPECT_EQ(ctx.pos, 0);
  29.671 +    EXPECT_EQ(ctx.next_pos, 0);
  29.672 +    EXPECT_EQ(ctx.delim_more, nullptr);
  29.673 +    EXPECT_EQ(ctx.delim_more_count, 0);
  29.674 +}
  29.675 +
  29.676 +TEST(String, strtok_m) {
  29.677 +    cxmutstr str = cx_strdup(cx_str("a,comma,separated,string"));
  29.678 +    cxstring delim = cx_str(",");
  29.679 +    CxStrtokCtx ctx = cx_strtok_m(str, delim, 3);
  29.680 +    EXPECT_EQ(ctx.str.ptr, str.ptr);
  29.681 +    EXPECT_EQ(ctx.str.length, str.length);
  29.682 +    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  29.683 +    EXPECT_EQ(ctx.delim.length, delim.length);
  29.684 +    EXPECT_EQ(ctx.limit, 3);
  29.685 +    EXPECT_EQ(ctx.found, 0);
  29.686 +    EXPECT_EQ(ctx.pos, 0);
  29.687 +    EXPECT_EQ(ctx.next_pos, 0);
  29.688 +    EXPECT_EQ(ctx.delim_more, nullptr);
  29.689 +    EXPECT_EQ(ctx.delim_more_count, 0);
  29.690 +    cx_strfree(&str);
  29.691 +}
  29.692 +
  29.693 +TEST(String, strtok_delim) {
  29.694 +    cxstring str = cx_str("an,arbitrarily|separated;string");
  29.695 +    cxstring delim = cx_str(",");
  29.696 +    cxstring delim_more[2] = {CX_STR("|"), CX_STR(";")};
  29.697 +    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  29.698 +    cx_strtok_delim(&ctx, delim_more, 2);
  29.699 +    EXPECT_EQ(ctx.str.ptr, str.ptr);
  29.700 +    EXPECT_EQ(ctx.str.length, str.length);
  29.701 +    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  29.702 +    EXPECT_EQ(ctx.delim.length, delim.length);
  29.703 +    EXPECT_EQ(ctx.limit, 3);
  29.704 +    EXPECT_EQ(ctx.found, 0);
  29.705 +    EXPECT_EQ(ctx.pos, 0);
  29.706 +    EXPECT_EQ(ctx.next_pos, 0);
  29.707 +    EXPECT_EQ(ctx.delim_more, delim_more);
  29.708 +    EXPECT_EQ(ctx.delim_more_count, 2);
  29.709 +}
  29.710 +
  29.711 +TEST(String, strtok_next_easy) {
  29.712 +    cxstring str = cx_str("a,comma,separated,string");
  29.713 +    cxstring delim = cx_str(",");
  29.714 +    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  29.715 +    bool ret;
  29.716 +    cxstring tok;
  29.717 +
  29.718 +    ret = cx_strtok_next(&ctx, &tok);
  29.719 +    ASSERT_TRUE(ret);
  29.720 +    EXPECT_EQ(cx_strcmp(tok, cx_str("a")), 0);
  29.721 +    EXPECT_EQ(ctx.pos, 0);
  29.722 +    EXPECT_EQ(ctx.next_pos, 2);
  29.723 +    EXPECT_EQ(ctx.delim_pos, 1);
  29.724 +    EXPECT_EQ(ctx.found, 1);
  29.725 +
  29.726 +    ret = cx_strtok_next(&ctx, &tok);
  29.727 +    ASSERT_TRUE(ret);
  29.728 +    EXPECT_EQ(cx_strcmp(tok, cx_str("comma")), 0);
  29.729 +    EXPECT_EQ(ctx.pos, 2);
  29.730 +    EXPECT_EQ(ctx.next_pos, 8);
  29.731 +    EXPECT_EQ(ctx.delim_pos, 7);
  29.732 +    EXPECT_EQ(ctx.found, 2);
  29.733 +
  29.734 +    ret = cx_strtok_next(&ctx, &tok);
  29.735 +    ASSERT_TRUE(ret);
  29.736 +    EXPECT_EQ(cx_strcmp(tok, cx_str("separated")), 0);
  29.737 +    EXPECT_EQ(ctx.pos, 8);
  29.738 +    EXPECT_EQ(ctx.next_pos, 18);
  29.739 +    EXPECT_EQ(ctx.delim_pos, 17);
  29.740 +    EXPECT_EQ(ctx.found, 3);
  29.741 +
  29.742 +    ret = cx_strtok_next(&ctx, &tok);
  29.743 +    ASSERT_FALSE(ret);
  29.744 +    EXPECT_EQ(ctx.pos, 8);
  29.745 +    EXPECT_EQ(ctx.next_pos, 18);
  29.746 +    EXPECT_EQ(ctx.delim_pos, 17);
  29.747 +    EXPECT_EQ(ctx.found, 3);
  29.748 +}
  29.749 +
  29.750 +TEST(String, strtok_next_unlimited) {
  29.751 +    cxstring str = cx_str("some;-;otherwise;-;separated;-;string;-;");
  29.752 +    cxstring delim = cx_str(";-;");
  29.753 +    CxStrtokCtx ctx = cx_strtok(str, delim, SIZE_MAX);
  29.754 +    bool ret;
  29.755 +    cxstring tok;
  29.756 +
  29.757 +    ret = cx_strtok_next(&ctx, &tok);
  29.758 +    ASSERT_TRUE(ret);
  29.759 +    EXPECT_EQ(cx_strcmp(tok, cx_str("some")), 0);
  29.760 +    EXPECT_EQ(ctx.pos, 0);
  29.761 +    EXPECT_EQ(ctx.next_pos, 7);
  29.762 +    EXPECT_EQ(ctx.delim_pos, 4);
  29.763 +    EXPECT_EQ(ctx.found, 1);
  29.764 +
  29.765 +    ret = cx_strtok_next(&ctx, &tok);
  29.766 +    ASSERT_TRUE(ret);
  29.767 +    EXPECT_EQ(cx_strcmp(tok, cx_str("otherwise")), 0);
  29.768 +    EXPECT_EQ(ctx.pos, 7);
  29.769 +    EXPECT_EQ(ctx.next_pos, 19);
  29.770 +    EXPECT_EQ(ctx.delim_pos, 16);
  29.771 +    EXPECT_EQ(ctx.found, 2);
  29.772 +
  29.773 +    ret = cx_strtok_next(&ctx, &tok);
  29.774 +    ASSERT_TRUE(ret);
  29.775 +    EXPECT_EQ(cx_strcmp(tok, cx_str("separated")), 0);
  29.776 +    EXPECT_EQ(ctx.pos, 19);
  29.777 +    EXPECT_EQ(ctx.next_pos, 31);
  29.778 +    EXPECT_EQ(ctx.delim_pos, 28);
  29.779 +    EXPECT_EQ(ctx.found, 3);
  29.780 +
  29.781 +    ret = cx_strtok_next(&ctx, &tok);
  29.782 +    ASSERT_TRUE(ret);
  29.783 +    EXPECT_EQ(cx_strcmp(tok, cx_str("string")), 0);
  29.784 +    EXPECT_EQ(ctx.pos, 31);
  29.785 +    EXPECT_EQ(ctx.next_pos, 40);
  29.786 +    EXPECT_EQ(ctx.delim_pos, 37);
  29.787 +    EXPECT_EQ(ctx.found, 4);
  29.788 +
  29.789 +    ret = cx_strtok_next(&ctx, &tok);
  29.790 +    ASSERT_TRUE(ret);
  29.791 +    EXPECT_EQ(cx_strcmp(tok, cx_str("")), 0);
  29.792 +    EXPECT_EQ(ctx.pos, 40);
  29.793 +    EXPECT_EQ(ctx.next_pos, 40);
  29.794 +    EXPECT_EQ(ctx.delim_pos, 40);
  29.795 +    EXPECT_EQ(ctx.found, 5);
  29.796 +
  29.797 +    ret = cx_strtok_next(&ctx, &tok);
  29.798 +    ASSERT_FALSE(ret);
  29.799 +    EXPECT_EQ(ctx.pos, 40);
  29.800 +    EXPECT_EQ(ctx.delim_pos, 40);
  29.801 +    EXPECT_EQ(ctx.found, 5);
  29.802 +}
  29.803 +
  29.804 +TEST(String, strtok_next_advanced) {
  29.805 +    cxmutstr str = cx_strdup(cx_str("an,arbitrarily;||separated;string"));
  29.806 +    cxstring delim = cx_str(",");
  29.807 +    cxstring delim_more[2] = {CX_STR("||"), CX_STR(";")};
  29.808 +    CxStrtokCtx ctx = cx_strtok_m(str, delim, 10);
  29.809 +    cx_strtok_delim(&ctx, delim_more, 2);
  29.810 +    bool ret;
  29.811 +    cxmutstr tok;
  29.812 +
  29.813 +    ret = cx_strtok_next_m(&ctx, &tok);
  29.814 +    ASSERT_TRUE(ret);
  29.815 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("an")), 0);
  29.816 +    EXPECT_EQ(ctx.pos, 0);
  29.817 +    EXPECT_EQ(ctx.next_pos, 3);
  29.818 +    EXPECT_EQ(ctx.delim_pos, 2);
  29.819 +    EXPECT_EQ(ctx.found, 1);
  29.820 +    cx_strupper(tok);
  29.821 +
  29.822 +    ret = cx_strtok_next_m(&ctx, &tok);
  29.823 +    ASSERT_TRUE(ret);
  29.824 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("arbitrarily")), 0);
  29.825 +    EXPECT_EQ(ctx.pos, 3);
  29.826 +    EXPECT_EQ(ctx.next_pos, 15);
  29.827 +    EXPECT_EQ(ctx.delim_pos, 14);
  29.828 +    EXPECT_EQ(ctx.found, 2);
  29.829 +    cx_strupper(tok);
  29.830 +
  29.831 +    ret = cx_strtok_next_m(&ctx, &tok);
  29.832 +    ASSERT_TRUE(ret);
  29.833 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("")), 0);
  29.834 +    EXPECT_EQ(ctx.pos, 15);
  29.835 +    EXPECT_EQ(ctx.next_pos, 17);
  29.836 +    EXPECT_EQ(ctx.delim_pos, 15);
  29.837 +    EXPECT_EQ(ctx.found, 3);
  29.838 +    cx_strupper(tok);
  29.839 +
  29.840 +    ret = cx_strtok_next_m(&ctx, &tok);
  29.841 +    ASSERT_TRUE(ret);
  29.842 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("separated")), 0);
  29.843 +    EXPECT_EQ(ctx.pos, 17);
  29.844 +    EXPECT_EQ(ctx.next_pos, 27);
  29.845 +    EXPECT_EQ(ctx.delim_pos, 26);
  29.846 +    EXPECT_EQ(ctx.found, 4);
  29.847 +    cx_strupper(tok);
  29.848 +
  29.849 +    ret = cx_strtok_next_m(&ctx, &tok);
  29.850 +    ASSERT_TRUE(ret);
  29.851 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("string")), 0);
  29.852 +    EXPECT_EQ(ctx.pos, 27);
  29.853 +    EXPECT_EQ(ctx.next_pos, 33);
  29.854 +    EXPECT_EQ(ctx.delim_pos, 33);
  29.855 +    EXPECT_EQ(ctx.found, 5);
  29.856 +    cx_strupper(tok);
  29.857 +
  29.858 +    ret = cx_strtok_next_m(&ctx, &tok);
  29.859 +    ASSERT_FALSE(ret);
  29.860 +    EXPECT_EQ(ctx.pos, 27);
  29.861 +    EXPECT_EQ(ctx.next_pos, 33);
  29.862 +    EXPECT_EQ(ctx.delim_pos, 33);
  29.863 +    EXPECT_EQ(ctx.found, 5);
  29.864 +
  29.865 +    EXPECT_EQ(cx_strcmp(cx_strcast(str), cx_str("AN,ARBITRARILY;||SEPARATED;STRING")), 0);
  29.866 +
  29.867 +    cx_strfree(&str);
  29.868 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/tests/test_tree.cpp	Tue Feb 07 21:55:37 2023 +0100
    30.3 @@ -0,0 +1,122 @@
    30.4 +/*
    30.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    30.6 + *
    30.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    30.8 + *
    30.9 + * Redistribution and use in source and binary forms, with or without
   30.10 + * modification, are permitted provided that the following conditions are met:
   30.11 + *
   30.12 + *   1. Redistributions of source code must retain the above copyright
   30.13 + *      notice, this list of conditions and the following disclaimer.
   30.14 + *
   30.15 + *   2. Redistributions in binary form must reproduce the above copyright
   30.16 + *      notice, this list of conditions and the following disclaimer in the
   30.17 + *      documentation and/or other materials provided with the distribution.
   30.18 + *
   30.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   30.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   30.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   30.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   30.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   30.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   30.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30.29 + * POSSIBILITY OF SUCH DAMAGE.
   30.30 + */
   30.31 +
   30.32 +#include "cx/tree.h"
   30.33 +#include <gtest/gtest.h>
   30.34 +
   30.35 +struct TestNode {
   30.36 +    TestNode *parent = nullptr;
   30.37 +    TestNode *prev = nullptr;
   30.38 +    TestNode *next = nullptr;
   30.39 +
   30.40 +    TestNode *children_begin = nullptr;
   30.41 +    TestNode *children_end = nullptr;
   30.42 +};
   30.43 +
   30.44 +TEST(Tree, cx_tree_add_sibling) {
   30.45 +    // prepare test tree
   30.46 +    TestNode root, a;
   30.47 +    root.children_begin = &a;
   30.48 +    root.children_end = &a;
   30.49 +    a.parent = &root;
   30.50 +
   30.51 +    // new test nodes
   30.52 +    TestNode b, c;
   30.53 +
   30.54 +    // test
   30.55 +    cx_tree_add_sibling(&a, offsetof(TestNode, prev), offsetof(TestNode, next), offsetof(TestNode, parent), &b);
   30.56 +    EXPECT_EQ(b.parent, &root);
   30.57 +    EXPECT_EQ(b.prev, &a);
   30.58 +    EXPECT_EQ(b.next, nullptr);
   30.59 +    EXPECT_EQ(a.next, &b);
   30.60 +
   30.61 +    cx_tree_add_sibling(&a, -1, offsetof(TestNode, next), -1, &c);
   30.62 +    EXPECT_EQ(c.parent, nullptr);
   30.63 +    EXPECT_EQ(c.prev, nullptr);
   30.64 +    EXPECT_EQ(c.next, nullptr);
   30.65 +    EXPECT_EQ(b.next, &c);
   30.66 +}
   30.67 +
   30.68 +TEST(Tree, cx_tree_add_child) {
   30.69 +    TestNode root, a, b, c, a1;
   30.70 +
   30.71 +    cx_tree_add_child(
   30.72 +            (void **) &root.children_begin,
   30.73 +            (void **) &root.children_end,
   30.74 +            offsetof(TestNode, prev),
   30.75 +            offsetof(TestNode, next),
   30.76 +            &a,
   30.77 +            offsetof(TestNode, parent),
   30.78 +            &root);
   30.79 +    EXPECT_EQ(root.children_begin, &a);
   30.80 +    EXPECT_EQ(root.children_end, &a);
   30.81 +    EXPECT_EQ(a.parent, &root);
   30.82 +    EXPECT_EQ(a.prev, nullptr);
   30.83 +    EXPECT_EQ(a.next, nullptr);
   30.84 +
   30.85 +    cx_tree_add_child(
   30.86 +            (void **) &root.children_begin,
   30.87 +            (void **) &root.children_end,
   30.88 +            offsetof(TestNode, prev),
   30.89 +            offsetof(TestNode, next),
   30.90 +            &b,
   30.91 +            offsetof(TestNode, parent),
   30.92 +            &root);
   30.93 +    EXPECT_EQ(root.children_begin, &a);
   30.94 +    EXPECT_EQ(root.children_begin->next, &b);
   30.95 +    EXPECT_EQ(root.children_end, &b);
   30.96 +    EXPECT_EQ(b.parent, &root);
   30.97 +    EXPECT_EQ(b.prev, &a);
   30.98 +
   30.99 +    cx_tree_add_child(
  30.100 +            (void **) &root.children_begin,
  30.101 +            nullptr,
  30.102 +            -1,
  30.103 +            offsetof(TestNode, next),
  30.104 +            &c,
  30.105 +            -1,
  30.106 +            &root);
  30.107 +    EXPECT_EQ(root.children_end, &b); // children_end unchanged
  30.108 +    EXPECT_EQ(b.next, &c);
  30.109 +    EXPECT_EQ(c.prev, nullptr);
  30.110 +    EXPECT_EQ(c.next, nullptr);
  30.111 +    EXPECT_EQ(c.parent, nullptr);
  30.112 +
  30.113 +    cx_tree_add_child(
  30.114 +            (void **) &a.children_begin,
  30.115 +            (void **) &a.children_end,
  30.116 +            offsetof(TestNode, prev),
  30.117 +            offsetof(TestNode, next),
  30.118 +            &a1,
  30.119 +            offsetof(TestNode, parent),
  30.120 +            &a);
  30.121 +    EXPECT_EQ(a.children_begin, &a1);
  30.122 +    EXPECT_EQ(a1.parent, &a);
  30.123 +    EXPECT_EQ(root.children_begin, &a);
  30.124 +    EXPECT_EQ(root.children_begin->children_begin, &a1);
  30.125 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/tests/test_utils.cpp	Tue Feb 07 21:55:37 2023 +0100
    31.3 @@ -0,0 +1,155 @@
    31.4 +/*
    31.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    31.6 + *
    31.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    31.8 + *
    31.9 + * Redistribution and use in source and binary forms, with or without
   31.10 + * modification, are permitted provided that the following conditions are met:
   31.11 + *
   31.12 + *   1. Redistributions of source code must retain the above copyright
   31.13 + *      notice, this list of conditions and the following disclaimer.
   31.14 + *
   31.15 + *   2. Redistributions in binary form must reproduce the above copyright
   31.16 + *      notice, this list of conditions and the following disclaimer in the
   31.17 + *      documentation and/or other materials provided with the distribution.
   31.18 + *
   31.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   31.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   31.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   31.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   31.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   31.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   31.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   31.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31.29 + * POSSIBILITY OF SUCH DAMAGE.
   31.30 + */
   31.31 +
   31.32 +#include "cx/utils.h"
   31.33 +
   31.34 +#include <gtest/gtest.h>
   31.35 +
   31.36 +TEST(Utils, ForN) {
   31.37 +    unsigned j;
   31.38 +    j = 0;
   31.39 +    cx_for_n(i, 50) {
   31.40 +        EXPECT_EQ(i, j);
   31.41 +        j++;
   31.42 +    }
   31.43 +}
   31.44 +
   31.45 +TEST(Utils, szmul) {
   31.46 +    size_t r;
   31.47 +    int e;
   31.48 +    e = cx_szmul(5, 7, &r);
   31.49 +    EXPECT_EQ(0, e);
   31.50 +    EXPECT_EQ(35, r);
   31.51 +
   31.52 +    size_t s = SIZE_MAX & ~3;
   31.53 +
   31.54 +    e = cx_szmul(s / 4, 2, &r);
   31.55 +    EXPECT_EQ(0, e);
   31.56 +    EXPECT_EQ(s / 2, r);
   31.57 +    e = cx_szmul(2, s / 4, &r);
   31.58 +    EXPECT_EQ(0, e);
   31.59 +    EXPECT_EQ(s / 2, r);
   31.60 +
   31.61 +    e = cx_szmul(s / 4, 4, &r);
   31.62 +    EXPECT_EQ(0, e);
   31.63 +    EXPECT_EQ(s, r);
   31.64 +
   31.65 +    e = cx_szmul(4, s / 4, &r);
   31.66 +    EXPECT_EQ(0, e);
   31.67 +    EXPECT_EQ(s, r);
   31.68 +
   31.69 +    e = cx_szmul(s / 4, 5, &r);
   31.70 +    EXPECT_NE(0, e);
   31.71 +
   31.72 +    e = cx_szmul(5, s / 4, &r);
   31.73 +    EXPECT_NE(0, e);
   31.74 +
   31.75 +    e = cx_szmul(SIZE_MAX - 4, 0, &r);
   31.76 +    EXPECT_EQ(0, e);
   31.77 +    EXPECT_EQ(0, r);
   31.78 +
   31.79 +    e = cx_szmul(0, SIZE_MAX - 1, &r);
   31.80 +    EXPECT_EQ(0, e);
   31.81 +    EXPECT_EQ(0, r);
   31.82 +
   31.83 +    e = cx_szmul(SIZE_MAX, 0, &r);
   31.84 +    EXPECT_EQ(0, e);
   31.85 +    EXPECT_EQ(0, r);
   31.86 +
   31.87 +    e = cx_szmul(0, SIZE_MAX, &r);
   31.88 +    EXPECT_EQ(0, e);
   31.89 +    EXPECT_EQ(0, r);
   31.90 +
   31.91 +    e = cx_szmul(0, 0, &r);
   31.92 +    EXPECT_EQ(0, e);
   31.93 +    EXPECT_EQ(0, r);
   31.94 +}
   31.95 +
   31.96 +#ifdef CX_SZMUL_BUILTIN
   31.97 +
   31.98 +// also test the custom implementation
   31.99 +struct Utils_szmul_impl : ::testing::Test {
  31.100 +#undef CX_SZMUL_BUILTIN
  31.101 +
  31.102 +#include "../src/utils.c"
  31.103 +
  31.104 +#define CX_SZMUL_BUILTIN
  31.105 +};
  31.106 +
  31.107 +TEST_F(Utils_szmul_impl, Test) {
  31.108 +    size_t r;
  31.109 +    int e;
  31.110 +    e = cx_szmul_impl(5, 7, &r);
  31.111 +    EXPECT_EQ(0, e);
  31.112 +    EXPECT_EQ(35, r);
  31.113 +
  31.114 +    size_t s = SIZE_MAX & ~3;
  31.115 +
  31.116 +    e = cx_szmul_impl(s / 4, 2, &r);
  31.117 +    EXPECT_EQ(0, e);
  31.118 +    EXPECT_EQ(s / 2, r);
  31.119 +    e = cx_szmul_impl(2, s / 4, &r);
  31.120 +    EXPECT_EQ(0, e);
  31.121 +    EXPECT_EQ(s / 2, r);
  31.122 +
  31.123 +    e = cx_szmul_impl(s / 4, 4, &r);
  31.124 +    EXPECT_EQ(0, e);
  31.125 +    EXPECT_EQ(s, r);
  31.126 +
  31.127 +    e = cx_szmul_impl(4, s / 4, &r);
  31.128 +    EXPECT_EQ(0, e);
  31.129 +    EXPECT_EQ(s, r);
  31.130 +
  31.131 +    e = cx_szmul_impl(s / 4, 5, &r);
  31.132 +    EXPECT_NE(0, e);
  31.133 +
  31.134 +    e = cx_szmul_impl(5, s / 4, &r);
  31.135 +    EXPECT_NE(0, e);
  31.136 +
  31.137 +    e = cx_szmul_impl(SIZE_MAX - 4, 0, &r);
  31.138 +    EXPECT_EQ(0, e);
  31.139 +    EXPECT_EQ(0, r);
  31.140 +
  31.141 +    e = cx_szmul_impl(0, SIZE_MAX - 1, &r);
  31.142 +    EXPECT_EQ(0, e);
  31.143 +    EXPECT_EQ(0, r);
  31.144 +
  31.145 +    e = cx_szmul_impl(SIZE_MAX, 0, &r);
  31.146 +    EXPECT_EQ(0, e);
  31.147 +    EXPECT_EQ(0, r);
  31.148 +
  31.149 +    e = cx_szmul_impl(0, SIZE_MAX, &r);
  31.150 +    EXPECT_EQ(0, e);
  31.151 +    EXPECT_EQ(0, r);
  31.152 +
  31.153 +    e = cx_szmul_impl(0, 0, &r);
  31.154 +    EXPECT_EQ(0, e);
  31.155 +    EXPECT_EQ(0, r);
  31.156 +}
  31.157 +
  31.158 +#endif // CX_SZMUL_BUILTIN
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/tests/util_allocator.cpp	Tue Feb 07 21:55:37 2023 +0100
    32.3 @@ -0,0 +1,167 @@
    32.4 +/*
    32.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    32.6 + *
    32.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    32.8 + *
    32.9 + * Redistribution and use in source and binary forms, with or without
   32.10 + * modification, are permitted provided that the following conditions are met:
   32.11 + *
   32.12 + *   1. Redistributions of source code must retain the above copyright
   32.13 + *      notice, this list of conditions and the following disclaimer.
   32.14 + *
   32.15 + *   2. Redistributions in binary form must reproduce the above copyright
   32.16 + *      notice, this list of conditions and the following disclaimer in the
   32.17 + *      documentation and/or other materials provided with the distribution.
   32.18 + *
   32.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   32.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   32.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   32.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   32.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   32.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   32.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   32.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32.29 + * POSSIBILITY OF SUCH DAMAGE.
   32.30 + */
   32.31 +
   32.32 +#include "util_allocator.h"
   32.33 +
   32.34 +void *cx_malloc_testing(void *d, size_t n) {
   32.35 +    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   32.36 +    void *ptr = malloc(n);
   32.37 +    data->alloc_total++;
   32.38 +    if (ptr == nullptr) {
   32.39 +        data->alloc_failed++;
   32.40 +    } else {
   32.41 +        data->tracked.insert(ptr);
   32.42 +    }
   32.43 +    return ptr;
   32.44 +}
   32.45 +
   32.46 +void *cx_realloc_testing(void *d, void *mem, size_t n) {
   32.47 +    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   32.48 +    void *ptr = realloc(mem, n);
   32.49 +    if (ptr == mem) {
   32.50 +        return ptr;
   32.51 +    } else {
   32.52 +        data->alloc_total++;
   32.53 +        if (ptr == nullptr) {
   32.54 +            data->alloc_failed++;
   32.55 +        } else {
   32.56 +            data->free_total++;
   32.57 +            if (data->tracked.erase(mem) == 0) {
   32.58 +                data->free_failed++;
   32.59 +            }
   32.60 +            data->tracked.insert(ptr);
   32.61 +        }
   32.62 +        return ptr;
   32.63 +    }
   32.64 +}
   32.65 +
   32.66 +void *cx_calloc_testing(void *d, size_t nelem, size_t n) {
   32.67 +    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   32.68 +    void *ptr = calloc(nelem, n);
   32.69 +    data->alloc_total++;
   32.70 +    if (ptr == nullptr) {
   32.71 +        data->alloc_failed++;
   32.72 +    } else {
   32.73 +        data->tracked.insert(ptr);
   32.74 +    }
   32.75 +    return ptr;
   32.76 +}
   32.77 +
   32.78 +void cx_free_testing(void *d, void *mem) {
   32.79 +    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   32.80 +    data->free_total++;
   32.81 +    if (data->tracked.erase(mem) == 0) {
   32.82 +        data->free_failed++;
   32.83 +        // do not even attempt to free mem, because it is likely to segfault
   32.84 +    } else {
   32.85 +        free(mem);
   32.86 +    }
   32.87 +}
   32.88 +
   32.89 +cx_allocator_class cx_testing_allocator_class = {
   32.90 +        cx_malloc_testing,
   32.91 +        cx_realloc_testing,
   32.92 +        cx_calloc_testing,
   32.93 +        cx_free_testing
   32.94 +};
   32.95 +
   32.96 +CxTestingAllocator::CxTestingAllocator() : CxAllocator() {
   32.97 +    cl = &cx_testing_allocator_class;
   32.98 +    data = this;
   32.99 +}
  32.100 +
  32.101 +bool CxTestingAllocator::used() const {
  32.102 +    return alloc_total > 0;
  32.103 +}
  32.104 +
  32.105 +bool CxTestingAllocator::verify() const {
  32.106 +    return tracked.empty() && alloc_failed == 0 && free_failed == 0 && alloc_total == free_total;
  32.107 +}
  32.108 +
  32.109 +// SELF-TEST
  32.110 +
  32.111 +#include <gtest/gtest.h>
  32.112 +
  32.113 +TEST(TestingAllocator, ExpectFree) {
  32.114 +    CxTestingAllocator allocator;
  32.115 +
  32.116 +    ASSERT_TRUE(allocator.verify());
  32.117 +    EXPECT_FALSE(allocator.used());
  32.118 +    auto ptr = cxMalloc(&allocator, 16);
  32.119 +    EXPECT_TRUE(allocator.used());
  32.120 +    ASSERT_NE(ptr, nullptr);
  32.121 +    EXPECT_FALSE(allocator.verify());
  32.122 +
  32.123 +    cxFree(&allocator, ptr);
  32.124 +    EXPECT_TRUE(allocator.verify());
  32.125 +}
  32.126 +
  32.127 +TEST(TestingAllocator, DetectDoubleFree) {
  32.128 +    CxTestingAllocator allocator;
  32.129 +
  32.130 +    ASSERT_TRUE(allocator.verify());
  32.131 +    auto ptr = cxMalloc(&allocator, 16);
  32.132 +    ASSERT_NE(ptr, nullptr);
  32.133 +
  32.134 +    cxFree(&allocator, ptr);
  32.135 +    EXPECT_TRUE(allocator.verify());
  32.136 +    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
  32.137 +    EXPECT_FALSE(allocator.verify());
  32.138 +}
  32.139 +
  32.140 +TEST(TestingAllocator, FreeUntracked) {
  32.141 +    CxTestingAllocator allocator;
  32.142 +
  32.143 +    auto ptr = malloc(16);
  32.144 +    ASSERT_TRUE(allocator.verify());
  32.145 +    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
  32.146 +    EXPECT_FALSE(allocator.verify());
  32.147 +    ASSERT_NO_FATAL_FAILURE(free(ptr));
  32.148 +}
  32.149 +
  32.150 +TEST(TestingAllocator, FullLifecycleWithRealloc) {
  32.151 +    CxTestingAllocator allocator;
  32.152 +    ASSERT_TRUE(allocator.verify());
  32.153 +    auto ptr = cxMalloc(&allocator, 16);
  32.154 +    ASSERT_NE(ptr, nullptr);
  32.155 +    EXPECT_EQ(allocator.tracked.size(), 1);
  32.156 +    ptr = cxRealloc(&allocator, ptr, 256);
  32.157 +    ASSERT_NE(ptr, nullptr);
  32.158 +    EXPECT_EQ(allocator.tracked.size(), 1);
  32.159 +    cxFree(&allocator, ptr);
  32.160 +    EXPECT_TRUE(allocator.verify());
  32.161 +}
  32.162 +
  32.163 +TEST(TestingAllocator, CallocInitializes) {
  32.164 +    CxTestingAllocator allocator;
  32.165 +    const char zeros[16] = {0};
  32.166 +    auto ptr = cxCalloc(&allocator, 16, 1);
  32.167 +    EXPECT_EQ(memcmp(ptr, zeros, 16), 0);
  32.168 +    cxFree(&allocator, ptr);
  32.169 +    EXPECT_TRUE(allocator.verify());
  32.170 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/tests/util_allocator.h	Tue Feb 07 21:55:37 2023 +0100
    33.3 @@ -0,0 +1,81 @@
    33.4 +/*
    33.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    33.6 + *
    33.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    33.8 + *
    33.9 + * Redistribution and use in source and binary forms, with or without
   33.10 + * modification, are permitted provided that the following conditions are met:
   33.11 + *
   33.12 + *   1. Redistributions of source code must retain the above copyright
   33.13 + *      notice, this list of conditions and the following disclaimer.
   33.14 + *
   33.15 + *   2. Redistributions in binary form must reproduce the above copyright
   33.16 + *      notice, this list of conditions and the following disclaimer in the
   33.17 + *      documentation and/or other materials provided with the distribution.
   33.18 + *
   33.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   33.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   33.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   33.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   33.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   33.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   33.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   33.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33.29 + * POSSIBILITY OF SUCH DAMAGE.
   33.30 + */
   33.31 +
   33.32 +#ifndef UCX_UTIL_ALLOCATOR_H
   33.33 +#define UCX_UTIL_ALLOCATOR_H
   33.34 +
   33.35 +#include "cx/allocator.h"
   33.36 +
   33.37 +#include <set>
   33.38 +
   33.39 +struct CxTestingAllocator : public CxAllocator {
   33.40 +    /**
   33.41 +     * Total number of all allocations (malloc, calloc, realloc).
   33.42 +     * A realloc() does only count when the memory has to be moved.
   33.43 +     */
   33.44 +    unsigned alloc_total = 0;
   33.45 +    /**
   33.46 +     * Number of failed allocations (malloc, calloc, realloc).
   33.47 +     */
   33.48 +    unsigned alloc_failed = 0;
   33.49 +    /**
   33.50 +     * Total number of freed pointers.
   33.51 +     * A reallocation also counts as a free when the memory has to be moved.
   33.52 +     */
   33.53 +    unsigned free_total = 0;
   33.54 +    /**
   33.55 +     * Number of failed free invocations.
   33.56 +     * A free() is considered failed, if it has not been performed on tracked memory.
   33.57 +     */
   33.58 +    unsigned free_failed = 0;
   33.59 +    /**
   33.60 +     * The set of tracked memory blocks.
   33.61 +     */
   33.62 +    std::set<void *> tracked;
   33.63 +
   33.64 +    /**
   33.65 +     * Constructs a new testing allocator.
   33.66 +     */
   33.67 +    CxTestingAllocator();
   33.68 +
   33.69 +    /**
   33.70 +     * Verifies that this allocator has been used.
   33.71 +     *
   33.72 +     * @return true if any allocation was attempted using this allocator
   33.73 +     */
   33.74 +    [[nodiscard]] bool used() const;
   33.75 +
   33.76 +    /**
   33.77 +     * Verifies that all allocated memory blocks are freed and no free occurred twice.
   33.78 +     *
   33.79 +     * @return true iff all tracked allocations / deallocations were valid
   33.80 +     */
   33.81 +    [[nodiscard]] bool verify() const;
   33.82 +};
   33.83 +
   33.84 +#endif // UCX_UTIL_ALLOCATOR_H

mercurial