Automated merge

Wed, 08 Feb 2023 20:26:26 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 08 Feb 2023 20:26:26 +0100
changeset 654
c9d008861178
parent 647
2e6e9d9f2159 (current diff)
parent 653
e081643aae2a (diff)
child 655
7340c4255f1f

Automated merge

src/array_list.c file | annotate | diff | comparison | revisions
src/cx/utils.h file | annotate | diff | comparison | revisions
src/linked_list.c file | annotate | diff | comparison | revisions
test/test_list.cpp file | annotate | diff | comparison | revisions
test/test_utils.cpp file | annotate | diff | comparison | revisions
tests/test_list.cpp file | annotate | diff | comparison | revisions
tests/test_utils.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/CMakeLists.txt	Wed Feb 08 20:26:09 2023 +0100
     1.2 +++ b/CMakeLists.txt	Wed Feb 08 20:26:26 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/README	Wed Feb 08 20:26:09 2023 +0100
     2.2 +++ b/README	Wed Feb 08 20:26:26 2023 +0100
     2.3 @@ -38,7 +38,7 @@
     2.4  
     2.5  If you want to verify your build, you can run
     2.6  
     2.7 -  make check
     2.8 +  make test
     2.9  
    2.10  
    2.11  3. Documentation
     3.1 --- a/src/allocator.c	Wed Feb 08 20:26:09 2023 +0100
     3.2 +++ b/src/allocator.c	Wed Feb 08 20:26:26 2023 +0100
     3.3 @@ -28,8 +28,6 @@
     3.4  
     3.5  #include "cx/allocator.h"
     3.6  
     3.7 -#include <stdlib.h>
     3.8 -
     3.9  __attribute__((__malloc__, __alloc_size__(2)))
    3.10  static void *cx_malloc_stdlib(
    3.11          __attribute__((__unused__)) void *d,
     4.1 --- a/src/array_list.c	Wed Feb 08 20:26:09 2023 +0100
     4.2 +++ b/src/array_list.c	Wed Feb 08 20:26:26 2023 +0100
     4.3 @@ -29,7 +29,6 @@
     4.4  #include "cx/array_list.h"
     4.5  #include <assert.h>
     4.6  #include <string.h>
     4.7 -#include <stdint.h>
     4.8  
     4.9  // LOW LEVEL ARRAY LIST FUNCTIONS
    4.10  
     5.1 --- a/src/basic_mempool.c	Wed Feb 08 20:26:09 2023 +0100
     5.2 +++ b/src/basic_mempool.c	Wed Feb 08 20:26:26 2023 +0100
     5.3 @@ -28,7 +28,6 @@
     5.4  
     5.5  #include "cx/basic_mempool.h"
     5.6  #include "cx/utils.h"
     5.7 -#include <stdint.h>
     5.8  #include <string.h>
     5.9  
    5.10  #define of_chk_(n) if (SIZE_MAX - sizeof(cx_destructor_func) < (n)) return NULL
     6.1 --- a/src/buffer.c	Wed Feb 08 20:26:09 2023 +0100
     6.2 +++ b/src/buffer.c	Wed Feb 08 20:26:26 2023 +0100
     6.3 @@ -29,10 +29,8 @@
     6.4  #include "cx/buffer.h"
     6.5  #include "cx/utils.h"
     6.6  
     6.7 -#include <stdlib.h>
     6.8  #include <stdio.h>
     6.9  #include <string.h>
    6.10 -#include <stdint.h>
    6.11  
    6.12  int cxBufferInit(
    6.13          CxBuffer *buffer,
     7.1 --- a/src/compare.c	Wed Feb 08 20:26:09 2023 +0100
     7.2 +++ b/src/compare.c	Wed Feb 08 20:26:26 2023 +0100
     7.3 @@ -28,7 +28,6 @@
     7.4  
     7.5  #include "cx/compare.h"
     7.6  
     7.7 -#include <stdint.h>
     7.8  #include <math.h>
     7.9  
    7.10  int cx_cmp_int(void const *i1, void const *i2) {
     8.1 --- a/src/cx/common.h	Wed Feb 08 20:26:09 2023 +0100
     8.2 +++ b/src/cx/common.h	Wed Feb 08 20:26:26 2023 +0100
     8.3 @@ -92,6 +92,7 @@
     8.4  #include <stdlib.h>
     8.5  #include <stddef.h>
     8.6  #include <stdbool.h>
     8.7 +#include <stdint.h>
     8.8  
     8.9  /**
    8.10   * Function pointer compatible with fwrite-like functions.
    8.11 @@ -104,13 +105,11 @@
    8.12  );
    8.13  
    8.14  #ifdef _WIN32
    8.15 -#ifndef __WORDSIZE
    8.16 -#ifdef _WIN64
    8.17 -#define __WORDSIZE 64
    8.18 -#else
    8.19 -#define __WORDSIZE 32
    8.20 -#endif
    8.21 -#endif // __WORDSIZE
    8.22 +
    8.23 +#ifdef __MINGW32__
    8.24 +#include <sys/types.h>
    8.25 +#endif // __MINGW32__
    8.26 +
    8.27  #else // !_WIN32
    8.28  
    8.29  #include <sys/types.h>
     9.1 --- a/src/cx/compare.h	Wed Feb 08 20:26:09 2023 +0100
     9.2 +++ b/src/cx/compare.h	Wed Feb 08 20:26:26 2023 +0100
     9.3 @@ -37,6 +37,8 @@
     9.4  #ifndef UCX_COMPARE_H
     9.5  #define UCX_COMPARE_H
     9.6  
     9.7 +#include "common.h"
     9.8 +
     9.9  #ifdef __cplusplus
    9.10  extern "C" {
    9.11  #endif
    10.1 --- a/src/cx/utils.h	Wed Feb 08 20:26:09 2023 +0100
    10.2 +++ b/src/cx/utils.h	Wed Feb 08 20:26:26 2023 +0100
    10.3 @@ -65,9 +65,8 @@
    10.4  #if (__GNUC__ >= 5 || defined(__clang__)) && !defined(CX_NO_SZMUL_BUILTIN)
    10.5  #define CX_SZMUL_BUILTIN
    10.6  
    10.7 -#if __WORDSIZE == 32
    10.8  /**
    10.9 - * Alias for \c __builtin_umul_overflow.
   10.10 + * Alias for \c __builtin_mul_overflow.
   10.11   *
   10.12   * Performs a multiplication of size_t values and checks for overflow.
   10.13   *
   10.14 @@ -78,22 +77,7 @@
   10.15   * @return zero, if no overflow occurred and the result is correct, non-zero
   10.16   * otherwise
   10.17   */
   10.18 -#define cx_szmul(a, b, result) __builtin_umul_overflow(a, b, result)
   10.19 -#else // __WORDSIZE != 32
   10.20 -/**
   10.21 - * Alias for \c __builtin_umull_overflow.
   10.22 - *
   10.23 - * Performs a multiplication of size_t values and checks for overflow.
   10.24 - *
   10.25 - * @param a first operand
   10.26 - * @param b second operand
   10.27 - * @param result a pointer to a size_t, where the result should
   10.28 - * be stored
   10.29 - * @return zero, if no overflow occurred and the result is correct, non-zero
   10.30 - * otherwise
   10.31 - */
   10.32 -#define cx_szmul(a, b, result) __builtin_umull_overflow(a, b, result)
   10.33 -#endif // __WORDSIZE
   10.34 +#define cx_szmul(a, b, result) __builtin_mul_overflow(a, b, result)
   10.35  
   10.36  #else // no GNUC or clang bultin
   10.37  
    11.1 --- a/src/linked_list.c	Wed Feb 08 20:26:09 2023 +0100
    11.2 +++ b/src/linked_list.c	Wed Feb 08 20:26:26 2023 +0100
    11.3 @@ -28,7 +28,6 @@
    11.4  
    11.5  #include "cx/linked_list.h"
    11.6  #include "cx/utils.h"
    11.7 -#include <stdint.h>
    11.8  #include <string.h>
    11.9  #include <assert.h>
   11.10  
    12.1 --- a/test/.clang-tidy	Wed Feb 08 20:26:09 2023 +0100
    12.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.3 @@ -1,2 +0,0 @@
    12.4 -# Disable static initialization warning for test code
    12.5 -Checks: '-cert-err58-cpp'
    13.1 --- a/test/CMakeLists.txt	Wed Feb 08 20:26:09 2023 +0100
    13.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.3 @@ -1,32 +0,0 @@
    13.4 -# Load Google Test Framework
    13.5 -set(CMAKE_CXX_STANDARD 17)
    13.6 -
    13.7 -include(FetchContent)
    13.8 -FetchContent_Declare(
    13.9 -        googletest
   13.10 -        GIT_REPOSITORY https://github.com/google/googletest.git
   13.11 -        GIT_TAG e2239ee6043f73722e7aa812a459f54a28552929 # release 1.11.0
   13.12 -)
   13.13 -# For Windows: Prevent overriding the parent project's compiler/linker settings
   13.14 -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
   13.15 -FetchContent_MakeAvailable(googletest)
   13.16 -include(GoogleTest)
   13.17 -message(STATUS "Google Test made available")
   13.18 -
   13.19 -add_executable(ucxtest
   13.20 -        test_utils.cpp
   13.21 -        test_allocator.cpp
   13.22 -        test_compare.cpp
   13.23 -        test_string.cpp
   13.24 -        test_buffer.cpp
   13.25 -        test_list.cpp
   13.26 -        test_tree.cpp
   13.27 -        test_hash_key.cpp
   13.28 -        test_map.cpp
   13.29 -        test_basic_mempool.cpp
   13.30 -        test_printf.cpp
   13.31 -        selftest.cpp
   13.32 -        util_allocator.cpp
   13.33 -        )
   13.34 -target_link_libraries(ucxtest PRIVATE ucx_static gtest_main)
   13.35 -gtest_discover_tests(ucxtest)
    14.1 --- a/test/selftest.cpp	Wed Feb 08 20:26:09 2023 +0100
    14.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.3 @@ -1,43 +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 <gtest/gtest.h>
   14.33 -#include <cx/common.h>
   14.34 -
   14.35 -TEST(SelfTest, BasicAssertion) {
   14.36 -    EXPECT_EQ(7 * 6, 42);
   14.37 -}
   14.38 -
   14.39 -TEST(SelfTest, UcxVersion) {
   14.40 -    EXPECT_GE(UCX_VERSION_MAJOR, 3);
   14.41 -    EXPECT_GE(UCX_VERSION, 3 << 16);
   14.42 -}
   14.43 -
   14.44 -TEST(SelfTest, CommonDefinitions) {
   14.45 -    EXPECT_EQ(__WORDSIZE, 8 * sizeof(void*));
   14.46 -}
    15.1 --- a/test/test_allocator.cpp	Wed Feb 08 20:26:09 2023 +0100
    15.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.3 @@ -1,96 +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/allocator.h"
   15.33 -#include <gtest/gtest.h>
   15.34 -
   15.35 -TEST(Allocator, DefaultAllocator) {
   15.36 -    cx_allocator_class *clazz = cxDefaultAllocator->cl;
   15.37 -    ASSERT_NE(clazz, nullptr);
   15.38 -}
   15.39 -
   15.40 -TEST(Allocator, DefaultMalloc) {
   15.41 -    void *test = cxMalloc(cxDefaultAllocator, 16);
   15.42 -    ASSERT_NE(test, nullptr);
   15.43 -    free(test);
   15.44 -}
   15.45 -
   15.46 -TEST(Allocator, DefaultRealloc) {
   15.47 -    void *test = calloc(8, 1);
   15.48 -    memcpy(test, "Test", 5);
   15.49 -    test = cxRealloc(cxDefaultAllocator, test, 16);
   15.50 -    ASSERT_NE(test, nullptr);
   15.51 -    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
   15.52 -    free(test);
   15.53 -}
   15.54 -
   15.55 -TEST(Allocator, Reallocate) {
   15.56 -    void *test = calloc(8, 1);
   15.57 -    memcpy(test, "Test", 5);
   15.58 -    int ret = cxReallocate(cxDefaultAllocator, &test, 16);
   15.59 -    EXPECT_EQ(ret, 0);
   15.60 -    ASSERT_NE(test, nullptr);
   15.61 -    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
   15.62 -    free(test);
   15.63 -}
   15.64 -
   15.65 -TEST(Allocator, DefaultCalloc) {
   15.66 -    char *test = reinterpret_cast<char *>(cxCalloc(cxDefaultAllocator, 8, 2));
   15.67 -    ASSERT_NE(test, nullptr);
   15.68 -    for (int i = 0; i < 16; i++) ASSERT_EQ(test[i], 0);
   15.69 -    free(test);
   15.70 -}
   15.71 -
   15.72 -TEST(Allocator, DefaultFree) {
   15.73 -    void *test = malloc(16);
   15.74 -    EXPECT_NO_FATAL_FAILURE(
   15.75 -            cxFree(cxDefaultAllocator, test);
   15.76 -    );
   15.77 -}
   15.78 -
   15.79 -TEST(Allocator, FailingReallocate) {
   15.80 -    // Mock an allocator that always returns nullptr on realloc
   15.81 -    cx_allocator_class mock_cl;
   15.82 -    mock_cl.realloc = [](
   15.83 -            [[maybe_unused]]void *p,
   15.84 -            [[maybe_unused]]void *d,
   15.85 -            [[maybe_unused]]size_t n
   15.86 -    ) -> void * { return nullptr; };
   15.87 -    cx_allocator_s mock{&mock_cl, nullptr};
   15.88 -
   15.89 -    void *test = calloc(8, 1);
   15.90 -    memcpy(test, "Test", 5);
   15.91 -    void *original = test;
   15.92 -    int ret = cxReallocate(&mock, &test, 16);
   15.93 -    // non-zero return code because of the failure
   15.94 -    EXPECT_NE(ret, 0);
   15.95 -    // the test pointer was not changed and still points to the same memory
   15.96 -    EXPECT_EQ(test, original);
   15.97 -    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
   15.98 -    free(test);
   15.99 -}
    16.1 --- a/test/test_basic_mempool.cpp	Wed Feb 08 20:26:09 2023 +0100
    16.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.3 @@ -1,154 +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 "cx/basic_mempool.h"
   16.33 -#include "util_allocator.h"
   16.34 -#include <gtest/gtest.h>
   16.35 -
   16.36 -class CxBasicMempool : public ::testing::Test {
   16.37 -protected:
   16.38 -    CxMempool *pool = nullptr;
   16.39 -
   16.40 -    void TearDown() override {
   16.41 -        if (pool != nullptr) {
   16.42 -            cxMempoolDestroy(pool);
   16.43 -        }
   16.44 -    }
   16.45 -};
   16.46 -
   16.47 -TEST_F(CxBasicMempool, Create) {
   16.48 -    pool = cxBasicMempoolCreate(16);
   16.49 -    ASSERT_NE(pool->allocator, nullptr);
   16.50 -    ASSERT_NE(pool->cl, nullptr);
   16.51 -    EXPECT_NE(pool->cl->destroy, nullptr);
   16.52 -    ASSERT_NE(pool->allocator->cl, nullptr);
   16.53 -    EXPECT_EQ(pool->allocator->data, pool);
   16.54 -    EXPECT_NE(pool->allocator->cl->malloc, nullptr);
   16.55 -    EXPECT_NE(pool->allocator->cl->calloc, nullptr);
   16.56 -    EXPECT_NE(pool->allocator->cl->realloc, nullptr);
   16.57 -    EXPECT_NE(pool->allocator->cl->free, nullptr);
   16.58 -
   16.59 -    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
   16.60 -    EXPECT_EQ(basic_pool->size, 16);
   16.61 -    EXPECT_EQ(basic_pool->ndata, 0);
   16.62 -    EXPECT_NE(basic_pool->data, nullptr);
   16.63 -}
   16.64 -
   16.65 -TEST_F(CxBasicMempool, malloc) {
   16.66 -    pool = cxBasicMempoolCreate(4);
   16.67 -    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
   16.68 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   16.69 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   16.70 -    EXPECT_EQ(basic_pool->ndata, 2);
   16.71 -    EXPECT_EQ(basic_pool->size, 4);
   16.72 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   16.73 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   16.74 -    EXPECT_EQ(basic_pool->ndata, 4);
   16.75 -    EXPECT_EQ(basic_pool->size, 4);
   16.76 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   16.77 -    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   16.78 -    EXPECT_EQ(basic_pool->ndata, 6);
   16.79 -    EXPECT_GE(basic_pool->size, 6);
   16.80 -}
   16.81 -
   16.82 -TEST_F(CxBasicMempool, calloc) {
   16.83 -    pool = cxBasicMempoolCreate(4);
   16.84 -
   16.85 -    auto test = (int *) cxCalloc(pool->allocator, 2, sizeof(int));
   16.86 -    ASSERT_NE(test, nullptr);
   16.87 -    EXPECT_EQ(test[0], 0);
   16.88 -    EXPECT_EQ(test[1], 0);
   16.89 -}
   16.90 -
   16.91 -static unsigned test_destructor_called = 0;
   16.92 -
   16.93 -static void test_destructor([[maybe_unused]] void *mem) {
   16.94 -    test_destructor_called++;
   16.95 -}
   16.96 -
   16.97 -TEST_F(CxBasicMempool, destructor) {
   16.98 -    pool = cxBasicMempoolCreate(4);
   16.99 -    auto data = cxMalloc(pool->allocator, sizeof(int));
  16.100 -    *((int *) data) = 13;
  16.101 -    cxMempoolSetDestructor(pool, data, test_destructor);
  16.102 -    EXPECT_EQ(*((int *) data), 13);
  16.103 -    test_destructor_called = 0;
  16.104 -    cxFree(pool->allocator, data);
  16.105 -    EXPECT_EQ(test_destructor_called, 1);
  16.106 -    data = cxMalloc(pool->allocator, sizeof(int));
  16.107 -    cxMempoolSetDestructor(pool, data, test_destructor);
  16.108 -    cxMempoolDestroy(pool);
  16.109 -    pool = nullptr;
  16.110 -    EXPECT_EQ(test_destructor_called, 2);
  16.111 -}
  16.112 -
  16.113 -TEST_F(CxBasicMempool, realloc) {
  16.114 -    pool = cxBasicMempoolCreate(4);
  16.115 -    auto data = cxMalloc(pool->allocator, sizeof(int));
  16.116 -    *((int *) data) = 13;
  16.117 -    cxMempoolSetDestructor(pool, data, test_destructor);
  16.118 -
  16.119 -    void *rdata = data;
  16.120 -    unsigned n = 1;
  16.121 -    while (rdata == data) {
  16.122 -        n <<= 1;
  16.123 -        ASSERT_LT(n, 65536); // eventually the memory should be moved elsewhere
  16.124 -        rdata = cxRealloc(pool->allocator, data, n * sizeof(intptr_t));
  16.125 -    }
  16.126 -
  16.127 -    EXPECT_EQ(*((int *) rdata), 13);
  16.128 -    // test if destructor is still intact
  16.129 -    test_destructor_called = 0;
  16.130 -    cxFree(pool->allocator, rdata);
  16.131 -    EXPECT_EQ(test_destructor_called, 1);
  16.132 -}
  16.133 -
  16.134 -
  16.135 -TEST_F(CxBasicMempool, free) {
  16.136 -    pool = cxBasicMempoolCreate(4);
  16.137 -    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
  16.138 -
  16.139 -    void *mem1;
  16.140 -    void *mem2;
  16.141 -
  16.142 -    mem1 = cxMalloc(pool->allocator, 16);
  16.143 -    cxFree(pool->allocator, mem1);
  16.144 -    EXPECT_EQ(basic_pool->ndata, 0);
  16.145 -
  16.146 -    cxMalloc(pool->allocator, 16);
  16.147 -    cxMalloc(pool->allocator, 16);
  16.148 -    mem1 = cxMalloc(pool->allocator, 16);
  16.149 -    cxMalloc(pool->allocator, 16);
  16.150 -    mem2 = cxMalloc(pool->allocator, 16);
  16.151 -
  16.152 -    EXPECT_EQ(basic_pool->ndata, 5);
  16.153 -    cxFree(pool->allocator, mem1);
  16.154 -    EXPECT_EQ(basic_pool->ndata, 4);
  16.155 -    cxFree(pool->allocator, mem2);
  16.156 -    EXPECT_EQ(basic_pool->ndata, 3);
  16.157 -}
  16.158 \ No newline at end of file
    17.1 --- a/test/test_buffer.cpp	Wed Feb 08 20:26:09 2023 +0100
    17.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.3 @@ -1,815 +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 -#include "cx/buffer.h"
   17.33 -
   17.34 -#include <gtest/gtest.h>
   17.35 -#include "util_allocator.h"
   17.36 -
   17.37 -class BufferFixture : public ::testing::Test {
   17.38 -protected:
   17.39 -    void SetUp() override {
   17.40 -        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   17.41 -        buf.size = 6;
   17.42 -        buf.pos = 3;
   17.43 -    }
   17.44 -
   17.45 -    void TearDown() override {
   17.46 -        cxBufferDestroy(&buf);
   17.47 -    }
   17.48 -
   17.49 -    CxBuffer buf{};
   17.50 -};
   17.51 -
   17.52 -static void expect_default_flush_config(CxBuffer *buf) {
   17.53 -    EXPECT_EQ(buf->flush_blkmax, 0);
   17.54 -    EXPECT_EQ(buf->flush_blksize, 4096);
   17.55 -    EXPECT_EQ(buf->flush_threshold, SIZE_MAX);
   17.56 -    EXPECT_EQ(buf->flush_func, nullptr);
   17.57 -    EXPECT_EQ(buf->flush_target, nullptr);
   17.58 -}
   17.59 -
   17.60 -TEST(BufferInit, WrapSpace) {
   17.61 -    CxTestingAllocator alloc;
   17.62 -    CxBuffer buf;
   17.63 -    void *space = cxMalloc(&alloc, 16);
   17.64 -    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_DEFAULT);
   17.65 -    expect_default_flush_config(&buf);
   17.66 -    EXPECT_EQ(buf.space, space);
   17.67 -    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
   17.68 -    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
   17.69 -    EXPECT_EQ(buf.pos, 0);
   17.70 -    EXPECT_EQ(buf.size, 0);
   17.71 -    EXPECT_EQ(buf.capacity, 16);
   17.72 -    EXPECT_EQ(buf.allocator, &alloc);
   17.73 -    cxBufferDestroy(&buf);
   17.74 -    EXPECT_FALSE(alloc.verify());
   17.75 -    cxFree(&alloc, space);
   17.76 -    EXPECT_TRUE(alloc.verify());
   17.77 -}
   17.78 -
   17.79 -TEST(BufferInit, WrapSpaceAutoExtend) {
   17.80 -    CxTestingAllocator alloc;
   17.81 -    CxBuffer buf;
   17.82 -    void *space = cxMalloc(&alloc, 16);
   17.83 -    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_AUTO_EXTEND);
   17.84 -    expect_default_flush_config(&buf);
   17.85 -    EXPECT_EQ(buf.space, space);
   17.86 -    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, CX_BUFFER_AUTO_EXTEND);
   17.87 -    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
   17.88 -    EXPECT_EQ(buf.pos, 0);
   17.89 -    EXPECT_EQ(buf.size, 0);
   17.90 -    EXPECT_EQ(buf.capacity, 16);
   17.91 -    EXPECT_EQ(buf.allocator, &alloc);
   17.92 -    cxBufferDestroy(&buf);
   17.93 -    EXPECT_FALSE(alloc.verify());
   17.94 -    cxFree(&alloc, space);
   17.95 -    EXPECT_TRUE(alloc.verify());
   17.96 -}
   17.97 -
   17.98 -TEST(BufferInit, WrapSpaceAutoFree) {
   17.99 -    CxTestingAllocator alloc;
  17.100 -    CxBuffer buf;
  17.101 -    void *space = cxMalloc(&alloc, 16);
  17.102 -    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_FREE_CONTENTS);
  17.103 -    expect_default_flush_config(&buf);
  17.104 -    EXPECT_EQ(buf.space, space);
  17.105 -    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
  17.106 -    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
  17.107 -    EXPECT_EQ(buf.pos, 0);
  17.108 -    EXPECT_EQ(buf.size, 0);
  17.109 -    EXPECT_EQ(buf.capacity, 16);
  17.110 -    EXPECT_EQ(buf.allocator, &alloc);
  17.111 -    EXPECT_FALSE(alloc.verify());
  17.112 -    cxBufferDestroy(&buf);
  17.113 -    EXPECT_TRUE(alloc.verify());
  17.114 -}
  17.115 -
  17.116 -TEST(BufferInit, FreshSpace) {
  17.117 -    CxTestingAllocator alloc;
  17.118 -    CxBuffer buf;
  17.119 -    cxBufferInit(&buf, nullptr, 8, &alloc, CX_BUFFER_DEFAULT);
  17.120 -    expect_default_flush_config(&buf);
  17.121 -    EXPECT_NE(buf.space, nullptr);
  17.122 -    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
  17.123 -    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
  17.124 -    EXPECT_EQ(buf.pos, 0);
  17.125 -    EXPECT_EQ(buf.size, 0);
  17.126 -    EXPECT_EQ(buf.capacity, 8);
  17.127 -    EXPECT_EQ(buf.allocator, &alloc);
  17.128 -    EXPECT_FALSE(alloc.verify()); // space is still allocated
  17.129 -    cxBufferDestroy(&buf);
  17.130 -    EXPECT_TRUE(alloc.verify());
  17.131 -}
  17.132 -
  17.133 -class BufferShiftFixture : public ::testing::Test {
  17.134 -protected:
  17.135 -    void SetUp() override {
  17.136 -        ASSERT_TRUE(alloc.verify());
  17.137 -        cxBufferInit(&buf, nullptr, 16, &alloc, CX_BUFFER_DEFAULT);
  17.138 -        memcpy(buf.space, "test____________", 16);
  17.139 -        buf.capacity = 8; // purposely pretend that the buffer has less capacity s.t. we can test beyond the range
  17.140 -        buf.pos = 4;
  17.141 -        buf.size = 4;
  17.142 -    }
  17.143 -
  17.144 -    void TearDown() override {
  17.145 -        cxBufferDestroy(&buf);
  17.146 -        EXPECT_TRUE(alloc.verify());
  17.147 -    }
  17.148 -
  17.149 -    CxTestingAllocator alloc;
  17.150 -    CxBuffer buf{};
  17.151 -};
  17.152 -
  17.153 -class BufferShiftLeft : public BufferShiftFixture {
  17.154 -};
  17.155 -
  17.156 -TEST_F(BufferShiftLeft, Zero) {
  17.157 -    ASSERT_EQ(buf.pos, 4);
  17.158 -    ASSERT_EQ(buf.size, 4);
  17.159 -    int ret = cxBufferShiftLeft(&buf, 0);
  17.160 -    EXPECT_EQ(ret, 0);
  17.161 -    EXPECT_EQ(buf.pos, 4);
  17.162 -    EXPECT_EQ(buf.size, 4);
  17.163 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  17.164 -}
  17.165 -
  17.166 -TEST_F(BufferShiftLeft, ZeroOffsetInterface) {
  17.167 -    ASSERT_EQ(buf.pos, 4);
  17.168 -    ASSERT_EQ(buf.size, 4);
  17.169 -    int ret = cxBufferShift(&buf, -0);
  17.170 -    EXPECT_EQ(ret, 0);
  17.171 -    EXPECT_EQ(buf.pos, 4);
  17.172 -    EXPECT_EQ(buf.size, 4);
  17.173 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  17.174 -}
  17.175 -
  17.176 -TEST_F(BufferShiftLeft, Standard) {
  17.177 -    ASSERT_EQ(buf.pos, 4);
  17.178 -    ASSERT_EQ(buf.size, 4);
  17.179 -    int ret = cxBufferShiftLeft(&buf, 2);
  17.180 -    EXPECT_EQ(ret, 0);
  17.181 -    EXPECT_EQ(buf.pos, 2);
  17.182 -    EXPECT_EQ(buf.size, 2);
  17.183 -    EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
  17.184 -}
  17.185 -
  17.186 -TEST_F(BufferShiftLeft, Overshift) {
  17.187 -    ASSERT_LT(buf.pos, 6);
  17.188 -    ASSERT_LT(buf.size, 6);
  17.189 -    int ret = cxBufferShiftLeft(&buf, 6);
  17.190 -    EXPECT_EQ(ret, 0);
  17.191 -    EXPECT_EQ(buf.pos, 0);
  17.192 -    EXPECT_EQ(buf.size, 0);
  17.193 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  17.194 -}
  17.195 -
  17.196 -TEST_F(BufferShiftLeft, OvershiftPosOnly) {
  17.197 -    buf.pos = 2;
  17.198 -    ASSERT_EQ(buf.size, 4);
  17.199 -    int ret = cxBufferShiftLeft(&buf, 3);
  17.200 -    EXPECT_EQ(ret, 0);
  17.201 -    EXPECT_EQ(buf.pos, 0);
  17.202 -    EXPECT_EQ(buf.size, 1);
  17.203 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  17.204 -}
  17.205 -
  17.206 -TEST_F(BufferShiftLeft, OffsetInterface) {
  17.207 -    buf.pos = 3;
  17.208 -    ASSERT_EQ(buf.size, 4);
  17.209 -    int ret = cxBufferShift(&buf, -2);
  17.210 -    EXPECT_EQ(ret, 0);
  17.211 -    EXPECT_EQ(buf.pos, 1);
  17.212 -    EXPECT_EQ(buf.size, 2);
  17.213 -    EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
  17.214 -}
  17.215 -
  17.216 -class BufferShiftRight : public BufferShiftFixture {
  17.217 -};
  17.218 -
  17.219 -TEST_F(BufferShiftRight, Zero) {
  17.220 -    ASSERT_EQ(buf.pos, 4);
  17.221 -    ASSERT_EQ(buf.size, 4);
  17.222 -    int ret = cxBufferShiftRight(&buf, 0);
  17.223 -    EXPECT_EQ(ret, 0);
  17.224 -    EXPECT_EQ(buf.pos, 4);
  17.225 -    EXPECT_EQ(buf.size, 4);
  17.226 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  17.227 -}
  17.228 -
  17.229 -TEST_F(BufferShiftRight, ZeroOffsetInterface) {
  17.230 -    ASSERT_EQ(buf.pos, 4);
  17.231 -    ASSERT_EQ(buf.size, 4);
  17.232 -    int ret = cxBufferShift(&buf, +0);
  17.233 -    EXPECT_EQ(ret, 0);
  17.234 -    EXPECT_EQ(buf.pos, 4);
  17.235 -    EXPECT_EQ(buf.size, 4);
  17.236 -    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  17.237 -}
  17.238 -
  17.239 -TEST_F(BufferShiftRight, Standard) {
  17.240 -    ASSERT_EQ(buf.pos, 4);
  17.241 -    ASSERT_EQ(buf.size, 4);
  17.242 -    int ret = cxBufferShiftRight(&buf, 3);
  17.243 -    EXPECT_EQ(ret, 0);
  17.244 -    EXPECT_EQ(buf.pos, 7);
  17.245 -    EXPECT_EQ(buf.size, 7);
  17.246 -    EXPECT_TRUE(memcmp(buf.space, "testest_____", 8) == 0);
  17.247 -}
  17.248 -
  17.249 -TEST_F(BufferShiftRight, OvershiftDiscard) {
  17.250 -    ASSERT_EQ(buf.pos, 4);
  17.251 -    ASSERT_EQ(buf.size, 4);
  17.252 -    ASSERT_EQ(buf.capacity, 8);
  17.253 -    int ret = cxBufferShiftRight(&buf, 6);
  17.254 -    EXPECT_EQ(ret, 0);
  17.255 -    EXPECT_EQ(buf.pos, 8);
  17.256 -    EXPECT_EQ(buf.size, 8);
  17.257 -    EXPECT_EQ(buf.capacity, 8);
  17.258 -    EXPECT_TRUE(memcmp(buf.space, "test__te____", 8) == 0);
  17.259 -}
  17.260 -
  17.261 -TEST_F(BufferShiftRight, OvershiftExtend) {
  17.262 -    ASSERT_EQ(buf.pos, 4);
  17.263 -    ASSERT_EQ(buf.size, 4);
  17.264 -    ASSERT_EQ(buf.capacity, 8);
  17.265 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  17.266 -    int ret = cxBufferShiftRight(&buf, 6);
  17.267 -    EXPECT_EQ(ret, 0);
  17.268 -    EXPECT_EQ(buf.pos, 10);
  17.269 -    EXPECT_EQ(buf.size, 10);
  17.270 -    EXPECT_GE(buf.capacity, 10);
  17.271 -    EXPECT_TRUE(memcmp(buf.space, "test__test__", 8) == 0);
  17.272 -}
  17.273 -
  17.274 -TEST_F(BufferShiftRight, OffsetInterface) {
  17.275 -    buf.pos = 3;
  17.276 -    ASSERT_EQ(buf.size, 4);
  17.277 -    int ret = cxBufferShift(&buf, 2);
  17.278 -    EXPECT_EQ(ret, 0);
  17.279 -    EXPECT_EQ(buf.pos, 5);
  17.280 -    EXPECT_EQ(buf.size, 6);
  17.281 -    EXPECT_TRUE(memcmp(buf.space, "tetest______", 8) == 0);
  17.282 -}
  17.283 -
  17.284 -TEST(BufferMinimumCapacity, Sufficient) {
  17.285 -    CxTestingAllocator alloc;
  17.286 -    auto space = cxMalloc(&alloc, 8);
  17.287 -    CxBuffer buf;
  17.288 -    cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS);
  17.289 -    memcpy(space, "Testing", 8);
  17.290 -    buf.size = 8;
  17.291 -    cxBufferMinimumCapacity(&buf, 6);
  17.292 -    EXPECT_EQ(buf.capacity, 8);
  17.293 -    EXPECT_EQ(buf.size, 8);
  17.294 -    EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
  17.295 -    cxBufferDestroy(&buf);
  17.296 -    EXPECT_TRUE(alloc.verify());
  17.297 -}
  17.298 -
  17.299 -TEST(BufferMinimumCapacity, Extend) {
  17.300 -    CxTestingAllocator alloc;
  17.301 -    auto space = cxMalloc(&alloc, 8);
  17.302 -    CxBuffer buf;
  17.303 -    cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS); // NO auto extend!
  17.304 -    memcpy(space, "Testing", 8);
  17.305 -    buf.size = 8;
  17.306 -    cxBufferMinimumCapacity(&buf, 16);
  17.307 -    EXPECT_EQ(buf.capacity, 16);
  17.308 -    EXPECT_EQ(buf.size, 8);
  17.309 -    EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
  17.310 -    cxBufferDestroy(&buf);
  17.311 -    EXPECT_TRUE(alloc.verify());
  17.312 -}
  17.313 -
  17.314 -TEST(BufferClear, Test) {
  17.315 -    char space[16];
  17.316 -    strcpy(space, "clear test");
  17.317 -    CxBuffer buf;
  17.318 -    cxBufferInit(&buf, space, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
  17.319 -    ASSERT_EQ(buf.size, 0);
  17.320 -    // only clear the used part of the buffer
  17.321 -    cxBufferClear(&buf);
  17.322 -    EXPECT_EQ(memcmp(space, "clear test", 10), 0);
  17.323 -    buf.size = 5;
  17.324 -    buf.pos = 3;
  17.325 -    cxBufferClear(&buf);
  17.326 -    EXPECT_EQ(memcmp(space, "\0\0\0\0\0 test", 10), 0);
  17.327 -    EXPECT_EQ(buf.size, 0);
  17.328 -    EXPECT_EQ(buf.pos, 0);
  17.329 -    cxBufferDestroy(&buf);
  17.330 -}
  17.331 -
  17.332 -class BufferWrite : public ::testing::Test {
  17.333 -protected:
  17.334 -    CxBuffer buf{}, target{};
  17.335 -
  17.336 -    void SetUp() override {
  17.337 -        cxBufferInit(&target, nullptr, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
  17.338 -        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
  17.339 -        buf.capacity = 8; // artificially reduce capacity to check OOB writes
  17.340 -        memset(buf.space, 0, 16);
  17.341 -        memcpy(buf.space, "prep", 4);
  17.342 -        buf.size = buf.pos = 4;
  17.343 -    }
  17.344 -
  17.345 -    void TearDown() override {
  17.346 -        cxBufferDestroy(&buf);
  17.347 -        cxBufferDestroy(&target);
  17.348 -    }
  17.349 -
  17.350 -    void enableFlushing() {
  17.351 -        buf.flush_target = &target;
  17.352 -        buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
  17.353 -        buf.flush_blkmax = 1;
  17.354 -    }
  17.355 -};
  17.356 -
  17.357 -static size_t mock_write_limited_rate(
  17.358 -        void const *ptr,
  17.359 -        size_t size,
  17.360 -        __attribute__((unused)) size_t nitems,
  17.361 -        CxBuffer *buffer
  17.362 -) {
  17.363 -    // simulate limited target drain capacity
  17.364 -    static bool full = false;
  17.365 -    if (full) {
  17.366 -        full = false;
  17.367 -        return 0;
  17.368 -    } else {
  17.369 -        full = true;
  17.370 -        return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
  17.371 -    }
  17.372 -}
  17.373 -
  17.374 -TEST_F(BufferWrite, SizeOneFit) {
  17.375 -    const char *data = "test";
  17.376 -    ASSERT_EQ(buf.capacity, 8);
  17.377 -    ASSERT_EQ(buf.pos, 4);
  17.378 -    ASSERT_EQ(buf.size, 4);
  17.379 -    size_t written = cxBufferWrite(data, 1, 4, &buf);
  17.380 -    EXPECT_EQ(written, 4);
  17.381 -    EXPECT_EQ(buf.size, 8);
  17.382 -    EXPECT_EQ(buf.pos, 8);
  17.383 -    EXPECT_EQ(buf.capacity, 8);
  17.384 -    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
  17.385 -}
  17.386 -
  17.387 -TEST_F(BufferWrite, SizeOneDiscard) {
  17.388 -    const char *data = "testing";
  17.389 -    ASSERT_EQ(buf.capacity, 8);
  17.390 -    ASSERT_EQ(buf.pos, 4);
  17.391 -    ASSERT_EQ(buf.size, 4);
  17.392 -    size_t written = cxBufferWrite(data, 1, 7, &buf);
  17.393 -    EXPECT_EQ(written, 4);
  17.394 -    EXPECT_EQ(buf.size, 8);
  17.395 -    EXPECT_EQ(buf.pos, 8);
  17.396 -    EXPECT_EQ(buf.capacity, 8);
  17.397 -    EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
  17.398 -}
  17.399 -
  17.400 -TEST_F(BufferWrite, SizeOneExtend) {
  17.401 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  17.402 -    const char *data = "testing";
  17.403 -    ASSERT_EQ(buf.capacity, 8);
  17.404 -    ASSERT_EQ(buf.pos, 4);
  17.405 -    ASSERT_EQ(buf.size, 4);
  17.406 -    size_t written = cxBufferWrite(data, 1, 7, &buf);
  17.407 -    EXPECT_EQ(written, 7);
  17.408 -    EXPECT_EQ(buf.size, 11);
  17.409 -    EXPECT_EQ(buf.pos, 11);
  17.410 -    EXPECT_GE(buf.capacity, 11);
  17.411 -    EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
  17.412 -}
  17.413 -
  17.414 -TEST_F(BufferWrite, MultibyteFit) {
  17.415 -    const char *data = "test";
  17.416 -    ASSERT_EQ(buf.capacity, 8);
  17.417 -    ASSERT_EQ(buf.pos, 4);
  17.418 -    ASSERT_EQ(buf.size, 4);
  17.419 -    size_t written = cxBufferWrite(data, 2, 2, &buf);
  17.420 -    EXPECT_EQ(written, 2);
  17.421 -    EXPECT_EQ(buf.size, 8);
  17.422 -    EXPECT_EQ(buf.pos, 8);
  17.423 -    EXPECT_EQ(buf.capacity, 8);
  17.424 -    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
  17.425 -}
  17.426 -
  17.427 -TEST_F(BufferWrite, MultibyteDiscard) {
  17.428 -    const char *data = "testing";
  17.429 -    ASSERT_EQ(buf.capacity, 8);
  17.430 -    ASSERT_EQ(buf.size, 4);
  17.431 -    buf.pos = 3;
  17.432 -    size_t written = cxBufferWrite(data, 2, 4, &buf);
  17.433 -    // remember: whole elements are discarded if they do not fit
  17.434 -    EXPECT_EQ(written, 2);
  17.435 -    EXPECT_EQ(buf.size, 7);
  17.436 -    EXPECT_EQ(buf.pos, 7);
  17.437 -    EXPECT_EQ(buf.capacity, 8);
  17.438 -    EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0);
  17.439 -}
  17.440 -
  17.441 -TEST_F(BufferWrite, MultibyteExtend) {
  17.442 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  17.443 -    const char *data = "tester";
  17.444 -    ASSERT_EQ(buf.capacity, 8);
  17.445 -    ASSERT_EQ(buf.size, 4);
  17.446 -    buf.pos = 3;
  17.447 -    size_t written = cxBufferWrite(data, 2, 3, &buf);
  17.448 -    // remember: whole elements are discarded if they do not fit
  17.449 -    EXPECT_EQ(written, 3);
  17.450 -    EXPECT_EQ(buf.size, 9);
  17.451 -    EXPECT_EQ(buf.pos, 9);
  17.452 -    EXPECT_GE(buf.capacity, 9);
  17.453 -    EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0);
  17.454 -}
  17.455 -
  17.456 -TEST_F(BufferWrite, PutcWrapperFit) {
  17.457 -    ASSERT_EQ(buf.capacity, 8);
  17.458 -    ASSERT_EQ(buf.pos, 4);
  17.459 -    ASSERT_EQ(buf.size, 4);
  17.460 -    int c = cxBufferPut(&buf, 0x200 | 'a');
  17.461 -    EXPECT_EQ(c, 'a');
  17.462 -    EXPECT_EQ(buf.size, 5);
  17.463 -    EXPECT_EQ(buf.pos, 5);
  17.464 -    EXPECT_EQ(buf.capacity, 8);
  17.465 -    EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0);
  17.466 -}
  17.467 -
  17.468 -TEST_F(BufferWrite, PutcWrapperDiscard) {
  17.469 -    ASSERT_EQ(buf.capacity, 8);
  17.470 -    ASSERT_EQ(buf.size, 4);
  17.471 -    buf.pos = 8;
  17.472 -    int c = cxBufferPut(&buf, 0x200 | 'a');
  17.473 -    EXPECT_EQ(c, EOF);
  17.474 -    EXPECT_EQ(buf.size, 4);
  17.475 -    EXPECT_EQ(buf.pos, 8);
  17.476 -    EXPECT_EQ(buf.capacity, 8);
  17.477 -    EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0);
  17.478 -}
  17.479 -
  17.480 -TEST_F(BufferWrite, PutcWrapperExtend) {
  17.481 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  17.482 -    ASSERT_EQ(buf.capacity, 8);
  17.483 -    ASSERT_EQ(buf.size, 4);
  17.484 -    buf.pos = 8;
  17.485 -    int c = cxBufferPut(&buf, 0x200 | 'a');
  17.486 -    EXPECT_EQ(c, 'a');
  17.487 -    EXPECT_EQ(buf.size, 9);
  17.488 -    EXPECT_EQ(buf.pos, 9);
  17.489 -    EXPECT_GE(buf.capacity, 9);
  17.490 -    EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0);
  17.491 -}
  17.492 -
  17.493 -TEST_F(BufferWrite, PutStringWrapperFit) {
  17.494 -    const char *data = "test";
  17.495 -    ASSERT_EQ(buf.capacity, 8);
  17.496 -    ASSERT_EQ(buf.pos, 4);
  17.497 -    ASSERT_EQ(buf.size, 4);
  17.498 -    size_t written = cxBufferPutString(&buf, data);
  17.499 -    EXPECT_EQ(written, 4);
  17.500 -    EXPECT_EQ(buf.size, 8);
  17.501 -    EXPECT_EQ(buf.pos, 8);
  17.502 -    EXPECT_EQ(buf.capacity, 8);
  17.503 -    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
  17.504 -}
  17.505 -
  17.506 -TEST_F(BufferWrite, PutStringWrapperDiscard) {
  17.507 -    const char *data = "testing";
  17.508 -    ASSERT_EQ(buf.capacity, 8);
  17.509 -    ASSERT_EQ(buf.pos, 4);
  17.510 -    ASSERT_EQ(buf.size, 4);
  17.511 -    size_t written = cxBufferPutString(&buf, data);
  17.512 -    EXPECT_EQ(written, 4);
  17.513 -    EXPECT_EQ(buf.size, 8);
  17.514 -    EXPECT_EQ(buf.pos, 8);
  17.515 -    EXPECT_EQ(buf.capacity, 8);
  17.516 -    EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
  17.517 -}
  17.518 -
  17.519 -TEST_F(BufferWrite, PutStringWrapperExtend) {
  17.520 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  17.521 -    const char *data = "testing";
  17.522 -    ASSERT_EQ(buf.capacity, 8);
  17.523 -    ASSERT_EQ(buf.pos, 4);
  17.524 -    ASSERT_EQ(buf.size, 4);
  17.525 -    size_t written = cxBufferPutString(&buf, data);
  17.526 -    EXPECT_EQ(written, 7);
  17.527 -    EXPECT_EQ(buf.size, 11);
  17.528 -    EXPECT_EQ(buf.pos, 11);
  17.529 -    EXPECT_GE(buf.capacity, 11);
  17.530 -    EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
  17.531 -}
  17.532 -
  17.533 -TEST_F(BufferWrite, MultOverflow) {
  17.534 -    const char *data = "testing";
  17.535 -    ASSERT_EQ(buf.capacity, 8);
  17.536 -    ASSERT_EQ(buf.pos, 4);
  17.537 -    ASSERT_EQ(buf.size, 4);
  17.538 -    size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf);
  17.539 -    EXPECT_EQ(written, 0);
  17.540 -    EXPECT_EQ(buf.capacity, 8);
  17.541 -    EXPECT_EQ(buf.pos, 4);
  17.542 -    EXPECT_EQ(buf.size, 4);
  17.543 -    EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
  17.544 -}
  17.545 -
  17.546 -TEST_F(BufferWrite, MaxCapaOverflow) {
  17.547 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  17.548 -    const char *data = "testing";
  17.549 -    ASSERT_EQ(buf.capacity, 8);
  17.550 -    ASSERT_EQ(buf.pos, 4);
  17.551 -    ASSERT_EQ(buf.size, 4);
  17.552 -    size_t written = cxBufferWrite(data, 1, SIZE_MAX - 2, &buf);
  17.553 -    EXPECT_EQ(written, 0);
  17.554 -    EXPECT_EQ(buf.capacity, 8);
  17.555 -    EXPECT_EQ(buf.pos, 4);
  17.556 -    EXPECT_EQ(buf.size, 4);
  17.557 -    EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
  17.558 -}
  17.559 -
  17.560 -TEST_F(BufferWrite, OnlyOverwrite) {
  17.561 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  17.562 -    ASSERT_EQ(buf.capacity, 8);
  17.563 -    memcpy(buf.space, "preptest", 8);
  17.564 -    buf.pos = 3;
  17.565 -    buf.size = 8;
  17.566 -    size_t written = cxBufferWrite("XXX", 2, 2, &buf);
  17.567 -    EXPECT_EQ(written, 2);
  17.568 -    EXPECT_EQ(buf.capacity, 8);
  17.569 -    EXPECT_EQ(buf.size, 8);
  17.570 -    EXPECT_EQ(buf.pos, 7);
  17.571 -    EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0);
  17.572 -}
  17.573 -
  17.574 -TEST_F(BufferWrite, FlushAtCapacity) {
  17.575 -    enableFlushing();
  17.576 -    ASSERT_EQ(buf.capacity, 8);
  17.577 -    ASSERT_EQ(buf.pos, 4);
  17.578 -    size_t written = cxBufferWrite("foo", 1, 3, &buf);
  17.579 -    EXPECT_EQ(written, 3);
  17.580 -    ASSERT_EQ(buf.pos, 7);
  17.581 -    ASSERT_EQ(buf.size, 7);
  17.582 -    ASSERT_EQ(target.pos, 0);
  17.583 -    ASSERT_EQ(target.size, 0);
  17.584 -    written = cxBufferWrite("hello", 1, 5, &buf);
  17.585 -    EXPECT_EQ(written, 5);
  17.586 -    EXPECT_EQ(buf.pos, 0);
  17.587 -    EXPECT_EQ(buf.size, 0);
  17.588 -    EXPECT_EQ(buf.capacity, 8);
  17.589 -    EXPECT_EQ(target.pos, 12);
  17.590 -    ASSERT_EQ(target.size, 12);
  17.591 -    EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0);
  17.592 -}
  17.593 -
  17.594 -TEST_F(BufferWrite, FlushAtThreshold) {
  17.595 -    enableFlushing();
  17.596 -    buf.flush_threshold = 12;
  17.597 -    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  17.598 -    ASSERT_EQ(buf.capacity, 8);
  17.599 -    ASSERT_EQ(buf.pos, 4);
  17.600 -    size_t written = cxBufferWrite("foobar", 1, 6, &buf);
  17.601 -    EXPECT_EQ(written, 6);
  17.602 -    ASSERT_EQ(buf.pos, 10);
  17.603 -    ASSERT_EQ(buf.size, 10);
  17.604 -    ASSERT_GE(buf.capacity, 10);
  17.605 -    ASSERT_LE(buf.capacity, 12);
  17.606 -    ASSERT_EQ(target.pos, 0);
  17.607 -    ASSERT_EQ(target.size, 0);
  17.608 -    written = cxBufferWrite("hello", 1, 5, &buf);
  17.609 -    EXPECT_EQ(written, 5);
  17.610 -    EXPECT_EQ(buf.pos, 0);
  17.611 -    EXPECT_EQ(buf.size, 0);
  17.612 -    EXPECT_LE(buf.capacity, 12);
  17.613 -    EXPECT_EQ(target.pos, 15);
  17.614 -    ASSERT_EQ(target.size, 15);
  17.615 -    EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0);
  17.616 -}
  17.617 -
  17.618 -TEST_F(BufferWrite, FlushRateLimited) {
  17.619 -    enableFlushing();
  17.620 -    // limit the rate of the flush function and the capacity of the target
  17.621 -    target.capacity = 16;
  17.622 -    target.flags &= ~CX_BUFFER_AUTO_EXTEND;
  17.623 -    buf.flush_func = (cx_write_func) mock_write_limited_rate;
  17.624 -    ASSERT_EQ(buf.capacity, 8);
  17.625 -    ASSERT_EQ(buf.pos, 4);
  17.626 -    size_t written = cxBufferWrite("foo", 1, 3, &buf);
  17.627 -    EXPECT_EQ(written, 3);
  17.628 -    ASSERT_EQ(buf.pos, 7);
  17.629 -    ASSERT_EQ(buf.size, 7);
  17.630 -    ASSERT_EQ(target.pos, 0);
  17.631 -    ASSERT_EQ(target.size, 0);
  17.632 -    written = cxBufferWrite("hello, world!", 1, 13, &buf);
  17.633 -    // " world!" fits into this buffer, the remaining stuff is flushed out
  17.634 -    EXPECT_EQ(written, 13);
  17.635 -    EXPECT_EQ(buf.pos, 7);
  17.636 -    EXPECT_EQ(buf.size, 7);
  17.637 -    EXPECT_EQ(buf.capacity, 8);
  17.638 -    EXPECT_EQ(memcmp(buf.space, " world!", 7), 0);
  17.639 -    EXPECT_EQ(target.pos, 13);
  17.640 -    ASSERT_EQ(target.size, 13);
  17.641 -    EXPECT_EQ(target.capacity, 16);
  17.642 -    EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0);
  17.643 -}
  17.644 -
  17.645 -class BufferSeek : public BufferFixture {
  17.646 -};
  17.647 -
  17.648 -TEST_F(BufferSeek, SetZero) {
  17.649 -    int result = cxBufferSeek(&buf, 0, SEEK_SET);
  17.650 -    EXPECT_EQ(result, 0);
  17.651 -    EXPECT_EQ(buf.pos, 0);
  17.652 -}
  17.653 -
  17.654 -TEST_F(BufferSeek, SetValid) {
  17.655 -    int result = cxBufferSeek(&buf, 5, SEEK_SET);
  17.656 -    EXPECT_EQ(result, 0);
  17.657 -    EXPECT_EQ(buf.pos, 5);
  17.658 -}
  17.659 -
  17.660 -TEST_F(BufferSeek, SetInvalid) {
  17.661 -    ASSERT_EQ(buf.pos, 3);
  17.662 -    int result = cxBufferSeek(&buf, 6, SEEK_SET);
  17.663 -    EXPECT_NE(result, 0);
  17.664 -    EXPECT_EQ(buf.pos, 3);
  17.665 -}
  17.666 -
  17.667 -TEST_F(BufferSeek, CurZero) {
  17.668 -    ASSERT_EQ(buf.pos, 3);
  17.669 -    int result = cxBufferSeek(&buf, 0, SEEK_CUR);
  17.670 -    EXPECT_EQ(result, 0);
  17.671 -    EXPECT_EQ(buf.pos, 3);
  17.672 -}
  17.673 -
  17.674 -TEST_F(BufferSeek, CurValidPositive) {
  17.675 -    ASSERT_EQ(buf.pos, 3);
  17.676 -    int result = cxBufferSeek(&buf, 2, SEEK_CUR);
  17.677 -    EXPECT_EQ(result, 0);
  17.678 -    EXPECT_EQ(buf.pos, 5);
  17.679 -}
  17.680 -
  17.681 -TEST_F(BufferSeek, CurValidNegative) {
  17.682 -    ASSERT_EQ(buf.pos, 3);
  17.683 -    int result = cxBufferSeek(&buf, -3, SEEK_CUR);
  17.684 -    EXPECT_EQ(result, 0);
  17.685 -    EXPECT_EQ(buf.pos, 0);
  17.686 -}
  17.687 -
  17.688 -TEST_F(BufferSeek, CurInvalidPositive) {
  17.689 -    ASSERT_EQ(buf.pos, 3);
  17.690 -    int result = cxBufferSeek(&buf, 3, SEEK_CUR);
  17.691 -    EXPECT_NE(result, 0);
  17.692 -    EXPECT_EQ(buf.pos, 3);
  17.693 -}
  17.694 -
  17.695 -TEST_F(BufferSeek, CurInvalidNegative) {
  17.696 -    ASSERT_EQ(buf.pos, 3);
  17.697 -    int result = cxBufferSeek(&buf, -4, SEEK_CUR);
  17.698 -    EXPECT_NE(result, 0);
  17.699 -    EXPECT_EQ(buf.pos, 3);
  17.700 -}
  17.701 -
  17.702 -TEST_F(BufferSeek, EndZero) {
  17.703 -    ASSERT_EQ(buf.size, 6);
  17.704 -    int result = cxBufferSeek(&buf, 0, SEEK_END);
  17.705 -    // the (past-the-)end position is always invalid
  17.706 -    EXPECT_NE(result, 0);
  17.707 -    EXPECT_EQ(buf.pos, 3);
  17.708 -}
  17.709 -
  17.710 -TEST_F(BufferSeek, EndValid) {
  17.711 -    ASSERT_EQ(buf.size, 6);
  17.712 -    int result = cxBufferSeek(&buf, -6, SEEK_END);
  17.713 -    EXPECT_EQ(result, 0);
  17.714 -    EXPECT_EQ(buf.pos, 0);
  17.715 -}
  17.716 -
  17.717 -TEST_F(BufferSeek, EndInvalid) {
  17.718 -    ASSERT_EQ(buf.size, 6);
  17.719 -    int result = cxBufferSeek(&buf, 1, SEEK_END);
  17.720 -    EXPECT_NE(result, 0);
  17.721 -    EXPECT_EQ(buf.pos, 3);
  17.722 -}
  17.723 -
  17.724 -TEST_F(BufferSeek, WhenceInvalid) {
  17.725 -    ASSERT_EQ(buf.size, 6);
  17.726 -    ASSERT_EQ(buf.pos, 3);
  17.727 -    int result = cxBufferSeek(&buf, 2, 9000);
  17.728 -    EXPECT_NE(result, 0);
  17.729 -    EXPECT_EQ(buf.size, 6);
  17.730 -    EXPECT_EQ(buf.pos, 3);
  17.731 -}
  17.732 -
  17.733 -class BufferEof : public BufferFixture {
  17.734 -};
  17.735 -
  17.736 -TEST_F(BufferEof, Reached) {
  17.737 -    buf.pos = buf.size;
  17.738 -    EXPECT_TRUE(cxBufferEof(&buf));
  17.739 -    buf.pos = buf.size - 1;
  17.740 -    ASSERT_FALSE(cxBufferEof(&buf));
  17.741 -    cxBufferPut(&buf, 'a');
  17.742 -    EXPECT_TRUE(cxBufferEof(&buf));
  17.743 -}
  17.744 -
  17.745 -TEST_F(BufferEof, NotReached) {
  17.746 -    buf.pos = buf.size - 1;
  17.747 -    EXPECT_FALSE(cxBufferEof(&buf));
  17.748 -    buf.pos = 0;
  17.749 -    cxBufferWrite("test", 1, 5, &buf);
  17.750 -    EXPECT_FALSE(cxBufferEof(&buf));
  17.751 -}
  17.752 -
  17.753 -class BufferRead : public ::testing::Test {
  17.754 -protected:
  17.755 -    CxBuffer buf{};
  17.756 -
  17.757 -    void SetUp() override {
  17.758 -        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
  17.759 -        buf.capacity = 8; // artificially reduce capacity to check OOB writes
  17.760 -        memset(buf.space, 0, 16);
  17.761 -        memcpy(buf.space, "some data", 9);
  17.762 -        buf.size = 9;
  17.763 -    }
  17.764 -
  17.765 -    void TearDown() override {
  17.766 -        cxBufferDestroy(&buf);
  17.767 -    }
  17.768 -};
  17.769 -
  17.770 -TEST_F(BufferRead, GetByte) {
  17.771 -    buf.pos = 2;
  17.772 -    EXPECT_EQ(cxBufferGet(&buf), 'm');
  17.773 -    EXPECT_EQ(cxBufferGet(&buf), 'e');
  17.774 -    EXPECT_EQ(cxBufferGet(&buf), ' ');
  17.775 -    EXPECT_EQ(cxBufferGet(&buf), 'd');
  17.776 -    EXPECT_EQ(buf.pos, 6);
  17.777 -}
  17.778 -
  17.779 -TEST_F(BufferRead, GetEof) {
  17.780 -    buf.pos = buf.size;
  17.781 -    EXPECT_EQ(cxBufferGet(&buf), EOF);
  17.782 -}
  17.783 -
  17.784 -TEST_F(BufferRead, ReadWithinBounds) {
  17.785 -    buf.pos = 2;
  17.786 -    char target[4];
  17.787 -    auto read = cxBufferRead(&target, 1, 4, &buf);
  17.788 -    ASSERT_EQ(read, 4);
  17.789 -    EXPECT_EQ(memcmp(&target, "me d", 4), 0);
  17.790 -    EXPECT_EQ(buf.pos, 6);
  17.791 -}
  17.792 -
  17.793 -TEST_F(BufferRead, ReadOutOfBounds) {
  17.794 -    buf.pos = 6;
  17.795 -    char target[4];
  17.796 -    auto read = cxBufferRead(&target, 1, 4, &buf);
  17.797 -    ASSERT_EQ(read, 3);
  17.798 -    EXPECT_EQ(memcmp(&target, "ata", 3), 0);
  17.799 -    EXPECT_EQ(buf.pos, 9);
  17.800 -}
  17.801 -
  17.802 -TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
  17.803 -    buf.pos = 6;
  17.804 -    char target[4];
  17.805 -    target[2] = '\0';
  17.806 -    auto read = cxBufferRead(&target, 2, 2, &buf);
  17.807 -    ASSERT_EQ(read, 1);
  17.808 -    EXPECT_EQ(memcmp(&target, "at\0", 3), 0);
  17.809 -    EXPECT_EQ(buf.pos, 8);
  17.810 -}
  17.811 -
  17.812 -TEST_F(BufferRead, ReadEof) {
  17.813 -    buf.pos = 9;
  17.814 -    char target[4];
  17.815 -    auto read = cxBufferRead(&target, 1, 1, &buf);
  17.816 -    ASSERT_EQ(read, 0);
  17.817 -    EXPECT_EQ(buf.pos, 9);
  17.818 -}
    18.1 --- a/test/test_compare.cpp	Wed Feb 08 20:26:09 2023 +0100
    18.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.3 @@ -1,127 +0,0 @@
    18.4 -/*
    18.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    18.6 - *
    18.7 - * Copyright 2022 Mike Becker, Olaf Wintermann All rights reserved.
    18.8 - *
    18.9 - * Redistribution and use in source and binary forms, with or without
   18.10 - * modification, are permitted provided that the following conditions are met:
   18.11 - *
   18.12 - *   1. Redistributions of source code must retain the above copyright
   18.13 - *      notice, this list of conditions and the following disclaimer.
   18.14 - *
   18.15 - *   2. Redistributions in binary form must reproduce the above copyright
   18.16 - *      notice, this list of conditions and the following disclaimer in the
   18.17 - *      documentation and/or other materials provided with the distribution.
   18.18 - *
   18.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   18.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   18.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   18.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   18.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   18.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   18.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   18.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   18.29 - * POSSIBILITY OF SUCH DAMAGE.
   18.30 - */
   18.31 -
   18.32 -#include "cx/compare.h"
   18.33 -
   18.34 -#include <gtest/gtest.h>
   18.35 -
   18.36 -template<typename T>
   18.37 -static void test_compare(
   18.38 -        int (*fnc)(
   18.39 -                void const *,
   18.40 -                void const *
   18.41 -        )
   18.42 -) {
   18.43 -    auto m = std::numeric_limits<T>::max() / 400;
   18.44 -    T x, y;
   18.45 -
   18.46 -    x = (std::is_signed_v<T> ? -3 : 3) * m;
   18.47 -    y = 5 * m;
   18.48 -    EXPECT_LT(fnc(&x, &y), 0);
   18.49 -    EXPECT_GT(fnc(&y, &x), 0);
   18.50 -
   18.51 -    x = 120 * m;
   18.52 -    y = 348 * m;
   18.53 -    EXPECT_LT(fnc(&x, &y), 0);
   18.54 -    EXPECT_GT(fnc(&y, &x), 0);
   18.55 -
   18.56 -    if constexpr (std::is_signed_v<T>) {
   18.57 -        x = -120 * m;
   18.58 -        y = -348 * m;
   18.59 -        EXPECT_GT(fnc(&x, &y), 0);
   18.60 -        EXPECT_LT(fnc(&y, &x), 0);
   18.61 -    }
   18.62 -
   18.63 -    x = y;
   18.64 -    EXPECT_EQ(fnc(&x, &y), 0);
   18.65 -    EXPECT_EQ(fnc(&y, &x), 0);
   18.66 -}
   18.67 -
   18.68 -TEST(Compare, Int) {
   18.69 -    test_compare<int>(cx_cmp_int);
   18.70 -}
   18.71 -
   18.72 -TEST(Compare, Longint) {
   18.73 -    test_compare<long int>(cx_cmp_longint);
   18.74 -}
   18.75 -
   18.76 -TEST(Compare, Longlong) {
   18.77 -    test_compare<long long>(cx_cmp_longlong);
   18.78 -}
   18.79 -
   18.80 -TEST(Compare, Int16) {
   18.81 -    test_compare<int16_t>(cx_cmp_int16);
   18.82 -}
   18.83 -
   18.84 -TEST(Compare, Int32) {
   18.85 -    test_compare<int32_t>(cx_cmp_int32);
   18.86 -}
   18.87 -
   18.88 -TEST(Compare, Int64) {
   18.89 -    test_compare<int64_t>(cx_cmp_int64);
   18.90 -}
   18.91 -
   18.92 -TEST(Compare, Uint) {
   18.93 -    test_compare<uint>(cx_cmp_uint);
   18.94 -}
   18.95 -
   18.96 -TEST(Compare, Ulongint) {
   18.97 -    test_compare<unsigned long int>(cx_cmp_ulongint);
   18.98 -}
   18.99 -
  18.100 -TEST(Compare, Ulonglong) {
  18.101 -    test_compare<unsigned long long>(cx_cmp_ulonglong);
  18.102 -}
  18.103 -
  18.104 -TEST(Compare, Uint16) {
  18.105 -    test_compare<uint16_t>(cx_cmp_uint16);
  18.106 -}
  18.107 -
  18.108 -TEST(Compare, Uint32) {
  18.109 -    test_compare<uint32_t>(cx_cmp_uint32);
  18.110 -}
  18.111 -
  18.112 -TEST(Compare, Uint64) {
  18.113 -    test_compare<uint64_t>(cx_cmp_uint64);
  18.114 -}
  18.115 -
  18.116 -TEST(Compare, Float) {
  18.117 -    test_compare<float>(cx_cmp_float);
  18.118 -}
  18.119 -
  18.120 -TEST(Compare, Double) {
  18.121 -    test_compare<double>(cx_cmp_double);
  18.122 -}
  18.123 -
  18.124 -TEST(Compare, IntPtr) {
  18.125 -    test_compare<intptr_t>(cx_cmp_intptr);
  18.126 -}
  18.127 -
  18.128 -TEST(Compare, UintPtr) {
  18.129 -    test_compare<uintptr_t>(cx_cmp_uintptr);
  18.130 -}
    19.1 --- a/test/test_hash_key.cpp	Wed Feb 08 20:26:09 2023 +0100
    19.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.3 @@ -1,87 +0,0 @@
    19.4 -/*
    19.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    19.6 - *
    19.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    19.8 - *
    19.9 - * Redistribution and use in source and binary forms, with or without
   19.10 - * modification, are permitted provided that the following conditions are met:
   19.11 - *
   19.12 - *   1. Redistributions of source code must retain the above copyright
   19.13 - *      notice, this list of conditions and the following disclaimer.
   19.14 - *
   19.15 - *   2. Redistributions in binary form must reproduce the above copyright
   19.16 - *      notice, this list of conditions and the following disclaimer in the
   19.17 - *      documentation and/or other materials provided with the distribution.
   19.18 - *
   19.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   19.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   19.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   19.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   19.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   19.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   19.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   19.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   19.29 - * POSSIBILITY OF SUCH DAMAGE.
   19.30 - */
   19.31 -
   19.32 -#include "cx/hash_key.h"
   19.33 -
   19.34 -#include <gtest/gtest.h>
   19.35 -
   19.36 -TEST(cx_hash_key, functions) {
   19.37 -    auto str = "my key";
   19.38 -    auto len = strlen(str);
   19.39 -
   19.40 -    auto str_key = cx_hash_key_str(str);
   19.41 -    auto bytes_key = cx_hash_key_bytes(
   19.42 -            reinterpret_cast<unsigned char const *>(str), len);
   19.43 -    auto obj_key = cx_hash_key(
   19.44 -            reinterpret_cast<void const *>(str), len);
   19.45 -
   19.46 -    EXPECT_EQ(str_key.hash, bytes_key.hash);
   19.47 -    EXPECT_EQ(obj_key.hash, bytes_key.hash);
   19.48 -    EXPECT_EQ(str_key.len, len);
   19.49 -    EXPECT_EQ(bytes_key.len, len);
   19.50 -    EXPECT_EQ(bytes_key.len, len);
   19.51 -    EXPECT_EQ(str_key.data.cstr, str);
   19.52 -    EXPECT_EQ(bytes_key.data.cbytes, reinterpret_cast<unsigned char const *>(str));
   19.53 -    EXPECT_EQ(bytes_key.data.cobj, reinterpret_cast<void const *>(str));
   19.54 -}
   19.55 -
   19.56 -TEST(cx_hash_key, empty_string) {
   19.57 -    auto str = "";
   19.58 -
   19.59 -    auto str_key = cx_hash_key_str(str);
   19.60 -    auto bytes_key = cx_hash_key_bytes(
   19.61 -            reinterpret_cast<unsigned char const *>(str), 0);
   19.62 -    auto obj_key = cx_hash_key(
   19.63 -            reinterpret_cast<void const *>(str), 0);
   19.64 -
   19.65 -    EXPECT_EQ(bytes_key.hash, 4152238450u);
   19.66 -    EXPECT_EQ(str_key.hash, 4152238450u);
   19.67 -    EXPECT_EQ(obj_key.hash, 4152238450u);
   19.68 -    EXPECT_EQ(str_key.len, 0);
   19.69 -    EXPECT_EQ(bytes_key.len, 0);
   19.70 -    EXPECT_EQ(bytes_key.len, 0);
   19.71 -    EXPECT_EQ(str_key.data.cstr, str);
   19.72 -    EXPECT_EQ(bytes_key.data.cbytes, reinterpret_cast<unsigned char const *>(str));
   19.73 -    EXPECT_EQ(bytes_key.data.cobj, reinterpret_cast<void const *>(str));
   19.74 -}
   19.75 -
   19.76 -TEST(cx_hash_key, null_ptr) {
   19.77 -    auto str_key = cx_hash_key_str(nullptr);
   19.78 -    auto bytes_key = cx_hash_key_bytes(nullptr, 0);
   19.79 -    auto obj_key = cx_hash_key(nullptr, 0);
   19.80 -
   19.81 -    EXPECT_EQ(bytes_key.hash, 1574210520u);
   19.82 -    EXPECT_EQ(str_key.hash, 1574210520u);
   19.83 -    EXPECT_EQ(obj_key.hash, 1574210520u);
   19.84 -    EXPECT_EQ(str_key.len, 0);
   19.85 -    EXPECT_EQ(bytes_key.len, 0);
   19.86 -    EXPECT_EQ(bytes_key.len, 0);
   19.87 -    EXPECT_EQ(str_key.data.cstr, nullptr);
   19.88 -    EXPECT_EQ(bytes_key.data.cbytes, nullptr);
   19.89 -    EXPECT_EQ(bytes_key.data.cobj, nullptr);
   19.90 -}
    20.1 --- a/test/test_list.cpp	Wed Feb 08 20:26:09 2023 +0100
    20.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.3 @@ -1,1159 +0,0 @@
    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 "cx/linked_list.h"
   20.33 -#include "cx/array_list.h"
   20.34 -#include "cx/utils.h"
   20.35 -#include "cx/compare.h"
   20.36 -#include "util_allocator.h"
   20.37 -
   20.38 -#include <gtest/gtest.h>
   20.39 -#include <array>
   20.40 -#include <vector>
   20.41 -#include <unordered_set>
   20.42 -#include <algorithm>
   20.43 -
   20.44 -struct node {
   20.45 -    node *next = nullptr;
   20.46 -    node *prev = nullptr;
   20.47 -    int data = 0;
   20.48 -};
   20.49 -
   20.50 -const ptrdiff_t loc_prev = offsetof(struct node, prev);
   20.51 -const ptrdiff_t loc_next = offsetof(struct node, next);
   20.52 -const ptrdiff_t loc_data = offsetof(struct node, data);
   20.53 -
   20.54 -struct node_test_data {
   20.55 -    node *begin = nullptr;
   20.56 -
   20.57 -    explicit node_test_data(node *begin) : begin(begin) {
   20.58 -        auto n = begin;
   20.59 -        while (n != nullptr) {
   20.60 -            nodes.push_back(n);
   20.61 -            n = n->next;
   20.62 -        }
   20.63 -    }
   20.64 -
   20.65 -    node_test_data(node_test_data &) = delete;
   20.66 -
   20.67 -    node_test_data(node_test_data &&) = default;
   20.68 -
   20.69 -    ~node_test_data() {
   20.70 -        for (auto &&n: nodes) delete n;
   20.71 -    }
   20.72 -
   20.73 -private:
   20.74 -    std::vector<node *> nodes;
   20.75 -};
   20.76 -
   20.77 -static node_test_data create_nodes_test_data(size_t len) {
   20.78 -    if (len == 0) return node_test_data{nullptr};
   20.79 -    auto begin = new node;
   20.80 -    auto prev = begin;
   20.81 -    for (size_t i = 1; i < len; i++) {
   20.82 -        auto n = new node;
   20.83 -        cx_linked_list_link(prev, n, loc_prev, loc_next);
   20.84 -        prev = n;
   20.85 -    }
   20.86 -    return node_test_data{begin};
   20.87 -}
   20.88 -
   20.89 -template<typename InputIter>
   20.90 -static node_test_data create_nodes_test_data(
   20.91 -        InputIter begin,
   20.92 -        InputIter end
   20.93 -) {
   20.94 -    if (begin == end) return node_test_data{nullptr};
   20.95 -    node *first = new node;
   20.96 -    first->data = *begin;
   20.97 -    node *prev = first;
   20.98 -    begin++;
   20.99 -    for (; begin != end; begin++) {
  20.100 -        auto n = new node;
  20.101 -        n->data = *begin;
  20.102 -        cx_linked_list_link(prev, n, loc_prev, loc_next);
  20.103 -        prev = n;
  20.104 -    }
  20.105 -    return node_test_data{first};
  20.106 -}
  20.107 -
  20.108 -static node_test_data create_nodes_test_data(std::initializer_list<int> data) {
  20.109 -    return create_nodes_test_data(data.begin(), data.end());
  20.110 -}
  20.111 -
  20.112 -template<size_t N>
  20.113 -struct int_test_data {
  20.114 -    std::array<int, N> data;
  20.115 -
  20.116 -    int_test_data() {
  20.117 -        cx_for_n (i, N) data[i] = ::rand(); // NOLINT(cert-msc50-cpp)
  20.118 -    }
  20.119 -};
  20.120 -
  20.121 -TEST(LinkedList_LowLevel, link_unlink) {
  20.122 -    node a, b, c;
  20.123 -
  20.124 -    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  20.125 -    EXPECT_EQ(a.prev, nullptr);
  20.126 -    EXPECT_EQ(a.next, &b);
  20.127 -    EXPECT_EQ(b.prev, &a);
  20.128 -    EXPECT_EQ(b.next, nullptr);
  20.129 -
  20.130 -    cx_linked_list_unlink(&a, &b, loc_prev, loc_next);
  20.131 -    EXPECT_EQ(a.prev, nullptr);
  20.132 -    EXPECT_EQ(a.next, nullptr);
  20.133 -    EXPECT_EQ(b.prev, nullptr);
  20.134 -    EXPECT_EQ(b.next, nullptr);
  20.135 -
  20.136 -    cx_linked_list_link(&b, &c, loc_prev, loc_next);
  20.137 -    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  20.138 -    cx_linked_list_unlink(&b, &c, loc_prev, loc_next);
  20.139 -    EXPECT_EQ(a.prev, nullptr);
  20.140 -    EXPECT_EQ(a.next, &b);
  20.141 -    EXPECT_EQ(b.prev, &a);
  20.142 -    EXPECT_EQ(b.next, nullptr);
  20.143 -    EXPECT_EQ(c.prev, nullptr);
  20.144 -    EXPECT_EQ(c.next, nullptr);
  20.145 -}
  20.146 -
  20.147 -TEST(LinkedList_LowLevel, cx_linked_list_at) {
  20.148 -    node a, b, c, d;
  20.149 -    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  20.150 -    cx_linked_list_link(&b, &c, loc_prev, loc_next);
  20.151 -    cx_linked_list_link(&c, &d, loc_prev, loc_next);
  20.152 -
  20.153 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 0), &a);
  20.154 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 1), &b);
  20.155 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 2), &c);
  20.156 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 3), &d);
  20.157 -    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 4), nullptr);
  20.158 -
  20.159 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_prev, 0), &a);
  20.160 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 1), &b);
  20.161 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 2), &c);
  20.162 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 3), &d);
  20.163 -    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 4), nullptr);
  20.164 -
  20.165 -    EXPECT_EQ(cx_linked_list_at(&d, 3, loc_prev, 0), &a);
  20.166 -    EXPECT_EQ(cx_linked_list_at(&d, 3, loc_prev, 1), &b);
  20.167 -}
  20.168 -
  20.169 -TEST(LinkedList_LowLevel, cx_linked_list_find) {
  20.170 -    auto testdata = create_nodes_test_data({2, 4, 6, 8});
  20.171 -    auto list = testdata.begin;
  20.172 -    int s;
  20.173 -
  20.174 -    s = 2;
  20.175 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 0);
  20.176 -    s = 4;
  20.177 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 1);
  20.178 -    s = 6;
  20.179 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 2);
  20.180 -    s = 8;
  20.181 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 3);
  20.182 -    s = 10;
  20.183 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 4);
  20.184 -    s = -2;
  20.185 -    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 4);
  20.186 -}
  20.187 -
  20.188 -TEST(LinkedList_LowLevel, cx_linked_list_compare) {
  20.189 -    auto ta = create_nodes_test_data({2, 4, 6, 8});
  20.190 -    auto tb = create_nodes_test_data({2, 4, 6});
  20.191 -    auto tc = create_nodes_test_data({2, 4, 6, 9});
  20.192 -    auto la = ta.begin, lb = tb.begin, lc = tc.begin;
  20.193 -
  20.194 -    EXPECT_GT(cx_linked_list_compare(la, lb, loc_next, loc_data, cx_cmp_int), 0);
  20.195 -    EXPECT_LT(cx_linked_list_compare(lb, la, loc_next, loc_data, cx_cmp_int), 0);
  20.196 -    EXPECT_GT(cx_linked_list_compare(lc, la, loc_next, loc_data, cx_cmp_int), 0);
  20.197 -    EXPECT_LT(cx_linked_list_compare(la, lc, loc_next, loc_data, cx_cmp_int), 0);
  20.198 -    EXPECT_EQ(cx_linked_list_compare(la, la, loc_next, loc_data, cx_cmp_int), 0);
  20.199 -}
  20.200 -
  20.201 -TEST(LinkedList_LowLevel, cx_linked_list_add) {
  20.202 -    // test with begin, end / prev, next
  20.203 -    {
  20.204 -        node nodes[4];
  20.205 -        void *begin = nullptr, *end = nullptr;
  20.206 -
  20.207 -        cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[0]);
  20.208 -        EXPECT_EQ(begin, &nodes[0]);
  20.209 -        EXPECT_EQ(end, &nodes[0]);
  20.210 -        EXPECT_EQ(nodes[0].prev, nullptr);
  20.211 -        EXPECT_EQ(nodes[0].next, nullptr);
  20.212 -
  20.213 -        cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[1]);
  20.214 -        EXPECT_EQ(begin, &nodes[0]);
  20.215 -        EXPECT_EQ(end, &nodes[1]);
  20.216 -        EXPECT_EQ(nodes[0].next, &nodes[1]);
  20.217 -        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  20.218 -    }
  20.219 -
  20.220 -    // test with begin only / prev, next
  20.221 -    {
  20.222 -        node nodes[4];
  20.223 -        void *begin = nullptr;
  20.224 -
  20.225 -        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[0]);
  20.226 -        EXPECT_EQ(begin, &nodes[0]);
  20.227 -        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[1]);
  20.228 -        EXPECT_EQ(begin, &nodes[0]);
  20.229 -        EXPECT_EQ(nodes[0].next, &nodes[1]);
  20.230 -        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  20.231 -
  20.232 -        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[2]);
  20.233 -        EXPECT_EQ(nodes[1].next, &nodes[2]);
  20.234 -        EXPECT_EQ(nodes[2].prev, &nodes[1]);
  20.235 -    }
  20.236 -
  20.237 -    // test with end only / prev, next
  20.238 -    {
  20.239 -        node nodes[4];
  20.240 -        void *end = nullptr;
  20.241 -
  20.242 -        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[0]);
  20.243 -        EXPECT_EQ(end, &nodes[0]);
  20.244 -        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[1]);
  20.245 -        EXPECT_EQ(end, &nodes[1]);
  20.246 -        EXPECT_EQ(nodes[0].next, &nodes[1]);
  20.247 -        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  20.248 -
  20.249 -        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[2]);
  20.250 -        EXPECT_EQ(end, &nodes[2]);
  20.251 -        EXPECT_EQ(nodes[1].next, &nodes[2]);
  20.252 -        EXPECT_EQ(nodes[2].prev, &nodes[1]);
  20.253 -    }
  20.254 -
  20.255 -    // test with begin, end / next
  20.256 -    {
  20.257 -        node nodes[4];
  20.258 -        void *begin = nullptr, *end = nullptr;
  20.259 -
  20.260 -        cx_linked_list_add(&begin, &end, -1, loc_next, &nodes[0]);
  20.261 -        EXPECT_EQ(begin, &nodes[0]);
  20.262 -        EXPECT_EQ(end, &nodes[0]);
  20.263 -        cx_linked_list_add(&begin, &end, -1, loc_next, &nodes[1]);
  20.264 -        EXPECT_EQ(end, &nodes[1]);
  20.265 -        EXPECT_EQ(nodes[0].next, &nodes[1]);
  20.266 -        EXPECT_EQ(nodes[1].prev, nullptr);
  20.267 -    }
  20.268 -}
  20.269 -
  20.270 -TEST(LinkedList_LowLevel, cx_linked_list_prepend) {
  20.271 -    // test with begin, end / prev, next
  20.272 -    {
  20.273 -        node nodes[4];
  20.274 -        void *begin = nullptr, *end = nullptr;
  20.275 -
  20.276 -        cx_linked_list_prepend(&begin, &end, loc_prev, loc_next, &nodes[0]);
  20.277 -        EXPECT_EQ(begin, &nodes[0]);
  20.278 -        EXPECT_EQ(end, &nodes[0]);
  20.279 -        EXPECT_EQ(nodes[0].prev, nullptr);
  20.280 -        EXPECT_EQ(nodes[0].next, nullptr);
  20.281 -
  20.282 -        cx_linked_list_prepend(&begin, &end, loc_prev, loc_next, &nodes[1]);
  20.283 -        EXPECT_EQ(begin, &nodes[1]);
  20.284 -        EXPECT_EQ(end, &nodes[0]);
  20.285 -        EXPECT_EQ(nodes[1].next, &nodes[0]);
  20.286 -        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  20.287 -    }
  20.288 -
  20.289 -    // test with begin only / prev, next
  20.290 -    {
  20.291 -        node nodes[4];
  20.292 -        void *begin = nullptr;
  20.293 -
  20.294 -        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[0]);
  20.295 -        EXPECT_EQ(begin, &nodes[0]);
  20.296 -        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[1]);
  20.297 -        EXPECT_EQ(begin, &nodes[1]);
  20.298 -        EXPECT_EQ(nodes[1].next, &nodes[0]);
  20.299 -        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  20.300 -
  20.301 -        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[2]);
  20.302 -        EXPECT_EQ(begin, &nodes[2]);
  20.303 -        EXPECT_EQ(nodes[2].next, &nodes[1]);
  20.304 -        EXPECT_EQ(nodes[1].prev, &nodes[2]);
  20.305 -    }
  20.306 -
  20.307 -    // test with end only / prev, next
  20.308 -    {
  20.309 -        node nodes[4];
  20.310 -        void *end = nullptr;
  20.311 -
  20.312 -        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[0]);
  20.313 -        EXPECT_EQ(end, &nodes[0]);
  20.314 -        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[1]);
  20.315 -        EXPECT_EQ(end, &nodes[0]);
  20.316 -        EXPECT_EQ(nodes[1].next, &nodes[0]);
  20.317 -        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  20.318 -
  20.319 -        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[2]);
  20.320 -        EXPECT_EQ(end, &nodes[0]);
  20.321 -        EXPECT_EQ(nodes[2].next, &nodes[1]);
  20.322 -        EXPECT_EQ(nodes[1].prev, &nodes[2]);
  20.323 -    }
  20.324 -
  20.325 -    // test with begin, end / next
  20.326 -    {
  20.327 -        node nodes[4];
  20.328 -        void *begin = nullptr, *end = nullptr;
  20.329 -
  20.330 -        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[0]);
  20.331 -        EXPECT_EQ(begin, &nodes[0]);
  20.332 -        EXPECT_EQ(end, &nodes[0]);
  20.333 -        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[1]);
  20.334 -        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[2]);
  20.335 -        EXPECT_EQ(begin, &nodes[2]);
  20.336 -        EXPECT_EQ(end, &nodes[0]);
  20.337 -        EXPECT_EQ(nodes[1].next, &nodes[0]);
  20.338 -        EXPECT_EQ(nodes[2].next, &nodes[1]);
  20.339 -        EXPECT_EQ(nodes[1].prev, nullptr);
  20.340 -        EXPECT_EQ(nodes[0].prev, nullptr);
  20.341 -    }
  20.342 -}
  20.343 -
  20.344 -TEST(LinkedList_LowLevel, cx_linked_list_insert) {
  20.345 -    // insert mid list
  20.346 -    {
  20.347 -        node nodes[4];
  20.348 -        void *begin = &nodes[0], *end = &nodes[2];
  20.349 -
  20.350 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  20.351 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  20.352 -
  20.353 -        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, &nodes[1], &nodes[3]);
  20.354 -        EXPECT_EQ(begin, &nodes[0]);
  20.355 -        EXPECT_EQ(end, &nodes[2]);
  20.356 -        EXPECT_EQ(nodes[1].next, &nodes[3]);
  20.357 -        EXPECT_EQ(nodes[2].prev, &nodes[3]);
  20.358 -        EXPECT_EQ(nodes[3].prev, &nodes[1]);
  20.359 -        EXPECT_EQ(nodes[3].next, &nodes[2]);
  20.360 -    }
  20.361 -
  20.362 -    // insert end
  20.363 -    {
  20.364 -        node nodes[4];
  20.365 -        void *begin = &nodes[0], *end = &nodes[2];
  20.366 -
  20.367 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  20.368 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  20.369 -
  20.370 -        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, &nodes[2], &nodes[3]);
  20.371 -        EXPECT_EQ(begin, &nodes[0]);
  20.372 -        EXPECT_EQ(end, &nodes[3]);
  20.373 -        EXPECT_EQ(nodes[2].next, &nodes[3]);
  20.374 -        EXPECT_EQ(nodes[3].prev, &nodes[2]);
  20.375 -        EXPECT_EQ(nodes[3].next, nullptr);
  20.376 -    }
  20.377 -
  20.378 -    // insert begin
  20.379 -    {
  20.380 -        node nodes[4];
  20.381 -        void *begin = &nodes[0], *end = &nodes[2];
  20.382 -
  20.383 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  20.384 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  20.385 -
  20.386 -        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, nullptr, &nodes[3]);
  20.387 -        EXPECT_EQ(begin, &nodes[3]);
  20.388 -        EXPECT_EQ(end, &nodes[2]);
  20.389 -        EXPECT_EQ(nodes[0].prev, &nodes[3]);
  20.390 -        EXPECT_EQ(nodes[3].prev, nullptr);
  20.391 -        EXPECT_EQ(nodes[3].next, &nodes[0]);
  20.392 -    }
  20.393 -}
  20.394 -
  20.395 -TEST(LinkedList_LowLevel, cx_linked_list_insert_chain) {
  20.396 -    // insert mid list
  20.397 -    {
  20.398 -        node nodes[5];
  20.399 -        void *begin = &nodes[0], *end = &nodes[2];
  20.400 -
  20.401 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  20.402 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  20.403 -        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  20.404 -
  20.405 -        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, &nodes[1], &nodes[3], nullptr);
  20.406 -        EXPECT_EQ(begin, &nodes[0]);
  20.407 -        EXPECT_EQ(end, &nodes[2]);
  20.408 -        EXPECT_EQ(nodes[1].next, &nodes[3]);
  20.409 -        EXPECT_EQ(nodes[2].prev, &nodes[4]);
  20.410 -        EXPECT_EQ(nodes[3].prev, &nodes[1]);
  20.411 -        EXPECT_EQ(nodes[4].next, &nodes[2]);
  20.412 -    }
  20.413 -
  20.414 -    // insert end
  20.415 -    {
  20.416 -        node nodes[5];
  20.417 -        void *begin = &nodes[0], *end = &nodes[2];
  20.418 -
  20.419 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  20.420 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  20.421 -        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  20.422 -
  20.423 -        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, &nodes[2], &nodes[3], nullptr);
  20.424 -        EXPECT_EQ(begin, &nodes[0]);
  20.425 -        EXPECT_EQ(end, &nodes[4]);
  20.426 -        EXPECT_EQ(nodes[2].next, &nodes[3]);
  20.427 -        EXPECT_EQ(nodes[3].prev, &nodes[2]);
  20.428 -        EXPECT_EQ(nodes[4].next, nullptr);
  20.429 -    }
  20.430 -
  20.431 -    // insert begin
  20.432 -    {
  20.433 -        node nodes[5];
  20.434 -        void *begin = &nodes[0], *end = &nodes[2];
  20.435 -
  20.436 -        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  20.437 -        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  20.438 -        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  20.439 -
  20.440 -        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, nullptr, &nodes[3], nullptr);
  20.441 -        EXPECT_EQ(begin, &nodes[3]);
  20.442 -        EXPECT_EQ(end, &nodes[2]);
  20.443 -        EXPECT_EQ(nodes[0].prev, &nodes[4]);
  20.444 -        EXPECT_EQ(nodes[3].prev, nullptr);
  20.445 -        EXPECT_EQ(nodes[4].next, &nodes[0]);
  20.446 -    }
  20.447 -}
  20.448 -
  20.449 -TEST(LinkedList_LowLevel, cx_linked_list_first) {
  20.450 -    auto testdata = create_nodes_test_data(3);
  20.451 -    auto begin = testdata.begin;
  20.452 -    EXPECT_EQ(cx_linked_list_first(begin, loc_prev), begin);
  20.453 -    EXPECT_EQ(cx_linked_list_first(begin->next, loc_prev), begin);
  20.454 -    EXPECT_EQ(cx_linked_list_first(begin->next->next, loc_prev), begin);
  20.455 -}
  20.456 -
  20.457 -TEST(LinkedList_LowLevel, cx_linked_list_last) {
  20.458 -    auto testdata = create_nodes_test_data(3);
  20.459 -    auto begin = testdata.begin;
  20.460 -    auto end = begin->next->next;
  20.461 -    EXPECT_EQ(cx_linked_list_last(begin, loc_next), end);
  20.462 -    EXPECT_EQ(cx_linked_list_last(begin->next, loc_next), end);
  20.463 -    EXPECT_EQ(cx_linked_list_last(begin->next->next, loc_next), end);
  20.464 -}
  20.465 -
  20.466 -TEST(LinkedList_LowLevel, cx_linked_list_prev) {
  20.467 -    auto testdata = create_nodes_test_data(3);
  20.468 -    auto begin = testdata.begin;
  20.469 -    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin), nullptr);
  20.470 -    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin->next), begin);
  20.471 -    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin->next->next), begin->next);
  20.472 -}
  20.473 -
  20.474 -TEST(LinkedList_LowLevel, cx_linked_list_remove) {
  20.475 -    auto testdata = create_nodes_test_data({2, 4, 6});
  20.476 -    auto begin = reinterpret_cast<void *>(testdata.begin);
  20.477 -    auto first = testdata.begin;
  20.478 -    auto second = first->next;
  20.479 -    auto third = second->next;
  20.480 -    auto end = reinterpret_cast<void *>(third);
  20.481 -
  20.482 -    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, second);
  20.483 -    EXPECT_EQ(begin, first);
  20.484 -    EXPECT_EQ(end, third);
  20.485 -    EXPECT_EQ(first->prev, nullptr);
  20.486 -    EXPECT_EQ(first->next, third);
  20.487 -    EXPECT_EQ(third->prev, first);
  20.488 -    EXPECT_EQ(third->next, nullptr);
  20.489 -
  20.490 -    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, third);
  20.491 -    EXPECT_EQ(begin, first);
  20.492 -    EXPECT_EQ(end, first);
  20.493 -    EXPECT_EQ(first->prev, nullptr);
  20.494 -    EXPECT_EQ(first->next, nullptr);
  20.495 -
  20.496 -    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, first);
  20.497 -    EXPECT_EQ(begin, nullptr);
  20.498 -    EXPECT_EQ(end, nullptr);
  20.499 -}
  20.500 -
  20.501 -TEST(LinkedList_LowLevel, cx_linked_list_size) {
  20.502 -    EXPECT_EQ(cx_linked_list_size(nullptr, loc_next), 0);
  20.503 -
  20.504 -    {
  20.505 -        auto testdata = create_nodes_test_data(5);
  20.506 -        EXPECT_EQ(cx_linked_list_size(testdata.begin, loc_next), 5);
  20.507 -    }
  20.508 -
  20.509 -    {
  20.510 -        auto testdata = create_nodes_test_data(13);
  20.511 -        EXPECT_EQ(cx_linked_list_size(testdata.begin, loc_next), 13);
  20.512 -    }
  20.513 -}
  20.514 -
  20.515 -TEST(LinkedList_LowLevel, cx_linked_list_sort) {
  20.516 -    int_test_data<1500> testdata;
  20.517 -    std::array<int, 1500> sorted{};
  20.518 -    std::partial_sort_copy(testdata.data.begin(), testdata.data.end(), sorted.begin(), sorted.end());
  20.519 -
  20.520 -    auto scrambled = create_nodes_test_data(testdata.data.begin(), testdata.data.end());
  20.521 -    void *begin = scrambled.begin;
  20.522 -    void *end = cx_linked_list_last(begin, loc_next);
  20.523 -
  20.524 -    cx_linked_list_sort(&begin, &end, loc_prev, loc_next, loc_data, cx_cmp_int);
  20.525 -
  20.526 -    node *check = reinterpret_cast<node *>(begin);
  20.527 -    node *check_last = nullptr;
  20.528 -    cx_for_n (i, sorted.size()) {
  20.529 -        EXPECT_EQ(check->data, sorted[i]);
  20.530 -        EXPECT_EQ(check->prev, check_last);
  20.531 -        if (i < sorted.size() - 1) {
  20.532 -            ASSERT_NE(check->next, nullptr);
  20.533 -        }
  20.534 -        check_last = check;
  20.535 -        check = check->next;
  20.536 -    }
  20.537 -    EXPECT_EQ(check, nullptr);
  20.538 -    EXPECT_EQ(end, check_last);
  20.539 -}
  20.540 -
  20.541 -TEST(LinkedList_LowLevel, cx_linked_list_reverse) {
  20.542 -    auto testdata = create_nodes_test_data({2, 4, 6, 8});
  20.543 -    auto expected = create_nodes_test_data({8, 6, 4, 2});
  20.544 -
  20.545 -    auto begin = reinterpret_cast<void *>(testdata.begin);
  20.546 -    auto end = cx_linked_list_last(begin, loc_next);
  20.547 -    auto orig_begin = begin, orig_end = end;
  20.548 -
  20.549 -    cx_linked_list_reverse(&begin, &end, loc_prev, loc_next);
  20.550 -    EXPECT_EQ(end, orig_begin);
  20.551 -    EXPECT_EQ(begin, orig_end);
  20.552 -    EXPECT_EQ(cx_linked_list_compare(begin, expected.begin, loc_next, loc_data, cx_cmp_int), 0);
  20.553 -}
  20.554 -
  20.555 -class HighLevelTest : public ::testing::Test {
  20.556 -    mutable std::unordered_set<CxList *> lists;
  20.557 -protected:
  20.558 -    CxTestingAllocator testingAllocator;
  20.559 -
  20.560 -    void TearDown() override {
  20.561 -        for (auto &&l: lists) cxListDestroy(l);
  20.562 -        EXPECT_TRUE(testingAllocator.verify());
  20.563 -    }
  20.564 -
  20.565 -    static constexpr size_t testdata_len = 250;
  20.566 -    int_test_data<testdata_len> testdata;
  20.567 -
  20.568 -    auto autofree(CxList *list) const -> CxList * {
  20.569 -        if (list != nullptr) lists.insert(list);
  20.570 -        return list;
  20.571 -    }
  20.572 -
  20.573 -    auto linkedListFromTestData() const -> CxList * {
  20.574 -        auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  20.575 -        cxListAddArray(list, testdata.data.data(), testdata_len);
  20.576 -        return list;
  20.577 -    }
  20.578 -
  20.579 -    auto pointerLinkedListFromTestData() const -> CxList * {
  20.580 -        auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  20.581 -        cxListStorePointers(list);
  20.582 -        // note: cannot use cxListAddArray() because we don't have a list of pointers
  20.583 -        cx_for_n(i, testdata_len) cxListAdd(list, &testdata.data[i]);
  20.584 -        return list;
  20.585 -    }
  20.586 -
  20.587 -    auto arrayListFromTestData() const -> CxList * {
  20.588 -        auto list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), testdata_len));
  20.589 -        cxListAddArray(list, testdata.data.data(), testdata_len);
  20.590 -        return list;
  20.591 -    }
  20.592 -
  20.593 -    void verifyCreate(CxList *list) const {
  20.594 -        EXPECT_EQ(list->content_destructor_type, CX_DESTRUCTOR_NONE);
  20.595 -        EXPECT_EQ(list->size, 0);
  20.596 -        EXPECT_EQ(list->allocator, &testingAllocator);
  20.597 -        EXPECT_EQ(list->cmpfunc, cx_cmp_int);
  20.598 -    }
  20.599 -
  20.600 -    void verifyAdd(
  20.601 -            CxList *list,
  20.602 -            bool as_pointer
  20.603 -    ) {
  20.604 -        auto len = testdata_len;
  20.605 -        cx_for_n (i, len) EXPECT_EQ(cxListAdd(list, &testdata.data[i]), 0);
  20.606 -        EXPECT_EQ(list->size, len);
  20.607 -        EXPECT_GE(list->capacity, list->size);
  20.608 -        cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  20.609 -        cx_for_n (i, len) ++testdata.data[i];
  20.610 -        if (as_pointer) {
  20.611 -            cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  20.612 -        } else {
  20.613 -            cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i] - 1);
  20.614 -        }
  20.615 -    }
  20.616 -
  20.617 -    static void verifyInsert(CxList *list) {
  20.618 -        int a = 5, b = 47, c = 13, d = 42;
  20.619 -
  20.620 -        EXPECT_NE(cxListInsert(list, 1, &a), 0);
  20.621 -        EXPECT_EQ(list->size, 0);
  20.622 -        EXPECT_EQ(cxListInsert(list, 0, &a), 0);
  20.623 -        EXPECT_EQ(list->size, 1);
  20.624 -        EXPECT_EQ(cxListInsert(list, 0, &b), 0);
  20.625 -        EXPECT_EQ(list->size, 2);
  20.626 -        EXPECT_EQ(cxListInsert(list, 1, &c), 0);
  20.627 -        EXPECT_EQ(list->size, 3);
  20.628 -        EXPECT_EQ(cxListInsert(list, 3, &d), 0);
  20.629 -
  20.630 -        ASSERT_EQ(list->size, 4);
  20.631 -        EXPECT_GE(list->capacity, list->size);
  20.632 -
  20.633 -        EXPECT_EQ(*(int *) cxListAt(list, 0), 47);
  20.634 -        EXPECT_EQ(*(int *) cxListAt(list, 1), 13);
  20.635 -        EXPECT_EQ(*(int *) cxListAt(list, 2), 5);
  20.636 -        EXPECT_EQ(*(int *) cxListAt(list, 3), 42);
  20.637 -    }
  20.638 -
  20.639 -    static void verifyInsertArray(
  20.640 -            CxList *list,
  20.641 -            bool pointers = false
  20.642 -    ) {
  20.643 -        int a[5] = {5, 47, 11, 13, 42};
  20.644 -        int b[5] = {9, 18, 72, 50, 7};
  20.645 -        int *aptr[5];
  20.646 -        int *bptr[5];
  20.647 -        cx_for_n(i, 5) {
  20.648 -            aptr[i] = &a[i];
  20.649 -            bptr[i] = &b[i];
  20.650 -        }
  20.651 -
  20.652 -        size_t inserted;
  20.653 -
  20.654 -        if (pointers) {
  20.655 -            inserted = cxListInsertArray(list, 0, aptr, 5);
  20.656 -        } else {
  20.657 -            inserted = cxListInsertArray(list, 0, a, 5);
  20.658 -        }
  20.659 -        EXPECT_EQ(inserted, 5);
  20.660 -        EXPECT_EQ(*(int *) cxListAt(list, 0), 5);
  20.661 -        EXPECT_EQ(*(int *) cxListAt(list, 1), 47);
  20.662 -        EXPECT_EQ(*(int *) cxListAt(list, 2), 11);
  20.663 -        EXPECT_EQ(*(int *) cxListAt(list, 3), 13);
  20.664 -        EXPECT_EQ(*(int *) cxListAt(list, 4), 42);
  20.665 -        if (pointers) {
  20.666 -            inserted = cxListInsertArray(list, 3, bptr, 5);
  20.667 -        } else {
  20.668 -            inserted = cxListInsertArray(list, 3, b, 5);
  20.669 -        }
  20.670 -        EXPECT_EQ(inserted, 5);
  20.671 -        EXPECT_EQ(*(int *) cxListAt(list, 0), 5);
  20.672 -        EXPECT_EQ(*(int *) cxListAt(list, 1), 47);
  20.673 -        EXPECT_EQ(*(int *) cxListAt(list, 2), 11);
  20.674 -        EXPECT_EQ(*(int *) cxListAt(list, 3), 9);
  20.675 -        EXPECT_EQ(*(int *) cxListAt(list, 4), 18);
  20.676 -        EXPECT_EQ(*(int *) cxListAt(list, 5), 72);
  20.677 -        EXPECT_EQ(*(int *) cxListAt(list, 6), 50);
  20.678 -        EXPECT_EQ(*(int *) cxListAt(list, 7), 7);
  20.679 -        EXPECT_EQ(*(int *) cxListAt(list, 8), 13);
  20.680 -        EXPECT_EQ(*(int *) cxListAt(list, 9), 42);
  20.681 -    }
  20.682 -
  20.683 -    void verifyRemove(CxList *list) const {
  20.684 -        EXPECT_EQ(cxListRemove(list, 2), 0);
  20.685 -        EXPECT_EQ(cxListRemove(list, 4), 0);
  20.686 -        EXPECT_EQ(list->size, testdata_len - 2);
  20.687 -        EXPECT_GE(list->capacity, list->size);
  20.688 -        EXPECT_EQ(*(int *) cxListAt(list, 0), testdata.data[0]);
  20.689 -        EXPECT_EQ(*(int *) cxListAt(list, 1), testdata.data[1]);
  20.690 -        EXPECT_EQ(*(int *) cxListAt(list, 2), testdata.data[3]);
  20.691 -        EXPECT_EQ(*(int *) cxListAt(list, 3), testdata.data[4]);
  20.692 -        EXPECT_EQ(*(int *) cxListAt(list, 4), testdata.data[6]);
  20.693 -
  20.694 -        EXPECT_EQ(cxListRemove(list, 0), 0);
  20.695 -        EXPECT_EQ(list->size, testdata_len - 3);
  20.696 -        EXPECT_GE(list->capacity, list->size);
  20.697 -        EXPECT_EQ(*(int *) cxListAt(list, 0), testdata.data[1]);
  20.698 -        EXPECT_EQ(*(int *) cxListAt(list, 1), testdata.data[3]);
  20.699 -
  20.700 -        EXPECT_NE(cxListRemove(list, testdata_len), 0);
  20.701 -    }
  20.702 -
  20.703 -    static void verifySwap(CxList *list) {
  20.704 -        ASSERT_EQ(list->size, 0);
  20.705 -
  20.706 -        int original[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
  20.707 -        int swapped[16] = {8, 4, 14, 3, 1, 5, 9, 12, 0, 6, 11, 10, 7, 15, 2, 13};
  20.708 -
  20.709 -        // we have to add the items one by one, because it could be a pointer list
  20.710 -        cx_for_n(i, 16) {
  20.711 -            cxListAdd(list, &original[i]);
  20.712 -        }
  20.713 -
  20.714 -        int result;
  20.715 -
  20.716 -        // execute the test two times with different item sizes
  20.717 -        result = cxListSwap(list, 1, 4);
  20.718 -        EXPECT_EQ(0, result);
  20.719 -        result = cxListSwap(list, 2, 14);
  20.720 -        EXPECT_EQ(0, result);
  20.721 -        result = cxListSwap(list, 9, 6);
  20.722 -        EXPECT_EQ(0, result);
  20.723 -        result = cxListSwap(list, 3, 3);
  20.724 -        EXPECT_EQ(0, result);
  20.725 -        result = cxListSwap(list, 10, 11);
  20.726 -        EXPECT_EQ(0, result);
  20.727 -        result = cxListSwap(list, 8, 0);
  20.728 -        EXPECT_EQ(0, result);
  20.729 -        result = cxListSwap(list, 7, 12);
  20.730 -        EXPECT_EQ(0, result);
  20.731 -        result = cxListSwap(list, 13, 15);
  20.732 -        EXPECT_EQ(0, result);
  20.733 -
  20.734 -        result = cxListSwap(list, 5, 16);
  20.735 -        EXPECT_NE(0, result);
  20.736 -        result = cxListSwap(list, 16, 6);
  20.737 -        EXPECT_NE(0, result);
  20.738 -        result = cxListSwap(list, 16, 17);
  20.739 -        EXPECT_NE(0, result);
  20.740 -
  20.741 -        auto iter = cxListBegin(list);
  20.742 -        cx_foreach(int*, e, iter) {
  20.743 -            EXPECT_EQ(*e, swapped[iter.index]);
  20.744 -        }
  20.745 -        // TODO: replace with backward iterator
  20.746 -        cx_for_n(i, 16) {
  20.747 -            EXPECT_EQ(*((int *) cxListAt(list, i)), swapped[i]);
  20.748 -        }
  20.749 -    }
  20.750 -
  20.751 -    void verifyAt(CxList *list) const {
  20.752 -        auto len = testdata_len;
  20.753 -        EXPECT_EQ(list->size, len);
  20.754 -        cx_for_n (i, len) {
  20.755 -            EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  20.756 -        }
  20.757 -        EXPECT_EQ(cxListAt(list, list->size), nullptr);
  20.758 -    }
  20.759 -
  20.760 -    void verifyFind(CxList *list) const {
  20.761 -        cx_for_n (attempt, 25) {
  20.762 -            size_t exp = rand() % testdata_len; // NOLINT(cert-msc50-cpp)
  20.763 -            int val = testdata.data[exp];
  20.764 -            // randomly picked number could occur earlier in list - find first position
  20.765 -            cx_for_n (i, exp) {
  20.766 -                if (testdata.data[i] == val) {
  20.767 -                    exp = i;
  20.768 -                    break;
  20.769 -                }
  20.770 -            }
  20.771 -            EXPECT_EQ(cxListFind(list, &val), exp);
  20.772 -        }
  20.773 -    }
  20.774 -
  20.775 -    void verifySort(CxList *list) const {
  20.776 -        std::array<int, testdata_len> expected{};
  20.777 -        std::partial_sort_copy(testdata.data.begin(), testdata.data.end(), expected.begin(), expected.end());
  20.778 -        cxListSort(list);
  20.779 -        cx_for_n (i, testdata_len) ASSERT_EQ(*(int *) cxListAt(list, i), expected[i]);
  20.780 -    }
  20.781 -
  20.782 -    void verifyIterator(CxList *list) const {
  20.783 -        int i = 0;
  20.784 -        auto iter = cxListBeginMut(list);
  20.785 -        cx_foreach(int*, x, iter) {
  20.786 -            ASSERT_EQ(iter.index, (size_t) (i + 1) / 2);
  20.787 -            ASSERT_EQ(*x, testdata.data[i]);
  20.788 -            if (i % 2 == 1) cxIteratorFlagRemoval(iter);
  20.789 -            i++;
  20.790 -        }
  20.791 -        auto len = testdata_len;
  20.792 -        EXPECT_EQ(i, len);
  20.793 -        ASSERT_EQ(list->size, len / 2);
  20.794 -        cx_for_n(j, len / 2) ASSERT_EQ(*(int *) cxListAt(list, j), testdata.data[j * 2]);
  20.795 -    }
  20.796 -
  20.797 -    static void verifyInsertViaIterator(CxList *list) {
  20.798 -        int newdata[] = {10, 20, 30, 40, 50};
  20.799 -
  20.800 -        auto iter = cxListMutIterator(list, 2);
  20.801 -        EXPECT_TRUE(cxIteratorValid(iter));
  20.802 -        EXPECT_EQ(iter.index, 2);
  20.803 -        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  20.804 -        cxListInsertAfter(&iter, &newdata[0]);
  20.805 -        EXPECT_TRUE(cxIteratorValid(iter));
  20.806 -        EXPECT_EQ(iter.index, 2);
  20.807 -        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  20.808 -        cxListInsertBefore(&iter, &newdata[1]);
  20.809 -        EXPECT_TRUE(cxIteratorValid(iter));
  20.810 -        EXPECT_EQ(iter.index, 3);
  20.811 -        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  20.812 -
  20.813 -        iter = cxListBeginMut(list);
  20.814 -        cxListInsertBefore(&iter, &newdata[2]);
  20.815 -        EXPECT_TRUE(cxIteratorValid(iter));
  20.816 -        EXPECT_EQ(iter.index, 1);
  20.817 -        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 0);
  20.818 -        iter = cxListMutIterator(list, list->size);
  20.819 -        cxListInsertBefore(&iter, &newdata[3]);
  20.820 -        EXPECT_FALSE(cxIteratorValid(iter));
  20.821 -        EXPECT_EQ(iter.index, 9);
  20.822 -        iter = cxListMutIterator(list, list->size);
  20.823 -        cxListInsertAfter(&iter, &newdata[4]);
  20.824 -        EXPECT_FALSE(cxIteratorValid(iter));
  20.825 -        EXPECT_EQ(iter.index, 10);
  20.826 -
  20.827 -        int expdata[] = {30, 0, 1, 20, 2, 10, 3, 4, 40, 50};
  20.828 -        cx_for_n (j, 10) EXPECT_EQ(*(int *) cxListAt(list, j), expdata[j]);
  20.829 -    }
  20.830 -
  20.831 -    void verifyReverse(CxList *list) const {
  20.832 -        cxListReverse(list);
  20.833 -        cx_for_n(i, testdata_len) {
  20.834 -            ASSERT_EQ(*(int *) cxListAt(list, i), testdata.data[testdata_len - 1 - i]);
  20.835 -        }
  20.836 -    }
  20.837 -
  20.838 -    static void verifyCompare(
  20.839 -            CxList *left,
  20.840 -            CxList *right
  20.841 -    ) {
  20.842 -        EXPECT_EQ(cxListCompare(left, right), 0);
  20.843 -        int x = 42;
  20.844 -        cxListAdd(left, &x);
  20.845 -        ASSERT_GT(left->size, right->size);
  20.846 -        EXPECT_GT(cxListCompare(left, right), 0);
  20.847 -        EXPECT_LT(cxListCompare(right, left), 0);
  20.848 -        cxListAdd(right, &x);
  20.849 -        ASSERT_EQ(left->size, right->size);
  20.850 -        EXPECT_EQ(cxListCompare(left, right), 0);
  20.851 -        int a = 5, b = 10;
  20.852 -        cxListInsert(left, 15, &a);
  20.853 -        cxListInsert(right, 15, &b);
  20.854 -        ASSERT_EQ(left->size, right->size);
  20.855 -        EXPECT_LT(cxListCompare(left, right), 0);
  20.856 -        EXPECT_GT(cxListCompare(right, left), 0);
  20.857 -        *(int *) cxListAt(left, 15) = 10;
  20.858 -        EXPECT_EQ(cxListCompare(left, right), 0);
  20.859 -    }
  20.860 -};
  20.861 -
  20.862 -class LinkedList : public HighLevelTest {
  20.863 -};
  20.864 -
  20.865 -class PointerLinkedList : public HighLevelTest {
  20.866 -};
  20.867 -
  20.868 -class ArrayList : public HighLevelTest {
  20.869 -};
  20.870 -
  20.871 -TEST_F(PointerLinkedList, cxListStorePointers) {
  20.872 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, 47));
  20.873 -    EXPECT_FALSE(cxListIsStoringPointers(list));
  20.874 -    cxListStorePointers(list);
  20.875 -    EXPECT_EQ(list->itemsize, sizeof(void *));
  20.876 -    EXPECT_NE(list->cl, nullptr);
  20.877 -    EXPECT_NE(list->climpl, nullptr);
  20.878 -    EXPECT_TRUE(cxListIsStoringPointers(list));
  20.879 -    cxListStoreObjects(list);
  20.880 -    EXPECT_NE(list->cl, nullptr);
  20.881 -    EXPECT_EQ(list->climpl, nullptr);
  20.882 -    EXPECT_FALSE(cxListIsStoringPointers(list));
  20.883 -}
  20.884 -
  20.885 -TEST_F(LinkedList, cxLinkedListCreate) {
  20.886 -    CxList *list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  20.887 -    ASSERT_NE(list, nullptr);
  20.888 -    EXPECT_EQ(list->itemsize, sizeof(int));
  20.889 -    EXPECT_EQ(list->capacity, (size_t) -1);
  20.890 -    verifyCreate(list);
  20.891 -}
  20.892 -
  20.893 -TEST_F(ArrayList, cxArrayListCreate) {
  20.894 -    CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8));
  20.895 -    ASSERT_NE(list, nullptr);
  20.896 -    EXPECT_EQ(list->itemsize, sizeof(int));
  20.897 -    EXPECT_EQ(list->capacity, 8);
  20.898 -    verifyCreate(list);
  20.899 -}
  20.900 -
  20.901 -TEST_F(LinkedList, cxListAdd) {
  20.902 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  20.903 -    verifyAdd(list, false);
  20.904 -}
  20.905 -
  20.906 -TEST_F(PointerLinkedList, cxListAdd) {
  20.907 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  20.908 -    cxListStorePointers(list);
  20.909 -    verifyAdd(list, true);
  20.910 -}
  20.911 -
  20.912 -TEST_F(ArrayList, cxListAdd) {
  20.913 -    auto list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8));
  20.914 -    verifyAdd(list, false);
  20.915 -}
  20.916 -
  20.917 -TEST_F(LinkedList, cxListInsert) {
  20.918 -    verifyInsert(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  20.919 -}
  20.920 -
  20.921 -TEST_F(PointerLinkedList, cxListInsert) {
  20.922 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  20.923 -    cxListStorePointers(list);
  20.924 -    verifyInsert(list);
  20.925 -}
  20.926 -
  20.927 -TEST_F(ArrayList, cxListInsert) {
  20.928 -    verifyInsert(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 2)));
  20.929 -}
  20.930 -
  20.931 -TEST_F(LinkedList, cxListInsertArray) {
  20.932 -    verifyInsertArray(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  20.933 -}
  20.934 -
  20.935 -TEST_F(PointerLinkedList, cxListInsertArray) {
  20.936 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  20.937 -    cxListStorePointers(list);
  20.938 -    verifyInsertArray(list, true);
  20.939 -}
  20.940 -
  20.941 -TEST_F(ArrayList, cxListInsertArray) {
  20.942 -    verifyInsertArray(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 4)));
  20.943 -}
  20.944 -
  20.945 -TEST_F(LinkedList, cxListRemove) {
  20.946 -    verifyRemove(linkedListFromTestData());
  20.947 -}
  20.948 -
  20.949 -TEST_F(PointerLinkedList, cxListRemove) {
  20.950 -    verifyRemove(pointerLinkedListFromTestData());
  20.951 -}
  20.952 -
  20.953 -TEST_F(ArrayList, cxListRemove) {
  20.954 -    verifyRemove(arrayListFromTestData());
  20.955 -}
  20.956 -
  20.957 -TEST_F(LinkedList, cxListSwap) {
  20.958 -    verifySwap(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  20.959 -}
  20.960 -
  20.961 -TEST_F(PointerLinkedList, cxListSwap) {
  20.962 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  20.963 -    cxListStorePointers(list);
  20.964 -    verifySwap(list);
  20.965 -}
  20.966 -
  20.967 -TEST_F(ArrayList, cxListSwap) {
  20.968 -    verifySwap(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 16)));
  20.969 -}
  20.970 -
  20.971 -TEST_F(LinkedList, cxListSwapNoSBO) {
  20.972 -    CX_DISABLE_LINKED_LIST_SWAP_SBO = true;
  20.973 -    verifySwap(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  20.974 -    CX_DISABLE_LINKED_LIST_SWAP_SBO = false;
  20.975 -}
  20.976 -
  20.977 -TEST_F(PointerLinkedList, cxListSwapNoSBO) {
  20.978 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  20.979 -    cxListStorePointers(list);
  20.980 -    CX_DISABLE_LINKED_LIST_SWAP_SBO = true;
  20.981 -    verifySwap(list);
  20.982 -    CX_DISABLE_LINKED_LIST_SWAP_SBO = false;
  20.983 -}
  20.984 -
  20.985 -TEST_F(ArrayList, cxListSwapNoSBO) {
  20.986 -    CX_DISABLE_LINKED_LIST_SWAP_SBO = true;
  20.987 -    verifySwap(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 16)));
  20.988 -    CX_DISABLE_LINKED_LIST_SWAP_SBO = false;
  20.989 -}
  20.990 -
  20.991 -TEST_F(LinkedList, cxListAt) {
  20.992 -    verifyAt(linkedListFromTestData());
  20.993 -}
  20.994 -
  20.995 -TEST_F(PointerLinkedList, cxListAt) {
  20.996 -    verifyAt(pointerLinkedListFromTestData());
  20.997 -}
  20.998 -
  20.999 -TEST_F(ArrayList, cxListAt) {
 20.1000 -    verifyAt(arrayListFromTestData());
 20.1001 -}
 20.1002 -
 20.1003 -TEST_F(LinkedList, cxListFind) {
 20.1004 -    verifyFind(linkedListFromTestData());
 20.1005 -}
 20.1006 -
 20.1007 -TEST_F(PointerLinkedList, cxListFind) {
 20.1008 -    verifyFind(pointerLinkedListFromTestData());
 20.1009 -}
 20.1010 -
 20.1011 -TEST_F(ArrayList, cxListFind) {
 20.1012 -    verifyFind(arrayListFromTestData());
 20.1013 -}
 20.1014 -
 20.1015 -TEST_F(LinkedList, cxListSort) {
 20.1016 -    verifySort(linkedListFromTestData());
 20.1017 -}
 20.1018 -
 20.1019 -TEST_F(PointerLinkedList, cxListSort) {
 20.1020 -    verifySort(pointerLinkedListFromTestData());
 20.1021 -}
 20.1022 -
 20.1023 -TEST_F(ArrayList, cxListSort) {
 20.1024 -    verifySort(arrayListFromTestData());
 20.1025 -}
 20.1026 -
 20.1027 -TEST_F(LinkedList, Iterator) {
 20.1028 -    verifyIterator(linkedListFromTestData());
 20.1029 -}
 20.1030 -
 20.1031 -TEST_F(PointerLinkedList, Iterator) {
 20.1032 -    verifyIterator(pointerLinkedListFromTestData());
 20.1033 -}
 20.1034 -
 20.1035 -TEST_F(ArrayList, Iterator) {
 20.1036 -    verifyIterator(arrayListFromTestData());
 20.1037 -}
 20.1038 -
 20.1039 -TEST_F(LinkedList, InsertViaIterator) {
 20.1040 -    int fivenums[] = {0, 1, 2, 3, 4, 5};
 20.1041 -    CxList *list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
 20.1042 -    cxListAddArray(list, fivenums, 5);
 20.1043 -    verifyInsertViaIterator(list);
 20.1044 -}
 20.1045 -
 20.1046 -TEST_F(PointerLinkedList, InsertViaIterator) {
 20.1047 -    int fivenums[] = {0, 1, 2, 3, 4, 5};
 20.1048 -    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
 20.1049 -    cxListStorePointers(list);
 20.1050 -    // note: cannot use cxListAddArray() because we don't have a list of pointers
 20.1051 -    cx_for_n(i, 5) cxListAdd(list, &fivenums[i]);
 20.1052 -    verifyInsertViaIterator(list);
 20.1053 -}
 20.1054 -
 20.1055 -TEST_F(ArrayList, InsertViaIterator) {
 20.1056 -    int fivenums[] = {0, 1, 2, 3, 4, 5};
 20.1057 -    CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 4));
 20.1058 -    cxListAddArray(list, fivenums, 5);
 20.1059 -    verifyInsertViaIterator(list);
 20.1060 -}
 20.1061 -
 20.1062 -TEST_F(LinkedList, cxListReverse) {
 20.1063 -    verifyReverse(linkedListFromTestData());
 20.1064 -}
 20.1065 -
 20.1066 -TEST_F(PointerLinkedList, cxListReverse) {
 20.1067 -    verifyReverse(pointerLinkedListFromTestData());
 20.1068 -}
 20.1069 -
 20.1070 -TEST_F(ArrayList, cxListReverse) {
 20.1071 -    verifyReverse(arrayListFromTestData());
 20.1072 -}
 20.1073 -
 20.1074 -TEST_F(LinkedList, cxListCompare) {
 20.1075 -    auto left = linkedListFromTestData();
 20.1076 -    auto right = linkedListFromTestData();
 20.1077 -    verifyCompare(left, right);
 20.1078 -}
 20.1079 -
 20.1080 -TEST_F(LinkedList, cxListCompareWithPtrList) {
 20.1081 -    auto left = linkedListFromTestData();
 20.1082 -    auto right = pointerLinkedListFromTestData();
 20.1083 -    verifyCompare(left, right);
 20.1084 -}
 20.1085 -
 20.1086 -TEST_F(LinkedList, cxListCompareWithArrayList) {
 20.1087 -    auto left = linkedListFromTestData();
 20.1088 -    auto right = arrayListFromTestData();
 20.1089 -    verifyCompare(left, right);
 20.1090 -}
 20.1091 -
 20.1092 -TEST_F(PointerLinkedList, cxListCompare) {
 20.1093 -    auto left = pointerLinkedListFromTestData();
 20.1094 -    auto right = pointerLinkedListFromTestData();
 20.1095 -    verifyCompare(left, right);
 20.1096 -}
 20.1097 -
 20.1098 -TEST_F(PointerLinkedList, cxListCompareWithNormalList) {
 20.1099 -    auto left = pointerLinkedListFromTestData();
 20.1100 -    auto right = linkedListFromTestData();
 20.1101 -    verifyCompare(left, right);
 20.1102 -}
 20.1103 -
 20.1104 -TEST_F(PointerLinkedList, cxListCompareWithArrayList) {
 20.1105 -    auto left = pointerLinkedListFromTestData();
 20.1106 -    auto right = arrayListFromTestData();
 20.1107 -    verifyCompare(left, right);
 20.1108 -}
 20.1109 -
 20.1110 -TEST_F(ArrayList, cxListCompare) {
 20.1111 -    auto left = arrayListFromTestData();
 20.1112 -    auto right = arrayListFromTestData();
 20.1113 -    verifyCompare(left, right);
 20.1114 -}
 20.1115 -
 20.1116 -TEST_F(ArrayList, cxListCompareWithPtrList) {
 20.1117 -    auto left = arrayListFromTestData();
 20.1118 -    auto right = pointerLinkedListFromTestData();
 20.1119 -    verifyCompare(left, right);
 20.1120 -}
 20.1121 -
 20.1122 -TEST_F(ArrayList, cxListCompareWithNormalList) {
 20.1123 -    auto left = arrayListFromTestData();
 20.1124 -    auto right = linkedListFromTestData();
 20.1125 -    verifyCompare(left, right);
 20.1126 -}
 20.1127 -
 20.1128 -TEST_F(PointerLinkedList, NoDestructor) {
 20.1129 -    void *item = cxMalloc(&testingAllocator, sizeof(int));
 20.1130 -    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 20.1131 -    cxListStorePointers(list);
 20.1132 -    cxListAdd(list, item);
 20.1133 -    ASSERT_FALSE(testingAllocator.verify());
 20.1134 -    cxListDestroy(list);
 20.1135 -    EXPECT_FALSE(testingAllocator.verify());
 20.1136 -    cxFree(&testingAllocator, item);
 20.1137 -    EXPECT_TRUE(testingAllocator.verify());
 20.1138 -}
 20.1139 -
 20.1140 -TEST_F(PointerLinkedList, SimpleDestructor) {
 20.1141 -    int item = 0;
 20.1142 -    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 20.1143 -    cxListStorePointers(list);
 20.1144 -    list->content_destructor_type = CX_DESTRUCTOR_SIMPLE;
 20.1145 -    list->simple_destructor = [](void *elem) { *(int *) elem = 42; };
 20.1146 -    cxListAdd(list, &item);
 20.1147 -    cxListDestroy(list);
 20.1148 -    EXPECT_EQ(item, 42);
 20.1149 -}
 20.1150 -
 20.1151 -TEST_F(PointerLinkedList, AdvancedDestructor) {
 20.1152 -    void *item = cxMalloc(&testingAllocator, sizeof(int));
 20.1153 -    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 20.1154 -    cxListStorePointers(list);
 20.1155 -    list->content_destructor_type = CX_DESTRUCTOR_ADVANCED;
 20.1156 -    list->advanced_destructor.data = &testingAllocator;
 20.1157 -    list->advanced_destructor.func = (cx_destructor_func2) cxFree;
 20.1158 -    cxListAdd(list, item);
 20.1159 -    ASSERT_FALSE(testingAllocator.verify());
 20.1160 -    cxListDestroy(list);
 20.1161 -    EXPECT_TRUE(testingAllocator.verify());
 20.1162 -}
    21.1 --- a/test/test_map.cpp	Wed Feb 08 20:26:09 2023 +0100
    21.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.3 @@ -1,272 +0,0 @@
    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/hash_map.h"
   21.33 -#include "cx/utils.h"
   21.34 -#include "util_allocator.h"
   21.35 -
   21.36 -#include <gtest/gtest.h>
   21.37 -#include <unordered_map>
   21.38 -#include <unordered_set>
   21.39 -
   21.40 -struct map_operation {
   21.41 -    enum {
   21.42 -        put, rm
   21.43 -    } op;
   21.44 -    char const *key;
   21.45 -    char const *value;
   21.46 -};
   21.47 -
   21.48 -auto generate_map_operations() -> std::vector<map_operation> {
   21.49 -    return {
   21.50 -            {map_operation::put, "key 1",          "test"},
   21.51 -            {map_operation::put, "key 2",          "blub"},
   21.52 -            {map_operation::put, "key 3",          "hallo"},
   21.53 -            {map_operation::put, "key 2",          "foobar"},
   21.54 -            {map_operation::put, "key 4",          "value 4"},
   21.55 -            {map_operation::put, "key 5",          "value 5"},
   21.56 -            {map_operation::put, "key 6",          "value 6"},
   21.57 -            {map_operation::rm,  "key 4",          nullptr},
   21.58 -            {map_operation::put, "key 7",          "value 7"},
   21.59 -            {map_operation::put, "key 8",          "value 8"},
   21.60 -            {map_operation::rm,  "does not exist", nullptr},
   21.61 -            {map_operation::put, "key 9",          "value 9"},
   21.62 -            {map_operation::put, "key 6",          "other value"},
   21.63 -            {map_operation::put, "key 7",          "something else"},
   21.64 -            {map_operation::rm,  "key 8",          nullptr},
   21.65 -            {map_operation::rm,  "key 2",          nullptr},
   21.66 -            {map_operation::put, "key 8",          "new value"},
   21.67 -    };
   21.68 -}
   21.69 -
   21.70 -static void verify_map_contents(
   21.71 -        CxMap *map,
   21.72 -        std::unordered_map<std::string, std::string> const &refmap
   21.73 -) {
   21.74 -    // verify key iterator
   21.75 -    {
   21.76 -        auto keyiter = cxMapIteratorKeys(map);
   21.77 -        std::unordered_set<std::string> keys;
   21.78 -        cx_foreach(CxHashKey*, elem, keyiter) {
   21.79 -            keys.insert(std::string(elem->data.cstr, elem->len));
   21.80 -        }
   21.81 -        EXPECT_EQ(keyiter.index, map->size);
   21.82 -        ASSERT_EQ(keys.size(), map->size);
   21.83 -        for (auto &&k: keys) {
   21.84 -            EXPECT_NE(refmap.find(k), refmap.end());
   21.85 -        }
   21.86 -    }
   21.87 -
   21.88 -    // verify value iterator
   21.89 -    {
   21.90 -        auto valiter = cxMapIteratorValues(map);
   21.91 -        std::unordered_set<std::string> values; // we use that the values in our test data are unique strings
   21.92 -        cx_foreach(char const*, elem, valiter) {
   21.93 -            values.insert(std::string(elem));
   21.94 -        }
   21.95 -        EXPECT_EQ(valiter.index, map->size);
   21.96 -        ASSERT_EQ(values.size(), map->size);
   21.97 -        for (auto &&v: values) {
   21.98 -            EXPECT_NE(std::find_if(refmap.begin(), refmap.end(),
   21.99 -                                   [v](auto const &e) { return e.second == v; }), refmap.end());
  21.100 -        }
  21.101 -    }
  21.102 -
  21.103 -    // verify pair iterator
  21.104 -    {
  21.105 -        auto pairiter = cxMapIterator(map);
  21.106 -        std::unordered_map<std::string, std::string> pairs;
  21.107 -        cx_foreach(CxMapEntry*, entry, pairiter) {
  21.108 -            pairs[std::string(entry->key->data.cstr, entry->key->len)] = std::string((char *) entry->value);
  21.109 -        }
  21.110 -        EXPECT_EQ(pairiter.index, map->size);
  21.111 -        ASSERT_EQ(pairs.size(), refmap.size());
  21.112 -        for (auto &&p: pairs) {
  21.113 -            ASSERT_EQ(p.second, refmap.at(p.first));
  21.114 -        }
  21.115 -    }
  21.116 -}
  21.117 -
  21.118 -TEST(CxHashMap, Create) {
  21.119 -    CxTestingAllocator allocator;
  21.120 -    auto map = cxHashMapCreate(&allocator, 0);
  21.121 -    auto hmap = reinterpret_cast<struct cx_hash_map_s *>(map);
  21.122 -    EXPECT_GT(hmap->bucket_count, 0);
  21.123 -    cx_for_n(i, hmap->bucket_count) {
  21.124 -        EXPECT_EQ(hmap->buckets[i], nullptr);
  21.125 -    }
  21.126 -    EXPECT_EQ(map->size, 0);
  21.127 -    EXPECT_EQ(map->allocator, &allocator);
  21.128 -
  21.129 -    cxMapDestroy(map);
  21.130 -    EXPECT_TRUE(allocator.verify());
  21.131 -}
  21.132 -
  21.133 -TEST(CxHashMap, BasicOperations) {
  21.134 -    // create the map
  21.135 -    CxTestingAllocator allocator;
  21.136 -    auto map = cxHashMapCreate(&allocator, 8);
  21.137 -
  21.138 -    // create a reference map
  21.139 -    std::unordered_map<std::string, std::string> refmap;
  21.140 -
  21.141 -    // generate operations
  21.142 -    auto ops = generate_map_operations();
  21.143 -
  21.144 -    // verify iterators for empty map
  21.145 -    verify_map_contents(map, refmap);
  21.146 -
  21.147 -    // execute operations and verify results
  21.148 -    for (auto &&op: ops) {
  21.149 -        CxHashKey key = cx_hash_key_str(op.key);
  21.150 -        key.hash = 0; // force the hash map to compute the hash
  21.151 -        if (op.op == map_operation::put) {
  21.152 -            // execute a put operation and verify that the exact value can be read back
  21.153 -            refmap[std::string(op.key)] = std::string(op.value);
  21.154 -            int result = cxMapPut(map, key, (void *) op.value);
  21.155 -            EXPECT_EQ(result, 0);
  21.156 -            auto added = cxMapGet(map, key);
  21.157 -            EXPECT_EQ(memcmp(op.value, added, strlen(op.value)), 0);
  21.158 -        } else {
  21.159 -            // execute a remove and verify that the removed element was returned (or nullptr)
  21.160 -            auto found = refmap.find(op.key);
  21.161 -            auto removed = cxMapRemove(map, key);
  21.162 -            if (found == refmap.end()) {
  21.163 -                EXPECT_EQ(removed, nullptr);
  21.164 -            } else {
  21.165 -                EXPECT_EQ(std::string((char *) removed), found->second);
  21.166 -                refmap.erase(found);
  21.167 -            }
  21.168 -        }
  21.169 -        // compare the current map state with the reference map
  21.170 -        verify_map_contents(map, refmap);
  21.171 -    }
  21.172 -
  21.173 -    // destroy the map and verify the memory (de)allocations
  21.174 -    cxMapDestroy(map);
  21.175 -    EXPECT_TRUE(allocator.verify());
  21.176 -}
  21.177 -
  21.178 -TEST(CxHashMap, RemoveViaIterator) {
  21.179 -    CxTestingAllocator allocator;
  21.180 -    auto map = cxHashMapCreate(&allocator, 4);
  21.181 -
  21.182 -    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  21.183 -    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  21.184 -    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  21.185 -    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  21.186 -    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  21.187 -    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  21.188 -
  21.189 -    auto iter = cxMapMutIterator(map);
  21.190 -    cx_foreach(CxMapEntry*, entry, iter) {
  21.191 -        if (entry->key->data.cstr[4] % 2 == 1) cxIteratorFlagRemoval(iter);
  21.192 -    }
  21.193 -    EXPECT_EQ(map->size, 3);
  21.194 -    EXPECT_EQ(iter.index, map->size);
  21.195 -
  21.196 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
  21.197 -    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
  21.198 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
  21.199 -    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 4")), nullptr);
  21.200 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 5")), nullptr);
  21.201 -    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 6")), nullptr);
  21.202 -
  21.203 -    cxMapDestroy(map);
  21.204 -    EXPECT_TRUE(allocator.verify());
  21.205 -}
  21.206 -
  21.207 -TEST(CxHashMap, RehashNotRequired) {
  21.208 -    CxTestingAllocator allocator;
  21.209 -    auto map = cxHashMapCreate(&allocator, 8);
  21.210 -
  21.211 -    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  21.212 -    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  21.213 -    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  21.214 -    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  21.215 -    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  21.216 -    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  21.217 -
  21.218 -    // 6/8 does not exceed 0.75, therefore the function should not rehash
  21.219 -    int result = cxMapRehash(map);
  21.220 -    EXPECT_EQ(result, 0);
  21.221 -    EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 8);
  21.222 -
  21.223 -    cxMapDestroy(map);
  21.224 -    EXPECT_TRUE(allocator.verify());
  21.225 -}
  21.226 -
  21.227 -TEST(CxHashMap, Rehash) {
  21.228 -    CxTestingAllocator allocator;
  21.229 -    auto map = cxHashMapCreate(&allocator, 8);
  21.230 -
  21.231 -    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  21.232 -    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  21.233 -    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  21.234 -    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  21.235 -    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  21.236 -    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  21.237 -    cxMapPut(map, cx_hash_key_str("key 7"), (void *) "val 7");
  21.238 -
  21.239 -    int result = cxMapRehash(map);
  21.240 -    EXPECT_EQ(result, 0);
  21.241 -    EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 17);
  21.242 -    EXPECT_EQ(map->size, 7);
  21.243 -
  21.244 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 1")), "val 1"), 0);
  21.245 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 2")), "val 2"), 0);
  21.246 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 3")), "val 3"), 0);
  21.247 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 4")), "val 4"), 0);
  21.248 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 5")), "val 5"), 0);
  21.249 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 6")), "val 6"), 0);
  21.250 -    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 7")), "val 7"), 0);
  21.251 -
  21.252 -    cxMapDestroy(map);
  21.253 -    EXPECT_TRUE(allocator.verify());
  21.254 -}
  21.255 -
  21.256 -TEST(CxHashMap, Clear) {
  21.257 -    CxTestingAllocator allocator;
  21.258 -    auto map = cxHashMapCreate(&allocator, 0);
  21.259 -    
  21.260 -    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  21.261 -    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  21.262 -    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  21.263 -
  21.264 -    EXPECT_EQ(map->size, 3);
  21.265 -
  21.266 -    cxMapClear(map);
  21.267 -
  21.268 -    EXPECT_EQ(map->size, 0);
  21.269 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
  21.270 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
  21.271 -    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
  21.272 -
  21.273 -    cxMapDestroy(map);
  21.274 -    EXPECT_TRUE(allocator.verify());
  21.275 -}
  21.276 \ No newline at end of file
    22.1 --- a/test/test_printf.cpp	Wed Feb 08 20:26:09 2023 +0100
    22.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.3 @@ -1,284 +0,0 @@
    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/printf.h"
   22.33 -#include "cx/buffer.h"
   22.34 -
   22.35 -#include <gtest/gtest.h>
   22.36 -#include "util_allocator.h"
   22.37 -
   22.38 -class PrintfFixture : public ::testing::Test {
   22.39 -protected:
   22.40 -    std::string buf;
   22.41 -    CxTestingAllocator alloc;
   22.42 -
   22.43 -    void TearDown() override {
   22.44 -        buf.clear();
   22.45 -        ASSERT_TRUE(alloc.verify());
   22.46 -    }
   22.47 -
   22.48 -    static size_t write_func(
   22.49 -            void const *src,
   22.50 -            size_t esize,
   22.51 -            size_t ecount,
   22.52 -            void *target
   22.53 -    ) {
   22.54 -        auto str = reinterpret_cast<char const *>(src);
   22.55 -        auto buf = reinterpret_cast<std::string *>(target);
   22.56 -        EXPECT_EQ(esize, 1);
   22.57 -        EXPECT_EQ(strlen(str), ecount);
   22.58 -        *buf = str;
   22.59 -        return ecount;
   22.60 -    }
   22.61 -};
   22.62 -
   22.63 -
   22.64 -TEST_F(PrintfFixture, BPrintf) {
   22.65 -    CxBuffer buf;
   22.66 -    cxBufferInit(&buf, nullptr, 64, &alloc, 0);
   22.67 -
   22.68 -    auto r = cx_bprintf(&buf, "This %s aged %u years in a %2XSK.", "Test", 10, 0xca);
   22.69 -    EXPECT_EQ(r, 34);
   22.70 -    EXPECT_EQ(buf.size, 34);
   22.71 -    buf.space[r] = '\0';
   22.72 -    EXPECT_STREQ(buf.space, "This Test aged 10 years in a CASK.");
   22.73 -
   22.74 -    cxBufferDestroy(&buf);
   22.75 -}
   22.76 -
   22.77 -TEST_F(PrintfFixture, FPrintf) {
   22.78 -    auto h = "Hello";
   22.79 -    size_t r;
   22.80 -
   22.81 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "teststring");
   22.82 -    EXPECT_EQ(r, 10);
   22.83 -    EXPECT_EQ(buf, "teststring");
   22.84 -
   22.85 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%10s]", h);
   22.86 -    EXPECT_EQ(r, 12);
   22.87 -    EXPECT_EQ(buf, "[     Hello]");
   22.88 -
   22.89 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-10s]", h);
   22.90 -    EXPECT_EQ(r, 12);
   22.91 -    EXPECT_EQ(buf, "[Hello     ]");
   22.92 -
   22.93 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%*s]", 10, h);
   22.94 -    EXPECT_EQ(r, 12);
   22.95 -    EXPECT_EQ(buf, "[     Hello]");
   22.96 -
   22.97 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-10.*s]", 4, h);
   22.98 -    EXPECT_EQ(r, 12);
   22.99 -    EXPECT_EQ(buf, "[Hell      ]");
  22.100 -
  22.101 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-*.*s]", 10, 4, h);
  22.102 -    EXPECT_EQ(r, 12);
  22.103 -    EXPECT_EQ(buf, "[Hell      ]");
  22.104 -
  22.105 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%c", 'A');
  22.106 -    EXPECT_EQ(r, 1);
  22.107 -    EXPECT_EQ(buf, "A");
  22.108 -
  22.109 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
  22.110 -    EXPECT_EQ(r, 19);
  22.111 -    EXPECT_EQ(buf, "1 2 000003 0  +4 -4");
  22.112 -
  22.113 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%x %x %X %#x", 5, 10, 10, 6);
  22.114 -    EXPECT_EQ(r, 9);
  22.115 -    EXPECT_EQ(buf, "5 a A 0x6");
  22.116 -
  22.117 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%o %#o %#o", 10, 10, 4);
  22.118 -    EXPECT_EQ(r, 9);
  22.119 -    EXPECT_EQ(buf, "12 012 04");
  22.120 -
  22.121 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%f %.0f %.32f", 1.5, 1.5, 1.3);
  22.122 -    EXPECT_EQ(r, 45);
  22.123 -    EXPECT_EQ(buf, "1.500000 2 1.30000000000000004440892098500626");
  22.124 -
  22.125 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
  22.126 -    EXPECT_EQ(r, 16);
  22.127 -    EXPECT_EQ(buf, "01.50 1.50  1.50");
  22.128 -
  22.129 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%E %e", 1.5, 1.5);
  22.130 -    EXPECT_EQ(r, 25);
  22.131 -    EXPECT_EQ(buf, "1.500000E+00 1.500000e+00");
  22.132 -
  22.133 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "%a %A", 1.5, 1.5);
  22.134 -    EXPECT_EQ(r, 17);
  22.135 -    EXPECT_EQ(buf, "0x1.8p+0 0X1.8P+0");
  22.136 -
  22.137 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "0/0=%g 1/0=%g", 0.0 / 0.0, 1.0 / 0.0);
  22.138 -    EXPECT_EQ(r, 16);
  22.139 -    EXPECT_EQ(buf, "0/0=-nan 1/0=inf");
  22.140 -
  22.141 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "'%*c'", 5, 'x');
  22.142 -    EXPECT_EQ(r, 7);
  22.143 -    EXPECT_EQ(buf, "'    x'");
  22.144 -
  22.145 -    r = cx_fprintf(&buf, PrintfFixture::write_func, "'%*c'", -5, 'x');
  22.146 -    EXPECT_EQ(r, 7);
  22.147 -    EXPECT_EQ(buf, "'x    '");
  22.148 -}
  22.149 -
  22.150 -TEST_F(PrintfFixture, BPrintfLargeString) {
  22.151 -    CxBuffer buf;
  22.152 -    cxBufferInit(&buf, nullptr, 64, &alloc, CX_BUFFER_AUTO_EXTEND);
  22.153 -
  22.154 -    auto aaa = std::string(512, 'a');
  22.155 -    auto bbb = std::string(512, 'b');
  22.156 -
  22.157 -    auto r = cx_bprintf(&buf, "After %s comes %s.", aaa.data(), bbb.data());
  22.158 -    EXPECT_EQ(r, 1038);
  22.159 -    EXPECT_EQ(buf.size, 1038);
  22.160 -    cxBufferPut(&buf, 0);
  22.161 -    EXPECT_EQ(buf.space, std::string("After ") + aaa + " comes " + bbb + ".");
  22.162 -
  22.163 -    cxBufferDestroy(&buf);
  22.164 -}
  22.165 -
  22.166 -TEST_F(PrintfFixture, BPrintfNoCap) {
  22.167 -    CxBuffer buf;
  22.168 -    char space[20];
  22.169 -    memset(space, 'a', 20);
  22.170 -    cxBufferInit(&buf, space, 16, &alloc, 0);
  22.171 -
  22.172 -    auto r = cx_bprintf(&buf, "Hello %s with more than %d chars.", "string", 16);
  22.173 -    EXPECT_EQ(r, 16);
  22.174 -    EXPECT_EQ(buf.size, 16);
  22.175 -    EXPECT_EQ(0, memcmp(space, "Hello string witaaaa", 20));
  22.176 -
  22.177 -    cxBufferDestroy(&buf);
  22.178 -}
  22.179 -
  22.180 -TEST_F(PrintfFixture, SPrintf) {
  22.181 -    auto h = "Hello";
  22.182 -
  22.183 -    std::vector<char *> fl;
  22.184 -    cxmutstr r;
  22.185 -
  22.186 -    r = cx_asprintf_a(&alloc, "teststring");
  22.187 -    EXPECT_EQ(r.length, 10);
  22.188 -    EXPECT_STREQ(r.ptr, "teststring");
  22.189 -    fl.push_back(r.ptr);
  22.190 -
  22.191 -    r = cx_asprintf_a(&alloc, "[%10s]", h);
  22.192 -    EXPECT_EQ(r.length, 12);
  22.193 -    EXPECT_STREQ(r.ptr, "[     Hello]");
  22.194 -    fl.push_back(r.ptr);
  22.195 -
  22.196 -    r = cx_asprintf_a(&alloc, "[%-10s]", h);
  22.197 -    EXPECT_EQ(r.length, 12);
  22.198 -    EXPECT_STREQ(r.ptr, "[Hello     ]");
  22.199 -    fl.push_back(r.ptr);
  22.200 -
  22.201 -    r = cx_asprintf_a(&alloc, "[%*s]", 10, h);
  22.202 -    EXPECT_EQ(r.length, 12);
  22.203 -    EXPECT_STREQ(r.ptr, "[     Hello]");
  22.204 -    fl.push_back(r.ptr);
  22.205 -
  22.206 -    r = cx_asprintf_a(&alloc, "[%-10.*s]", 4, h);
  22.207 -    EXPECT_EQ(r.length, 12);
  22.208 -    EXPECT_STREQ(r.ptr, "[Hell      ]");
  22.209 -    fl.push_back(r.ptr);
  22.210 -
  22.211 -    r = cx_asprintf_a(&alloc, "[%-*.*s]", 10, 4, h);
  22.212 -    EXPECT_EQ(r.length, 12);
  22.213 -    EXPECT_STREQ(r.ptr, "[Hell      ]");
  22.214 -    fl.push_back(r.ptr);
  22.215 -
  22.216 -    r = cx_asprintf_a(&alloc, "%c", 'A');
  22.217 -    EXPECT_EQ(r.length, 1);
  22.218 -    EXPECT_STREQ(r.ptr, "A");
  22.219 -    fl.push_back(r.ptr);
  22.220 -
  22.221 -    r = cx_asprintf_a(&alloc, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
  22.222 -    EXPECT_EQ(r.length, 19);
  22.223 -    EXPECT_STREQ(r.ptr, "1 2 000003 0  +4 -4");
  22.224 -    fl.push_back(r.ptr);
  22.225 -
  22.226 -    r = cx_asprintf_a(&alloc, "%x %x %X %#x", 5, 10, 10, 6);
  22.227 -    EXPECT_EQ(r.length, 9);
  22.228 -    EXPECT_STREQ(r.ptr, "5 a A 0x6");
  22.229 -    fl.push_back(r.ptr);
  22.230 -
  22.231 -    r = cx_asprintf_a(&alloc, "%o %#o %#o", 10, 10, 4);
  22.232 -    EXPECT_EQ(r.length, 9);
  22.233 -    EXPECT_STREQ(r.ptr, "12 012 04");
  22.234 -    fl.push_back(r.ptr);
  22.235 -
  22.236 -    r = cx_asprintf_a(&alloc, "%f %.0f %.32f", 1.5, 1.5, 1.3);
  22.237 -    EXPECT_EQ(r.length, 45);
  22.238 -    EXPECT_STREQ(r.ptr, "1.500000 2 1.30000000000000004440892098500626");
  22.239 -    fl.push_back(r.ptr);
  22.240 -
  22.241 -    r = cx_asprintf_a(&alloc, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
  22.242 -    EXPECT_EQ(r.length, 16);
  22.243 -    EXPECT_STREQ(r.ptr, "01.50 1.50  1.50");
  22.244 -    fl.push_back(r.ptr);
  22.245 -
  22.246 -    r = cx_asprintf_a(&alloc, "%E %e", 1.5, 1.5);
  22.247 -    EXPECT_EQ(r.length, 25);
  22.248 -    EXPECT_STREQ(r.ptr, "1.500000E+00 1.500000e+00");
  22.249 -    fl.push_back(r.ptr);
  22.250 -
  22.251 -    r = cx_asprintf_a(&alloc, "%a %A", 1.5, 1.5);
  22.252 -    EXPECT_EQ(r.length, 17);
  22.253 -    EXPECT_STREQ(r.ptr, "0x1.8p+0 0X1.8P+0");
  22.254 -    fl.push_back(r.ptr);
  22.255 -
  22.256 -    r = cx_asprintf_a(&alloc, "0/0=%g 1/0=%g", 0.0 / 0.0, 1.0 / 0.0);
  22.257 -    EXPECT_EQ(r.length, 16);
  22.258 -    EXPECT_STREQ(r.ptr, "0/0=-nan 1/0=inf");
  22.259 -    fl.push_back(r.ptr);
  22.260 -
  22.261 -    r = cx_asprintf_a(&alloc, "'%*c'", 5, 'x');
  22.262 -    EXPECT_EQ(r.length, 7);
  22.263 -    EXPECT_STREQ(r.ptr, "'    x'");
  22.264 -    fl.push_back(r.ptr);
  22.265 -
  22.266 -    r = cx_asprintf_a(&alloc, "'%*c'", -5, 'x');
  22.267 -    EXPECT_EQ(r.length, 7);
  22.268 -    EXPECT_STREQ(r.ptr, "'x    '");
  22.269 -    fl.push_back(r.ptr);
  22.270 -
  22.271 -    for (auto c: fl) {
  22.272 -        auto s = cx_mutstrn(c, 0);
  22.273 -        cx_strfree_a(&alloc, &s);
  22.274 -    }
  22.275 -}
  22.276 -
  22.277 -TEST_F(PrintfFixture, SPrintfLargeString) {
  22.278 -    auto aaa = std::string(512, 'a');
  22.279 -    auto bbb = std::string(512, 'b');
  22.280 -
  22.281 -    auto r = cx_asprintf_a(&alloc, "After %s comes %s.", aaa.data(), bbb.data());
  22.282 -    EXPECT_EQ(r.length, 1038);
  22.283 -    EXPECT_EQ(r.ptr, std::string("After ") + aaa + " comes " + bbb + ".");
  22.284 -    EXPECT_EQ(r.ptr[1038], '\0');
  22.285 -
  22.286 -    cx_strfree_a(&alloc, &r);
  22.287 -}
  22.288 \ No newline at end of file
    23.1 --- a/test/test_string.cpp	Wed Feb 08 20:26:09 2023 +0100
    23.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.3 @@ -1,865 +0,0 @@
    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/string.h"
   23.33 -#include "util_allocator.h"
   23.34 -
   23.35 -#include <gtest/gtest.h>
   23.36 -
   23.37 -#define EXPECT_ZERO_TERMINATED(str) EXPECT_EQ((str).ptr[(str).length], '\0')
   23.38 -
   23.39 -TEST(String, construct) {
   23.40 -    cxstring s1 = cx_str("1234");
   23.41 -    cxstring s2 = cx_strn("abcd", 2);
   23.42 -    cxmutstr s3 = cx_mutstr((char *) "1234");
   23.43 -    cxmutstr s4 = cx_mutstrn((char *) "abcd", 2);
   23.44 -
   23.45 -    EXPECT_EQ(s1.length, 4);
   23.46 -    EXPECT_EQ(s2.length, 2);
   23.47 -    EXPECT_EQ(s3.length, 4);
   23.48 -    EXPECT_EQ(s4.length, 2);
   23.49 -}
   23.50 -
   23.51 -TEST(String, strfree) {
   23.52 -    CxTestingAllocator alloc;
   23.53 -    auto test = (char *) cxMalloc(&alloc, 16);
   23.54 -    cxmutstr str = cx_mutstrn(test, 16);
   23.55 -    ASSERT_EQ(str.ptr, test);
   23.56 -    EXPECT_EQ(str.length, 16);
   23.57 -    cx_strfree_a(&alloc, &str);
   23.58 -    EXPECT_EQ(str.ptr, nullptr);
   23.59 -    EXPECT_EQ(str.length, 0);
   23.60 -    EXPECT_TRUE(alloc.verify());
   23.61 -}
   23.62 -
   23.63 -TEST(String, strdup) {
   23.64 -    cxstring str = CX_STR("test");
   23.65 -    cxmutstr dup = cx_strdup(str);
   23.66 -    ASSERT_EQ(dup.length, str.length);
   23.67 -    EXPECT_STREQ(dup.ptr, str.ptr);
   23.68 -    EXPECT_ZERO_TERMINATED(dup);
   23.69 -    cx_strfree(&dup);
   23.70 -
   23.71 -    str.length = 2;
   23.72 -    dup = cx_strdup(str);
   23.73 -    ASSERT_EQ(dup.length, str.length);
   23.74 -    EXPECT_STREQ(dup.ptr, "te");
   23.75 -    EXPECT_ZERO_TERMINATED(dup);
   23.76 -    cx_strfree(&dup);
   23.77 -}
   23.78 -
   23.79 -TEST(String, strlen) {
   23.80 -    cxstring s1 = CX_STR("1234");
   23.81 -    cxstring s2 = CX_STR(".:.:.");
   23.82 -    cxstring s3 = CX_STR("X");
   23.83 -
   23.84 -    size_t len0 = cx_strlen(0);
   23.85 -    size_t len1 = cx_strlen(1, s1);
   23.86 -    size_t len2 = cx_strlen(2, s1, s2);
   23.87 -    size_t len3 = cx_strlen(3, s1, s2, s3);
   23.88 -
   23.89 -    EXPECT_EQ(len0, 0);
   23.90 -    EXPECT_EQ(len1, 4);
   23.91 -    EXPECT_EQ(len2, 9);
   23.92 -    EXPECT_EQ(len3, 10);
   23.93 -}
   23.94 -
   23.95 -TEST(String, strsubs) {
   23.96 -    cxstring str = CX_STR("A test string");
   23.97 -
   23.98 -    cxstring sub = cx_strsubs(str, 0);
   23.99 -    EXPECT_EQ(cx_strcmp(sub, str), 0);
  23.100 -
  23.101 -    sub = cx_strsubs(str, 2);
  23.102 -    EXPECT_EQ(cx_strcmp(sub, cx_str("test string")), 0);
  23.103 -
  23.104 -    sub = cx_strsubs(str, 7);
  23.105 -    EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
  23.106 -
  23.107 -    sub = cx_strsubs(str, 15);
  23.108 -    EXPECT_EQ(cx_strcmp(sub, cx_str("")), 0);
  23.109 -
  23.110 -    sub = cx_strsubsl(str, 2, 4);
  23.111 -    EXPECT_EQ(cx_strcmp(sub, cx_str("test")), 0);
  23.112 -
  23.113 -    sub = cx_strsubsl(str, 7, 3);
  23.114 -    EXPECT_EQ(cx_strcmp(sub, cx_str("str")), 0);
  23.115 -
  23.116 -    sub = cx_strsubsl(str, 7, 20);
  23.117 -    EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
  23.118 -
  23.119 -    // just for coverage, call the _m variant
  23.120 -    auto m = cx_strsubs_m(cx_mutstrn(nullptr, 0), 0);
  23.121 -    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  23.122 -}
  23.123 -
  23.124 -TEST(String, strchr) {
  23.125 -    cxstring str = CX_STR("I will find you - and I will kill you");
  23.126 -
  23.127 -    cxstring notfound = cx_strchr(str, 'x');
  23.128 -    EXPECT_EQ(notfound.length, 0);
  23.129 -
  23.130 -    cxstring result = cx_strchr(str, 'w');
  23.131 -    EXPECT_EQ(result.length, 35);
  23.132 -    EXPECT_STREQ(result.ptr, "will find you - and I will kill you");
  23.133 -
  23.134 -    // just for coverage, call the _m variant
  23.135 -    auto m = cx_strchr_m(cx_mutstrn(nullptr, 0), 'a');
  23.136 -    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  23.137 -}
  23.138 -
  23.139 -TEST(String, strrchr) {
  23.140 -    cxstring str = CX_STR("I will find you - and I will kill you");
  23.141 -
  23.142 -    cxstring notfound = cx_strrchr(str, 'x');
  23.143 -    EXPECT_EQ(notfound.length, 0);
  23.144 -
  23.145 -    cxstring result = cx_strrchr(str, 'w');
  23.146 -    EXPECT_EQ(result.length, 13);
  23.147 -    EXPECT_STREQ(result.ptr, "will kill you");
  23.148 -
  23.149 -    // just for coverage, call the _m variant
  23.150 -    auto m = cx_strrchr_m(cx_mutstrn(nullptr, 0), 'a');
  23.151 -    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  23.152 -}
  23.153 -
  23.154 -TEST(String, strstr) {
  23.155 -    cxstring str = CX_STR("find the match in this string");
  23.156 -    cxstring longstr = CX_STR(
  23.157 -            "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl"
  23.158 -            "mnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx"
  23.159 -            "yzabcdeababababnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij"
  23.160 -            "klmnopqrstuvwxyzaababababababababrstuvwxyzabcdefghijklmnopqrstuv"
  23.161 -            "abababababababababababababababababababababababababababababababab"
  23.162 -            "abababababababababababababababababababababababababababababababab"
  23.163 -            "abababababababababababababababababababababababababababababababab"
  23.164 -            "abababababababababababababababababababababababababababababababab"
  23.165 -            "abababababababababababababababababababababababababababababababab"
  23.166 -            "abababababababababababababababababababababababababababababababab"
  23.167 -            "wxyz1234567890");
  23.168 -    cxstring longstrpattern = CX_STR(
  23.169 -            "abababababababababababababababababababababababababababababababab"
  23.170 -            "abababababababababababababababababababababababababababababababab"
  23.171 -            "abababababababababababababababababababababababababababababababab"
  23.172 -            "abababababababababababababababababababababababababababababababab"
  23.173 -            "abababababababababababababababababababababababababababababababab"
  23.174 -    );
  23.175 -    cxstring longstrresult = CX_STR(
  23.176 -            "abababababababababababababababababababababababababababababababab"
  23.177 -            "abababababababababababababababababababababababababababababababab"
  23.178 -            "abababababababababababababababababababababababababababababababab"
  23.179 -            "abababababababababababababababababababababababababababababababab"
  23.180 -            "abababababababababababababababababababababababababababababababab"
  23.181 -            "abababababababababababababababababababababababababababababababab"
  23.182 -            "wxyz1234567890"
  23.183 -    );
  23.184 -
  23.185 -    cxstring notfound = cx_strstr(str, cx_str("no match"));
  23.186 -    EXPECT_EQ(notfound.length, 0);
  23.187 -
  23.188 -    cxstring result = cx_strstr(str, cx_str("match"));
  23.189 -    EXPECT_EQ(result.length, 20);
  23.190 -    EXPECT_STREQ(result.ptr, "match in this string");
  23.191 -
  23.192 -    result = cx_strstr(str, cx_str(""));
  23.193 -    EXPECT_EQ(result.length, str.length);
  23.194 -    EXPECT_STREQ(result.ptr, str.ptr);
  23.195 -
  23.196 -    result = cx_strstr(longstr, longstrpattern);
  23.197 -    EXPECT_EQ(result.length, longstrresult.length);
  23.198 -    EXPECT_STREQ(result.ptr, longstrresult.ptr);
  23.199 -
  23.200 -    // just for coverage, call the _m variant
  23.201 -    auto mstr = cx_strdup(longstr);
  23.202 -    auto m = cx_strstr_m(mstr, longstrpattern);
  23.203 -    EXPECT_EQ(m.length, longstrresult.length);
  23.204 -    EXPECT_STREQ(m.ptr, longstrresult.ptr);
  23.205 -    cx_strfree(&mstr);
  23.206 -}
  23.207 -
  23.208 -TEST(String, strcmp) {
  23.209 -    cxstring str = CX_STR("compare this");
  23.210 -
  23.211 -    EXPECT_EQ(cx_strcmp(cx_str(""), cx_str("")), 0);
  23.212 -    EXPECT_GT(cx_strcmp(str, cx_str("")), 0);
  23.213 -    EXPECT_EQ(cx_strcmp(str, cx_str("compare this")), 0);
  23.214 -    EXPECT_NE(cx_strcmp(str, cx_str("Compare This")), 0);
  23.215 -    EXPECT_LT(cx_strcmp(str, cx_str("compare tool")), 0);
  23.216 -    EXPECT_GT(cx_strcmp(str, cx_str("compare shit")), 0);
  23.217 -    EXPECT_LT(cx_strcmp(str, cx_str("compare this not")), 0);
  23.218 -    EXPECT_GT(cx_strcmp(str, cx_str("compare")), 0);
  23.219 -}
  23.220 -
  23.221 -TEST(String, strcasecmp) {
  23.222 -    cxstring str = CX_STR("compare this");
  23.223 -
  23.224 -    EXPECT_EQ(cx_strcasecmp(cx_str(""), cx_str("")), 0);
  23.225 -    EXPECT_GT(cx_strcasecmp(str, cx_str("")), 0);
  23.226 -    EXPECT_EQ(cx_strcasecmp(str, cx_str("compare this")), 0);
  23.227 -    EXPECT_EQ(cx_strcasecmp(str, cx_str("Compare This")), 0);
  23.228 -    EXPECT_LT(cx_strcasecmp(str, cx_str("compare tool")), 0);
  23.229 -    EXPECT_GT(cx_strcasecmp(str, cx_str("compare shit")), 0);
  23.230 -    EXPECT_LT(cx_strcasecmp(str, cx_str("compare this not")), 0);
  23.231 -    EXPECT_GT(cx_strcasecmp(str, cx_str("compare")), 0);
  23.232 -}
  23.233 -
  23.234 -TEST(String, strcat) {
  23.235 -    cxstring s1 = CX_STR("12");
  23.236 -    cxstring s2 = CX_STR("34");
  23.237 -    cxstring s3 = CX_STR("56");
  23.238 -    cxstring sn = {nullptr, 0};
  23.239 -
  23.240 -    CxTestingAllocator alloc;
  23.241 -
  23.242 -    cxmutstr t1 = cx_strcat_a(&alloc, 2, s1, s2);
  23.243 -    EXPECT_EQ(cx_strcmp(cx_strcast(t1), cx_str("1234")), 0);
  23.244 -    EXPECT_ZERO_TERMINATED(t1);
  23.245 -    cx_strfree_a(&alloc, &t1);
  23.246 -
  23.247 -    cxmutstr t2 = cx_strcat_a(&alloc, 3, s1, s2, s3);
  23.248 -    EXPECT_EQ(cx_strcmp(cx_strcast(t2), cx_str("123456")), 0);
  23.249 -    EXPECT_ZERO_TERMINATED(t2);
  23.250 -    cx_strfree_a(&alloc, &t2);
  23.251 -
  23.252 -    cxmutstr t3 = cx_strcat_a(&alloc, 6, s1, sn, s2, sn, s3, sn);
  23.253 -    EXPECT_EQ(cx_strcmp(cx_strcast(t3), cx_str("123456")), 0);
  23.254 -    EXPECT_ZERO_TERMINATED(t3);
  23.255 -    cx_strfree_a(&alloc, &t3);
  23.256 -
  23.257 -    cxmutstr t4 = cx_strcat_a(&alloc, 2, sn, sn);
  23.258 -    EXPECT_EQ(cx_strcmp(cx_strcast(t4), cx_str("")), 0);
  23.259 -    EXPECT_ZERO_TERMINATED(t4);
  23.260 -    cx_strfree_a(&alloc, &t4);
  23.261 -
  23.262 -    EXPECT_TRUE(alloc.verify());
  23.263 -
  23.264 -    // use the macro
  23.265 -    cxmutstr t5 = cx_strcat(3, s3, s1, s2);
  23.266 -    EXPECT_EQ(cx_strcmp(cx_strcast(t5), cx_str("561234")), 0);
  23.267 -    EXPECT_ZERO_TERMINATED(t5);
  23.268 -    cx_strfree(&t5);
  23.269 -}
  23.270 -
  23.271 -TEST(String, strsplit) {
  23.272 -
  23.273 -    cxstring test = cx_str("this,is,a,csv,string");
  23.274 -    size_t capa = 8;
  23.275 -    cxstring list[8];
  23.276 -    size_t n;
  23.277 -
  23.278 -    // special case: empty string
  23.279 -    n = cx_strsplit(test, cx_str(""), capa, list);
  23.280 -    ASSERT_EQ(n, 1);
  23.281 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  23.282 -
  23.283 -    // no delimiter occurrence
  23.284 -    n = cx_strsplit(test, cx_str("z"), capa, list);
  23.285 -    ASSERT_EQ(n, 1);
  23.286 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  23.287 -
  23.288 -    // partially matching delimiter
  23.289 -    n = cx_strsplit(test, cx_str("is,not"), capa, list);
  23.290 -    ASSERT_EQ(n, 1);
  23.291 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  23.292 -
  23.293 -    // matching single-char delimiter
  23.294 -    n = cx_strsplit(test, cx_str(","), capa, list);
  23.295 -    ASSERT_EQ(n, 5);
  23.296 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  23.297 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  23.298 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
  23.299 -    EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
  23.300 -    EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
  23.301 -
  23.302 -    // matching multi-char delimiter
  23.303 -    n = cx_strsplit(test, cx_str("is"), capa, list);
  23.304 -    ASSERT_EQ(n, 3);
  23.305 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  23.306 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
  23.307 -    EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
  23.308 -
  23.309 -    // bounded list using single-char delimiter
  23.310 -    n = cx_strsplit(test, cx_str(","), 3, list);
  23.311 -    ASSERT_EQ(n, 3);
  23.312 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  23.313 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  23.314 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  23.315 -
  23.316 -    // bounded list using multi-char delimiter
  23.317 -    n = cx_strsplit(test, cx_str("is"), 2, list);
  23.318 -    ASSERT_EQ(n, 2);
  23.319 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  23.320 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  23.321 -
  23.322 -    // start with delimiter
  23.323 -    n = cx_strsplit(test, cx_str("this"), capa, list);
  23.324 -    ASSERT_EQ(n, 2);
  23.325 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  23.326 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  23.327 -
  23.328 -    // end with delimiter
  23.329 -    n = cx_strsplit(test, cx_str("string"), capa, list);
  23.330 -    ASSERT_EQ(n, 2);
  23.331 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
  23.332 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  23.333 -
  23.334 -
  23.335 -    // end with delimiter exceed bound
  23.336 -    n = cx_strsplit(cx_str("a,b,c,"), cx_str(","), 3, list);
  23.337 -    ASSERT_EQ(n, 3);
  23.338 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
  23.339 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
  23.340 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
  23.341 -
  23.342 -    // exact match
  23.343 -    n = cx_strsplit(test, cx_str("this,is,a,csv,string"), capa, list);
  23.344 -    ASSERT_EQ(n, 2);
  23.345 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  23.346 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  23.347 -
  23.348 -    // string to be split is only substring
  23.349 -    n = cx_strsplit(test, cx_str("this,is,a,csv,string,with,extension"), capa, list);
  23.350 -    ASSERT_EQ(n, 1);
  23.351 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  23.352 -
  23.353 -    // subsequent encounter of delimiter (the string between is empty)
  23.354 -    n = cx_strsplit(test, cx_str("is,"), capa, list);
  23.355 -    ASSERT_EQ(n, 3);
  23.356 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  23.357 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  23.358 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  23.359 -
  23.360 -    // call the _m variant just for coverage
  23.361 -    auto mtest = cx_strdup(test);
  23.362 -    cxmutstr mlist[4];
  23.363 -    n = cx_strsplit_m(mtest, cx_str("is,"), 4, mlist);
  23.364 -    ASSERT_EQ(n, 3);
  23.365 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
  23.366 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
  23.367 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
  23.368 -    cx_strfree(&mtest);
  23.369 -}
  23.370 -
  23.371 -TEST(String, strsplit_a) {
  23.372 -    CxTestingAllocator alloc;
  23.373 -
  23.374 -    cxstring test = cx_str("this,is,a,csv,string");
  23.375 -    size_t capa = 8;
  23.376 -    cxstring *list;
  23.377 -    size_t n;
  23.378 -
  23.379 -    // special case: empty string
  23.380 -    n = cx_strsplit_a(&alloc, test, cx_str(""), capa, &list);
  23.381 -    ASSERT_EQ(n, 1);
  23.382 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  23.383 -    cxFree(&alloc, list);
  23.384 -
  23.385 -    // no delimiter occurrence
  23.386 -    n = cx_strsplit_a(&alloc, test, cx_str("z"), capa, &list);
  23.387 -    ASSERT_EQ(n, 1);
  23.388 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  23.389 -    cxFree(&alloc, list);
  23.390 -
  23.391 -    // partially matching delimiter
  23.392 -    n = cx_strsplit_a(&alloc, test, cx_str("is,not"), capa, &list);
  23.393 -    ASSERT_EQ(n, 1);
  23.394 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  23.395 -    cxFree(&alloc, list);
  23.396 -
  23.397 -    // matching single-char delimiter
  23.398 -    n = cx_strsplit_a(&alloc, test, cx_str(","), capa, &list);
  23.399 -    ASSERT_EQ(n, 5);
  23.400 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  23.401 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  23.402 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
  23.403 -    EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
  23.404 -    EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
  23.405 -    cxFree(&alloc, list);
  23.406 -
  23.407 -    // matching multi-char delimiter
  23.408 -    n = cx_strsplit_a(&alloc, test, cx_str("is"), capa, &list);
  23.409 -    ASSERT_EQ(n, 3);
  23.410 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  23.411 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
  23.412 -    EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
  23.413 -    cxFree(&alloc, list);
  23.414 -
  23.415 -    // bounded list using single-char delimiter
  23.416 -    n = cx_strsplit_a(&alloc, test, cx_str(","), 3, &list);
  23.417 -    ASSERT_EQ(n, 3);
  23.418 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  23.419 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  23.420 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  23.421 -    cxFree(&alloc, list);
  23.422 -
  23.423 -    // bounded list using multi-char delimiter
  23.424 -    n = cx_strsplit_a(&alloc, test, cx_str("is"), 2, &list);
  23.425 -    ASSERT_EQ(n, 2);
  23.426 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  23.427 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  23.428 -    cxFree(&alloc, list);
  23.429 -
  23.430 -    // start with delimiter
  23.431 -    n = cx_strsplit_a(&alloc, test, cx_str("this"), capa, &list);
  23.432 -    ASSERT_EQ(n, 2);
  23.433 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  23.434 -    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  23.435 -    cxFree(&alloc, list);
  23.436 -
  23.437 -    // end with delimiter
  23.438 -    n = cx_strsplit_a(&alloc, test, cx_str("string"), capa, &list);
  23.439 -    ASSERT_EQ(n, 2);
  23.440 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
  23.441 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  23.442 -    cxFree(&alloc, list);
  23.443 -
  23.444 -    // end with delimiter exceed bound
  23.445 -    n = cx_strsplit_a(&alloc, cx_str("a,b,c,"), cx_str(","), 3, &list);
  23.446 -    ASSERT_EQ(n, 3);
  23.447 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
  23.448 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
  23.449 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
  23.450 -    cxFree(&alloc, list);
  23.451 -
  23.452 -    // exact match
  23.453 -    n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string"), capa, &list);
  23.454 -    ASSERT_EQ(n, 2);
  23.455 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  23.456 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  23.457 -    cxFree(&alloc, list);
  23.458 -
  23.459 -    // string to be split is only substring
  23.460 -    n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string,with,extension"), capa, &list);
  23.461 -    ASSERT_EQ(n, 1);
  23.462 -    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  23.463 -    cxFree(&alloc, list);
  23.464 -
  23.465 -    // subsequent encounter of delimiter (the string between is empty)
  23.466 -    n = cx_strsplit_a(&alloc, test, cx_str("is,"), capa, &list);
  23.467 -    ASSERT_EQ(n, 3);
  23.468 -    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  23.469 -    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  23.470 -    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  23.471 -    cxFree(&alloc, list);
  23.472 -
  23.473 -    // call the _m variant just for coverage
  23.474 -    auto mtest = cx_strdup(test);
  23.475 -    cxmutstr *mlist;
  23.476 -    n = cx_strsplit_ma(&alloc, mtest, cx_str("is,"), 4, &mlist);
  23.477 -    ASSERT_EQ(n, 3);
  23.478 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
  23.479 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
  23.480 -    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
  23.481 -    cxFree(&alloc, mlist);
  23.482 -    cx_strfree(&mtest);
  23.483 -
  23.484 -    EXPECT_TRUE(alloc.verify());
  23.485 -}
  23.486 -
  23.487 -TEST(String, strtrim) {
  23.488 -    cxstring t1 = cx_strtrim(cx_str("  ein test  \t "));
  23.489 -    cxstring t2 = cx_strtrim(cx_str("abc"));
  23.490 -    cxstring t3 = cx_strtrim(cx_str(" 123"));
  23.491 -    cxstring t4 = cx_strtrim(cx_str("xyz "));
  23.492 -    cxstring t5 = cx_strtrim(cx_str("   "));
  23.493 -    cxstring empty = cx_strtrim(cx_str(""));
  23.494 -
  23.495 -    EXPECT_EQ(cx_strcmp(t1, cx_str("ein test")), 0);
  23.496 -    EXPECT_EQ(cx_strcmp(t2, cx_str("abc")), 0);
  23.497 -    EXPECT_EQ(cx_strcmp(t3, cx_str("123")), 0);
  23.498 -    EXPECT_EQ(cx_strcmp(t4, cx_str("xyz")), 0);
  23.499 -    EXPECT_EQ(cx_strcmp(t5, cx_str("")), 0);
  23.500 -    EXPECT_EQ(cx_strcmp(empty, cx_str("")), 0);
  23.501 -
  23.502 -    // call the _m variant just for coverage
  23.503 -    cxmutstr m1 = cx_strtrim_m(cx_mutstr((char *) "  ein test  \t "));
  23.504 -    EXPECT_EQ(cx_strcmp(cx_strcast(m1), cx_str("ein test")), 0);
  23.505 -}
  23.506 -
  23.507 -TEST(String, strprefix) {
  23.508 -    cxstring str = CX_STR("test my prefix and my suffix");
  23.509 -    cxstring empty = CX_STR("");
  23.510 -    EXPECT_FALSE(cx_strprefix(empty, cx_str("pref")));
  23.511 -    EXPECT_TRUE(cx_strprefix(str, empty));
  23.512 -    EXPECT_TRUE(cx_strprefix(empty, empty));
  23.513 -    EXPECT_TRUE(cx_strprefix(str, cx_str("test ")));
  23.514 -    EXPECT_FALSE(cx_strprefix(str, cx_str("8-) fsck ")));
  23.515 -}
  23.516 -
  23.517 -TEST(String, strsuffix) {
  23.518 -    cxstring str = CX_STR("test my prefix and my suffix");
  23.519 -    cxstring empty = CX_STR("");
  23.520 -    EXPECT_FALSE(cx_strsuffix(empty, cx_str("suf")));
  23.521 -    EXPECT_TRUE(cx_strsuffix(str, empty));
  23.522 -    EXPECT_TRUE(cx_strsuffix(empty, empty));
  23.523 -    EXPECT_TRUE(cx_strsuffix(str, cx_str("fix")));
  23.524 -    EXPECT_FALSE(cx_strsuffix(str, cx_str("fox")));
  23.525 -}
  23.526 -
  23.527 -TEST(String, strcaseprefix) {
  23.528 -    cxstring str = CX_STR("test my prefix and my suffix");
  23.529 -    cxstring empty = CX_STR("");
  23.530 -    EXPECT_FALSE(cx_strcaseprefix(empty, cx_str("pREf")));
  23.531 -    EXPECT_TRUE(cx_strcaseprefix(str, empty));
  23.532 -    EXPECT_TRUE(cx_strcaseprefix(empty, empty));
  23.533 -    EXPECT_TRUE(cx_strcaseprefix(str, cx_str("TEST ")));
  23.534 -    EXPECT_FALSE(cx_strcaseprefix(str, cx_str("8-) fsck ")));
  23.535 -}
  23.536 -
  23.537 -TEST(String, strcasesuffix) {
  23.538 -    cxstring str = CX_STR("test my prefix and my suffix");
  23.539 -    cxstring empty = CX_STR("");
  23.540 -    EXPECT_FALSE(cx_strcasesuffix(empty, cx_str("sUf")));
  23.541 -    EXPECT_TRUE(cx_strcasesuffix(str, empty));
  23.542 -    EXPECT_TRUE(cx_strcasesuffix(empty, empty));
  23.543 -    EXPECT_TRUE(cx_strcasesuffix(str, cx_str("FIX")));
  23.544 -    EXPECT_FALSE(cx_strcasesuffix(str, cx_str("fox")));
  23.545 -}
  23.546 -
  23.547 -TEST(String, strreplace) {
  23.548 -    CxTestingAllocator alloc;
  23.549 -    cxstring str = CX_STR("test ababab string aba");
  23.550 -    cxstring longstr = CX_STR(
  23.551 -            "xyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacd");
  23.552 -    cxstring notrail = CX_STR("test abab");
  23.553 -    cxstring empty = CX_STR("");
  23.554 -    cxstring astr = CX_STR("aaaaaaaaaa");
  23.555 -    cxstring csstr = CX_STR("test AB ab TEST xyz");
  23.556 -
  23.557 -    cxmutstr repl = cx_strreplace(str, cx_str("abab"), cx_str("muchlonger"));
  23.558 -    auto expected = "test muchlongerab string aba";
  23.559 -
  23.560 -    cxmutstr repln = cx_strreplacen(str, cx_str("ab"), cx_str("c"), 2);
  23.561 -    auto expectedn = "test ccab string aba";
  23.562 -
  23.563 -    cxmutstr longrepl = cx_strreplace(longstr, cx_str("a"), cx_str("z"));
  23.564 -    auto longexpect = "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd";
  23.565 -
  23.566 -    cxmutstr replnotrail = cx_strreplace(notrail, cx_str("ab"), cx_str("z"));
  23.567 -    auto notrailexpect = "test zz";
  23.568 -
  23.569 -    cxmutstr repleq = cx_strreplace(str, str, cx_str("hello"));
  23.570 -    auto eqexpect = "hello";
  23.571 -
  23.572 -    cxmutstr replempty1 = cx_strreplace(empty, cx_str("ab"), cx_str("c")); // expect: empty
  23.573 -    cxmutstr replempty2 = cx_strreplace(str, cx_str("abab"), empty);
  23.574 -    auto emptyexpect2 = "test ab string aba";
  23.575 -
  23.576 -    cxmutstr replpre = cx_strreplace(str, cx_str("test "), cx_str("TEST "));
  23.577 -    auto preexpected = "TEST ababab string aba";
  23.578 -
  23.579 -    cxmutstr replan1 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 1);
  23.580 -    auto an1expected = "xaaaaaaaaa";
  23.581 -
  23.582 -    cxmutstr replan4 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 4);
  23.583 -    auto an4expected = "xxxxaaaaaa";
  23.584 -
  23.585 -    cxmutstr replan9 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 9);
  23.586 -    auto an9expected = "xxxxxxxxxa";
  23.587 -
  23.588 -    cxmutstr replan10 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 10);
  23.589 -    auto an10expected = "xxxxxxxxxx";
  23.590 -
  23.591 -    cxmutstr repl1_a = cx_strreplace_a(&alloc, csstr, cx_str("AB"), cx_str("*"));
  23.592 -    auto expeced1_a = "test * ab TEST xyz";
  23.593 -
  23.594 -    cxmutstr repl2_a = cx_strreplace_a(&alloc, csstr, cx_str("test"), cx_str("TEST"));
  23.595 -    auto expected2_a = "TEST AB ab TEST xyz";
  23.596 -
  23.597 -
  23.598 -    EXPECT_NE(repl.ptr, str.ptr);
  23.599 -    EXPECT_ZERO_TERMINATED(repl);
  23.600 -    EXPECT_STREQ(repl.ptr, expected);
  23.601 -    EXPECT_ZERO_TERMINATED(repln);
  23.602 -    EXPECT_STREQ(repln.ptr, expectedn);
  23.603 -    EXPECT_ZERO_TERMINATED(longrepl);
  23.604 -    EXPECT_STREQ(longrepl.ptr, longexpect);
  23.605 -    EXPECT_ZERO_TERMINATED(replnotrail);
  23.606 -    EXPECT_STREQ(replnotrail.ptr, notrailexpect);
  23.607 -    EXPECT_ZERO_TERMINATED(repleq);
  23.608 -    EXPECT_STREQ(repleq.ptr, eqexpect);
  23.609 -    EXPECT_ZERO_TERMINATED(replempty1);
  23.610 -    EXPECT_STREQ(replempty1.ptr, "");
  23.611 -    EXPECT_ZERO_TERMINATED(replempty2);
  23.612 -    EXPECT_STREQ(replempty2.ptr, emptyexpect2);
  23.613 -    EXPECT_ZERO_TERMINATED(replpre);
  23.614 -    EXPECT_STREQ(replpre.ptr, preexpected);
  23.615 -    EXPECT_ZERO_TERMINATED(replan1);
  23.616 -    EXPECT_STREQ(replan1.ptr, an1expected);
  23.617 -    EXPECT_ZERO_TERMINATED(replan4);
  23.618 -    EXPECT_STREQ(replan4.ptr, an4expected);
  23.619 -    EXPECT_ZERO_TERMINATED(replan9);
  23.620 -    EXPECT_STREQ(replan9.ptr, an9expected);
  23.621 -    EXPECT_ZERO_TERMINATED(replan10);
  23.622 -    EXPECT_STREQ(replan10.ptr, an10expected);
  23.623 -    EXPECT_ZERO_TERMINATED(repl1_a);
  23.624 -    EXPECT_STREQ(repl1_a.ptr, expeced1_a);
  23.625 -    EXPECT_ZERO_TERMINATED(repl2_a);
  23.626 -    EXPECT_STREQ(repl2_a.ptr, expected2_a);
  23.627 -
  23.628 -    cx_strfree(&repl);
  23.629 -    cx_strfree(&repln);
  23.630 -    cx_strfree(&longrepl);
  23.631 -    cx_strfree(&replnotrail);
  23.632 -    cx_strfree(&repleq);
  23.633 -    cx_strfree(&replempty1);
  23.634 -    cx_strfree(&replempty2);
  23.635 -    cx_strfree(&replpre);
  23.636 -    cx_strfree(&replan1);
  23.637 -    cx_strfree(&replan4);
  23.638 -    cx_strfree(&replan9);
  23.639 -    cx_strfree(&replan10);
  23.640 -
  23.641 -    cx_strfree_a(&alloc, &repl1_a);
  23.642 -    cx_strfree_a(&alloc, &repl2_a);
  23.643 -    EXPECT_TRUE(alloc.verify());
  23.644 -}
  23.645 -
  23.646 -TEST(String, strupper) {
  23.647 -    cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
  23.648 -    cx_strupper(str);
  23.649 -    EXPECT_STREQ(str.ptr, "THIS 1S @ TE$T");
  23.650 -    cx_strfree(&str);
  23.651 -}
  23.652 -
  23.653 -TEST(String, strlower) {
  23.654 -    cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
  23.655 -    cx_strlower(str);
  23.656 -    EXPECT_STREQ(str.ptr, "this 1s @ te$t");
  23.657 -    cx_strfree(&str);
  23.658 -}
  23.659 -
  23.660 -TEST(String, strtok) {
  23.661 -    cxstring str = cx_str("a,comma,separated,string");
  23.662 -    cxstring delim = cx_str(",");
  23.663 -    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  23.664 -    EXPECT_EQ(ctx.str.ptr, str.ptr);
  23.665 -    EXPECT_EQ(ctx.str.length, str.length);
  23.666 -    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  23.667 -    EXPECT_EQ(ctx.delim.length, delim.length);
  23.668 -    EXPECT_EQ(ctx.limit, 3);
  23.669 -    EXPECT_EQ(ctx.found, 0);
  23.670 -    EXPECT_EQ(ctx.pos, 0);
  23.671 -    EXPECT_EQ(ctx.next_pos, 0);
  23.672 -    EXPECT_EQ(ctx.delim_more, nullptr);
  23.673 -    EXPECT_EQ(ctx.delim_more_count, 0);
  23.674 -}
  23.675 -
  23.676 -TEST(String, strtok_m) {
  23.677 -    cxmutstr str = cx_strdup(cx_str("a,comma,separated,string"));
  23.678 -    cxstring delim = cx_str(",");
  23.679 -    CxStrtokCtx ctx = cx_strtok_m(str, delim, 3);
  23.680 -    EXPECT_EQ(ctx.str.ptr, str.ptr);
  23.681 -    EXPECT_EQ(ctx.str.length, str.length);
  23.682 -    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  23.683 -    EXPECT_EQ(ctx.delim.length, delim.length);
  23.684 -    EXPECT_EQ(ctx.limit, 3);
  23.685 -    EXPECT_EQ(ctx.found, 0);
  23.686 -    EXPECT_EQ(ctx.pos, 0);
  23.687 -    EXPECT_EQ(ctx.next_pos, 0);
  23.688 -    EXPECT_EQ(ctx.delim_more, nullptr);
  23.689 -    EXPECT_EQ(ctx.delim_more_count, 0);
  23.690 -    cx_strfree(&str);
  23.691 -}
  23.692 -
  23.693 -TEST(String, strtok_delim) {
  23.694 -    cxstring str = cx_str("an,arbitrarily|separated;string");
  23.695 -    cxstring delim = cx_str(",");
  23.696 -    cxstring delim_more[2] = {CX_STR("|"), CX_STR(";")};
  23.697 -    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  23.698 -    cx_strtok_delim(&ctx, delim_more, 2);
  23.699 -    EXPECT_EQ(ctx.str.ptr, str.ptr);
  23.700 -    EXPECT_EQ(ctx.str.length, str.length);
  23.701 -    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  23.702 -    EXPECT_EQ(ctx.delim.length, delim.length);
  23.703 -    EXPECT_EQ(ctx.limit, 3);
  23.704 -    EXPECT_EQ(ctx.found, 0);
  23.705 -    EXPECT_EQ(ctx.pos, 0);
  23.706 -    EXPECT_EQ(ctx.next_pos, 0);
  23.707 -    EXPECT_EQ(ctx.delim_more, delim_more);
  23.708 -    EXPECT_EQ(ctx.delim_more_count, 2);
  23.709 -}
  23.710 -
  23.711 -TEST(String, strtok_next_easy) {
  23.712 -    cxstring str = cx_str("a,comma,separated,string");
  23.713 -    cxstring delim = cx_str(",");
  23.714 -    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  23.715 -    bool ret;
  23.716 -    cxstring tok;
  23.717 -
  23.718 -    ret = cx_strtok_next(&ctx, &tok);
  23.719 -    ASSERT_TRUE(ret);
  23.720 -    EXPECT_EQ(cx_strcmp(tok, cx_str("a")), 0);
  23.721 -    EXPECT_EQ(ctx.pos, 0);
  23.722 -    EXPECT_EQ(ctx.next_pos, 2);
  23.723 -    EXPECT_EQ(ctx.delim_pos, 1);
  23.724 -    EXPECT_EQ(ctx.found, 1);
  23.725 -
  23.726 -    ret = cx_strtok_next(&ctx, &tok);
  23.727 -    ASSERT_TRUE(ret);
  23.728 -    EXPECT_EQ(cx_strcmp(tok, cx_str("comma")), 0);
  23.729 -    EXPECT_EQ(ctx.pos, 2);
  23.730 -    EXPECT_EQ(ctx.next_pos, 8);
  23.731 -    EXPECT_EQ(ctx.delim_pos, 7);
  23.732 -    EXPECT_EQ(ctx.found, 2);
  23.733 -
  23.734 -    ret = cx_strtok_next(&ctx, &tok);
  23.735 -    ASSERT_TRUE(ret);
  23.736 -    EXPECT_EQ(cx_strcmp(tok, cx_str("separated")), 0);
  23.737 -    EXPECT_EQ(ctx.pos, 8);
  23.738 -    EXPECT_EQ(ctx.next_pos, 18);
  23.739 -    EXPECT_EQ(ctx.delim_pos, 17);
  23.740 -    EXPECT_EQ(ctx.found, 3);
  23.741 -
  23.742 -    ret = cx_strtok_next(&ctx, &tok);
  23.743 -    ASSERT_FALSE(ret);
  23.744 -    EXPECT_EQ(ctx.pos, 8);
  23.745 -    EXPECT_EQ(ctx.next_pos, 18);
  23.746 -    EXPECT_EQ(ctx.delim_pos, 17);
  23.747 -    EXPECT_EQ(ctx.found, 3);
  23.748 -}
  23.749 -
  23.750 -TEST(String, strtok_next_unlimited) {
  23.751 -    cxstring str = cx_str("some;-;otherwise;-;separated;-;string;-;");
  23.752 -    cxstring delim = cx_str(";-;");
  23.753 -    CxStrtokCtx ctx = cx_strtok(str, delim, SIZE_MAX);
  23.754 -    bool ret;
  23.755 -    cxstring tok;
  23.756 -
  23.757 -    ret = cx_strtok_next(&ctx, &tok);
  23.758 -    ASSERT_TRUE(ret);
  23.759 -    EXPECT_EQ(cx_strcmp(tok, cx_str("some")), 0);
  23.760 -    EXPECT_EQ(ctx.pos, 0);
  23.761 -    EXPECT_EQ(ctx.next_pos, 7);
  23.762 -    EXPECT_EQ(ctx.delim_pos, 4);
  23.763 -    EXPECT_EQ(ctx.found, 1);
  23.764 -
  23.765 -    ret = cx_strtok_next(&ctx, &tok);
  23.766 -    ASSERT_TRUE(ret);
  23.767 -    EXPECT_EQ(cx_strcmp(tok, cx_str("otherwise")), 0);
  23.768 -    EXPECT_EQ(ctx.pos, 7);
  23.769 -    EXPECT_EQ(ctx.next_pos, 19);
  23.770 -    EXPECT_EQ(ctx.delim_pos, 16);
  23.771 -    EXPECT_EQ(ctx.found, 2);
  23.772 -
  23.773 -    ret = cx_strtok_next(&ctx, &tok);
  23.774 -    ASSERT_TRUE(ret);
  23.775 -    EXPECT_EQ(cx_strcmp(tok, cx_str("separated")), 0);
  23.776 -    EXPECT_EQ(ctx.pos, 19);
  23.777 -    EXPECT_EQ(ctx.next_pos, 31);
  23.778 -    EXPECT_EQ(ctx.delim_pos, 28);
  23.779 -    EXPECT_EQ(ctx.found, 3);
  23.780 -
  23.781 -    ret = cx_strtok_next(&ctx, &tok);
  23.782 -    ASSERT_TRUE(ret);
  23.783 -    EXPECT_EQ(cx_strcmp(tok, cx_str("string")), 0);
  23.784 -    EXPECT_EQ(ctx.pos, 31);
  23.785 -    EXPECT_EQ(ctx.next_pos, 40);
  23.786 -    EXPECT_EQ(ctx.delim_pos, 37);
  23.787 -    EXPECT_EQ(ctx.found, 4);
  23.788 -
  23.789 -    ret = cx_strtok_next(&ctx, &tok);
  23.790 -    ASSERT_TRUE(ret);
  23.791 -    EXPECT_EQ(cx_strcmp(tok, cx_str("")), 0);
  23.792 -    EXPECT_EQ(ctx.pos, 40);
  23.793 -    EXPECT_EQ(ctx.next_pos, 40);
  23.794 -    EXPECT_EQ(ctx.delim_pos, 40);
  23.795 -    EXPECT_EQ(ctx.found, 5);
  23.796 -
  23.797 -    ret = cx_strtok_next(&ctx, &tok);
  23.798 -    ASSERT_FALSE(ret);
  23.799 -    EXPECT_EQ(ctx.pos, 40);
  23.800 -    EXPECT_EQ(ctx.delim_pos, 40);
  23.801 -    EXPECT_EQ(ctx.found, 5);
  23.802 -}
  23.803 -
  23.804 -TEST(String, strtok_next_advanced) {
  23.805 -    cxmutstr str = cx_strdup(cx_str("an,arbitrarily;||separated;string"));
  23.806 -    cxstring delim = cx_str(",");
  23.807 -    cxstring delim_more[2] = {CX_STR("||"), CX_STR(";")};
  23.808 -    CxStrtokCtx ctx = cx_strtok_m(str, delim, 10);
  23.809 -    cx_strtok_delim(&ctx, delim_more, 2);
  23.810 -    bool ret;
  23.811 -    cxmutstr tok;
  23.812 -
  23.813 -    ret = cx_strtok_next_m(&ctx, &tok);
  23.814 -    ASSERT_TRUE(ret);
  23.815 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("an")), 0);
  23.816 -    EXPECT_EQ(ctx.pos, 0);
  23.817 -    EXPECT_EQ(ctx.next_pos, 3);
  23.818 -    EXPECT_EQ(ctx.delim_pos, 2);
  23.819 -    EXPECT_EQ(ctx.found, 1);
  23.820 -    cx_strupper(tok);
  23.821 -
  23.822 -    ret = cx_strtok_next_m(&ctx, &tok);
  23.823 -    ASSERT_TRUE(ret);
  23.824 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("arbitrarily")), 0);
  23.825 -    EXPECT_EQ(ctx.pos, 3);
  23.826 -    EXPECT_EQ(ctx.next_pos, 15);
  23.827 -    EXPECT_EQ(ctx.delim_pos, 14);
  23.828 -    EXPECT_EQ(ctx.found, 2);
  23.829 -    cx_strupper(tok);
  23.830 -
  23.831 -    ret = cx_strtok_next_m(&ctx, &tok);
  23.832 -    ASSERT_TRUE(ret);
  23.833 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("")), 0);
  23.834 -    EXPECT_EQ(ctx.pos, 15);
  23.835 -    EXPECT_EQ(ctx.next_pos, 17);
  23.836 -    EXPECT_EQ(ctx.delim_pos, 15);
  23.837 -    EXPECT_EQ(ctx.found, 3);
  23.838 -    cx_strupper(tok);
  23.839 -
  23.840 -    ret = cx_strtok_next_m(&ctx, &tok);
  23.841 -    ASSERT_TRUE(ret);
  23.842 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("separated")), 0);
  23.843 -    EXPECT_EQ(ctx.pos, 17);
  23.844 -    EXPECT_EQ(ctx.next_pos, 27);
  23.845 -    EXPECT_EQ(ctx.delim_pos, 26);
  23.846 -    EXPECT_EQ(ctx.found, 4);
  23.847 -    cx_strupper(tok);
  23.848 -
  23.849 -    ret = cx_strtok_next_m(&ctx, &tok);
  23.850 -    ASSERT_TRUE(ret);
  23.851 -    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("string")), 0);
  23.852 -    EXPECT_EQ(ctx.pos, 27);
  23.853 -    EXPECT_EQ(ctx.next_pos, 33);
  23.854 -    EXPECT_EQ(ctx.delim_pos, 33);
  23.855 -    EXPECT_EQ(ctx.found, 5);
  23.856 -    cx_strupper(tok);
  23.857 -
  23.858 -    ret = cx_strtok_next_m(&ctx, &tok);
  23.859 -    ASSERT_FALSE(ret);
  23.860 -    EXPECT_EQ(ctx.pos, 27);
  23.861 -    EXPECT_EQ(ctx.next_pos, 33);
  23.862 -    EXPECT_EQ(ctx.delim_pos, 33);
  23.863 -    EXPECT_EQ(ctx.found, 5);
  23.864 -
  23.865 -    EXPECT_EQ(cx_strcmp(cx_strcast(str), cx_str("AN,ARBITRARILY;||SEPARATED;STRING")), 0);
  23.866 -
  23.867 -    cx_strfree(&str);
  23.868 -}
    24.1 --- a/test/test_tree.cpp	Wed Feb 08 20:26:09 2023 +0100
    24.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.3 @@ -1,122 +0,0 @@
    24.4 -/*
    24.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    24.6 - *
    24.7 - * Copyright 2021 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/tree.h"
   24.33 -#include <gtest/gtest.h>
   24.34 -
   24.35 -struct TestNode {
   24.36 -    TestNode *parent = nullptr;
   24.37 -    TestNode *prev = nullptr;
   24.38 -    TestNode *next = nullptr;
   24.39 -
   24.40 -    TestNode *children_begin = nullptr;
   24.41 -    TestNode *children_end = nullptr;
   24.42 -};
   24.43 -
   24.44 -TEST(Tree, cx_tree_add_sibling) {
   24.45 -    // prepare test tree
   24.46 -    TestNode root, a;
   24.47 -    root.children_begin = &a;
   24.48 -    root.children_end = &a;
   24.49 -    a.parent = &root;
   24.50 -
   24.51 -    // new test nodes
   24.52 -    TestNode b, c;
   24.53 -
   24.54 -    // test
   24.55 -    cx_tree_add_sibling(&a, offsetof(TestNode, prev), offsetof(TestNode, next), offsetof(TestNode, parent), &b);
   24.56 -    EXPECT_EQ(b.parent, &root);
   24.57 -    EXPECT_EQ(b.prev, &a);
   24.58 -    EXPECT_EQ(b.next, nullptr);
   24.59 -    EXPECT_EQ(a.next, &b);
   24.60 -
   24.61 -    cx_tree_add_sibling(&a, -1, offsetof(TestNode, next), -1, &c);
   24.62 -    EXPECT_EQ(c.parent, nullptr);
   24.63 -    EXPECT_EQ(c.prev, nullptr);
   24.64 -    EXPECT_EQ(c.next, nullptr);
   24.65 -    EXPECT_EQ(b.next, &c);
   24.66 -}
   24.67 -
   24.68 -TEST(Tree, cx_tree_add_child) {
   24.69 -    TestNode root, a, b, c, a1;
   24.70 -
   24.71 -    cx_tree_add_child(
   24.72 -            (void **) &root.children_begin,
   24.73 -            (void **) &root.children_end,
   24.74 -            offsetof(TestNode, prev),
   24.75 -            offsetof(TestNode, next),
   24.76 -            &a,
   24.77 -            offsetof(TestNode, parent),
   24.78 -            &root);
   24.79 -    EXPECT_EQ(root.children_begin, &a);
   24.80 -    EXPECT_EQ(root.children_end, &a);
   24.81 -    EXPECT_EQ(a.parent, &root);
   24.82 -    EXPECT_EQ(a.prev, nullptr);
   24.83 -    EXPECT_EQ(a.next, nullptr);
   24.84 -
   24.85 -    cx_tree_add_child(
   24.86 -            (void **) &root.children_begin,
   24.87 -            (void **) &root.children_end,
   24.88 -            offsetof(TestNode, prev),
   24.89 -            offsetof(TestNode, next),
   24.90 -            &b,
   24.91 -            offsetof(TestNode, parent),
   24.92 -            &root);
   24.93 -    EXPECT_EQ(root.children_begin, &a);
   24.94 -    EXPECT_EQ(root.children_begin->next, &b);
   24.95 -    EXPECT_EQ(root.children_end, &b);
   24.96 -    EXPECT_EQ(b.parent, &root);
   24.97 -    EXPECT_EQ(b.prev, &a);
   24.98 -
   24.99 -    cx_tree_add_child(
  24.100 -            (void **) &root.children_begin,
  24.101 -            nullptr,
  24.102 -            -1,
  24.103 -            offsetof(TestNode, next),
  24.104 -            &c,
  24.105 -            -1,
  24.106 -            &root);
  24.107 -    EXPECT_EQ(root.children_end, &b); // children_end unchanged
  24.108 -    EXPECT_EQ(b.next, &c);
  24.109 -    EXPECT_EQ(c.prev, nullptr);
  24.110 -    EXPECT_EQ(c.next, nullptr);
  24.111 -    EXPECT_EQ(c.parent, nullptr);
  24.112 -
  24.113 -    cx_tree_add_child(
  24.114 -            (void **) &a.children_begin,
  24.115 -            (void **) &a.children_end,
  24.116 -            offsetof(TestNode, prev),
  24.117 -            offsetof(TestNode, next),
  24.118 -            &a1,
  24.119 -            offsetof(TestNode, parent),
  24.120 -            &a);
  24.121 -    EXPECT_EQ(a.children_begin, &a1);
  24.122 -    EXPECT_EQ(a1.parent, &a);
  24.123 -    EXPECT_EQ(root.children_begin, &a);
  24.124 -    EXPECT_EQ(root.children_begin->children_begin, &a1);
  24.125 -}
    25.1 --- a/test/test_utils.cpp	Wed Feb 08 20:26:09 2023 +0100
    25.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.3 @@ -1,165 +0,0 @@
    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/utils.h"
   25.33 -
   25.34 -#include <gtest/gtest.h>
   25.35 -
   25.36 -TEST(Utils, ForN) {
   25.37 -    unsigned j;
   25.38 -    j = 0;
   25.39 -    cx_for_n(i, 50) {
   25.40 -        EXPECT_EQ(i, j);
   25.41 -        j++;
   25.42 -    }
   25.43 -}
   25.44 -
   25.45 -TEST(Utils, swap_ptr) {
   25.46 -    int i = 5;
   25.47 -    int j = 8;
   25.48 -    int *ip = &i;
   25.49 -    int *jp = &j;
   25.50 -    cx_swap_ptr(ip, jp);
   25.51 -    EXPECT_EQ(ip, &j);
   25.52 -    EXPECT_EQ(jp, &i);
   25.53 -}
   25.54 -
   25.55 -TEST(Utils, szmul) {
   25.56 -    size_t r;
   25.57 -    int e;
   25.58 -    e = cx_szmul(5, 7, &r);
   25.59 -    EXPECT_EQ(0, e);
   25.60 -    EXPECT_EQ(35, r);
   25.61 -
   25.62 -    size_t s = SIZE_MAX & ~3;
   25.63 -
   25.64 -    e = cx_szmul(s / 4, 2, &r);
   25.65 -    EXPECT_EQ(0, e);
   25.66 -    EXPECT_EQ(s / 2, r);
   25.67 -    e = cx_szmul(2, s / 4, &r);
   25.68 -    EXPECT_EQ(0, e);
   25.69 -    EXPECT_EQ(s / 2, r);
   25.70 -
   25.71 -    e = cx_szmul(s / 4, 4, &r);
   25.72 -    EXPECT_EQ(0, e);
   25.73 -    EXPECT_EQ(s, r);
   25.74 -
   25.75 -    e = cx_szmul(4, s / 4, &r);
   25.76 -    EXPECT_EQ(0, e);
   25.77 -    EXPECT_EQ(s, r);
   25.78 -
   25.79 -    e = cx_szmul(s / 4, 5, &r);
   25.80 -    EXPECT_NE(0, e);
   25.81 -
   25.82 -    e = cx_szmul(5, s / 4, &r);
   25.83 -    EXPECT_NE(0, e);
   25.84 -
   25.85 -    e = cx_szmul(SIZE_MAX - 4, 0, &r);
   25.86 -    EXPECT_EQ(0, e);
   25.87 -    EXPECT_EQ(0, r);
   25.88 -
   25.89 -    e = cx_szmul(0, SIZE_MAX - 1, &r);
   25.90 -    EXPECT_EQ(0, e);
   25.91 -    EXPECT_EQ(0, r);
   25.92 -
   25.93 -    e = cx_szmul(SIZE_MAX, 0, &r);
   25.94 -    EXPECT_EQ(0, e);
   25.95 -    EXPECT_EQ(0, r);
   25.96 -
   25.97 -    e = cx_szmul(0, SIZE_MAX, &r);
   25.98 -    EXPECT_EQ(0, e);
   25.99 -    EXPECT_EQ(0, r);
  25.100 -
  25.101 -    e = cx_szmul(0, 0, &r);
  25.102 -    EXPECT_EQ(0, e);
  25.103 -    EXPECT_EQ(0, r);
  25.104 -}
  25.105 -
  25.106 -#ifdef CX_SZMUL_BUILTIN
  25.107 -
  25.108 -// also test the custom implementation
  25.109 -struct Utils_szmul_impl : ::testing::Test {
  25.110 -#undef CX_SZMUL_BUILTIN
  25.111 -
  25.112 -#include "../src/utils.c"
  25.113 -
  25.114 -#define CX_SZMUL_BUILTIN
  25.115 -};
  25.116 -
  25.117 -TEST_F(Utils_szmul_impl, Test) {
  25.118 -    size_t r;
  25.119 -    int e;
  25.120 -    e = cx_szmul_impl(5, 7, &r);
  25.121 -    EXPECT_EQ(0, e);
  25.122 -    EXPECT_EQ(35, r);
  25.123 -
  25.124 -    size_t s = SIZE_MAX & ~3;
  25.125 -
  25.126 -    e = cx_szmul_impl(s / 4, 2, &r);
  25.127 -    EXPECT_EQ(0, e);
  25.128 -    EXPECT_EQ(s / 2, r);
  25.129 -    e = cx_szmul_impl(2, s / 4, &r);
  25.130 -    EXPECT_EQ(0, e);
  25.131 -    EXPECT_EQ(s / 2, r);
  25.132 -
  25.133 -    e = cx_szmul_impl(s / 4, 4, &r);
  25.134 -    EXPECT_EQ(0, e);
  25.135 -    EXPECT_EQ(s, r);
  25.136 -
  25.137 -    e = cx_szmul_impl(4, s / 4, &r);
  25.138 -    EXPECT_EQ(0, e);
  25.139 -    EXPECT_EQ(s, r);
  25.140 -
  25.141 -    e = cx_szmul_impl(s / 4, 5, &r);
  25.142 -    EXPECT_NE(0, e);
  25.143 -
  25.144 -    e = cx_szmul_impl(5, s / 4, &r);
  25.145 -    EXPECT_NE(0, e);
  25.146 -
  25.147 -    e = cx_szmul_impl(SIZE_MAX - 4, 0, &r);
  25.148 -    EXPECT_EQ(0, e);
  25.149 -    EXPECT_EQ(0, r);
  25.150 -
  25.151 -    e = cx_szmul_impl(0, SIZE_MAX - 1, &r);
  25.152 -    EXPECT_EQ(0, e);
  25.153 -    EXPECT_EQ(0, r);
  25.154 -
  25.155 -    e = cx_szmul_impl(SIZE_MAX, 0, &r);
  25.156 -    EXPECT_EQ(0, e);
  25.157 -    EXPECT_EQ(0, r);
  25.158 -
  25.159 -    e = cx_szmul_impl(0, SIZE_MAX, &r);
  25.160 -    EXPECT_EQ(0, e);
  25.161 -    EXPECT_EQ(0, r);
  25.162 -
  25.163 -    e = cx_szmul_impl(0, 0, &r);
  25.164 -    EXPECT_EQ(0, e);
  25.165 -    EXPECT_EQ(0, r);
  25.166 -}
  25.167 -
  25.168 -#endif // CX_SZMUL_BUILTIN
    26.1 --- a/test/util_allocator.cpp	Wed Feb 08 20:26:09 2023 +0100
    26.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.3 @@ -1,167 +0,0 @@
    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 "util_allocator.h"
   26.33 -
   26.34 -void *cx_malloc_testing(void *d, size_t n) {
   26.35 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   26.36 -    void *ptr = malloc(n);
   26.37 -    data->alloc_total++;
   26.38 -    if (ptr == nullptr) {
   26.39 -        data->alloc_failed++;
   26.40 -    } else {
   26.41 -        data->tracked.insert(ptr);
   26.42 -    }
   26.43 -    return ptr;
   26.44 -}
   26.45 -
   26.46 -void *cx_realloc_testing(void *d, void *mem, size_t n) {
   26.47 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   26.48 -    void *ptr = realloc(mem, n);
   26.49 -    if (ptr == mem) {
   26.50 -        return ptr;
   26.51 -    } else {
   26.52 -        data->alloc_total++;
   26.53 -        if (ptr == nullptr) {
   26.54 -            data->alloc_failed++;
   26.55 -        } else {
   26.56 -            data->free_total++;
   26.57 -            if (data->tracked.erase(mem) == 0) {
   26.58 -                data->free_failed++;
   26.59 -            }
   26.60 -            data->tracked.insert(ptr);
   26.61 -        }
   26.62 -        return ptr;
   26.63 -    }
   26.64 -}
   26.65 -
   26.66 -void *cx_calloc_testing(void *d, size_t nelem, size_t n) {
   26.67 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   26.68 -    void *ptr = calloc(nelem, n);
   26.69 -    data->alloc_total++;
   26.70 -    if (ptr == nullptr) {
   26.71 -        data->alloc_failed++;
   26.72 -    } else {
   26.73 -        data->tracked.insert(ptr);
   26.74 -    }
   26.75 -    return ptr;
   26.76 -}
   26.77 -
   26.78 -void cx_free_testing(void *d, void *mem) {
   26.79 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   26.80 -    data->free_total++;
   26.81 -    if (data->tracked.erase(mem) == 0) {
   26.82 -        data->free_failed++;
   26.83 -        // do not even attempt to free mem, because it is likely to segfault
   26.84 -    } else {
   26.85 -        free(mem);
   26.86 -    }
   26.87 -}
   26.88 -
   26.89 -cx_allocator_class cx_testing_allocator_class = {
   26.90 -        cx_malloc_testing,
   26.91 -        cx_realloc_testing,
   26.92 -        cx_calloc_testing,
   26.93 -        cx_free_testing
   26.94 -};
   26.95 -
   26.96 -CxTestingAllocator::CxTestingAllocator() : CxAllocator() {
   26.97 -    cl = &cx_testing_allocator_class;
   26.98 -    data = this;
   26.99 -}
  26.100 -
  26.101 -bool CxTestingAllocator::used() const {
  26.102 -    return alloc_total > 0;
  26.103 -}
  26.104 -
  26.105 -bool CxTestingAllocator::verify() const {
  26.106 -    return tracked.empty() && alloc_failed == 0 && free_failed == 0 && alloc_total == free_total;
  26.107 -}
  26.108 -
  26.109 -// SELF-TEST
  26.110 -
  26.111 -#include <gtest/gtest.h>
  26.112 -
  26.113 -TEST(TestingAllocator, ExpectFree) {
  26.114 -    CxTestingAllocator allocator;
  26.115 -
  26.116 -    ASSERT_TRUE(allocator.verify());
  26.117 -    EXPECT_FALSE(allocator.used());
  26.118 -    auto ptr = cxMalloc(&allocator, 16);
  26.119 -    EXPECT_TRUE(allocator.used());
  26.120 -    ASSERT_NE(ptr, nullptr);
  26.121 -    EXPECT_FALSE(allocator.verify());
  26.122 -
  26.123 -    cxFree(&allocator, ptr);
  26.124 -    EXPECT_TRUE(allocator.verify());
  26.125 -}
  26.126 -
  26.127 -TEST(TestingAllocator, DetectDoubleFree) {
  26.128 -    CxTestingAllocator allocator;
  26.129 -
  26.130 -    ASSERT_TRUE(allocator.verify());
  26.131 -    auto ptr = cxMalloc(&allocator, 16);
  26.132 -    ASSERT_NE(ptr, nullptr);
  26.133 -
  26.134 -    cxFree(&allocator, ptr);
  26.135 -    EXPECT_TRUE(allocator.verify());
  26.136 -    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
  26.137 -    EXPECT_FALSE(allocator.verify());
  26.138 -}
  26.139 -
  26.140 -TEST(TestingAllocator, FreeUntracked) {
  26.141 -    CxTestingAllocator allocator;
  26.142 -
  26.143 -    auto ptr = malloc(16);
  26.144 -    ASSERT_TRUE(allocator.verify());
  26.145 -    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
  26.146 -    EXPECT_FALSE(allocator.verify());
  26.147 -    ASSERT_NO_FATAL_FAILURE(free(ptr));
  26.148 -}
  26.149 -
  26.150 -TEST(TestingAllocator, FullLifecycleWithRealloc) {
  26.151 -    CxTestingAllocator allocator;
  26.152 -    ASSERT_TRUE(allocator.verify());
  26.153 -    auto ptr = cxMalloc(&allocator, 16);
  26.154 -    ASSERT_NE(ptr, nullptr);
  26.155 -    EXPECT_EQ(allocator.tracked.size(), 1);
  26.156 -    ptr = cxRealloc(&allocator, ptr, 256);
  26.157 -    ASSERT_NE(ptr, nullptr);
  26.158 -    EXPECT_EQ(allocator.tracked.size(), 1);
  26.159 -    cxFree(&allocator, ptr);
  26.160 -    EXPECT_TRUE(allocator.verify());
  26.161 -}
  26.162 -
  26.163 -TEST(TestingAllocator, CallocInitializes) {
  26.164 -    CxTestingAllocator allocator;
  26.165 -    const char zeros[16] = {0};
  26.166 -    auto ptr = cxCalloc(&allocator, 16, 1);
  26.167 -    EXPECT_EQ(memcmp(ptr, zeros, 16), 0);
  26.168 -    cxFree(&allocator, ptr);
  26.169 -    EXPECT_TRUE(allocator.verify());
  26.170 -}
    27.1 --- a/test/util_allocator.h	Wed Feb 08 20:26:09 2023 +0100
    27.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.3 @@ -1,81 +0,0 @@
    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 -#ifndef UCX_UTIL_ALLOCATOR_H
   27.33 -#define UCX_UTIL_ALLOCATOR_H
   27.34 -
   27.35 -#include "cx/allocator.h"
   27.36 -
   27.37 -#include <set>
   27.38 -
   27.39 -struct CxTestingAllocator : public CxAllocator {
   27.40 -    /**
   27.41 -     * Total number of all allocations (malloc, calloc, realloc).
   27.42 -     * A realloc() does only count when the memory has to be moved.
   27.43 -     */
   27.44 -    unsigned alloc_total = 0;
   27.45 -    /**
   27.46 -     * Number of failed allocations (malloc, calloc, realloc).
   27.47 -     */
   27.48 -    unsigned alloc_failed = 0;
   27.49 -    /**
   27.50 -     * Total number of freed pointers.
   27.51 -     * A reallocation also counts as a free when the memory has to be moved.
   27.52 -     */
   27.53 -    unsigned free_total = 0;
   27.54 -    /**
   27.55 -     * Number of failed free invocations.
   27.56 -     * A free() is considered failed, if it has not been performed on tracked memory.
   27.57 -     */
   27.58 -    unsigned free_failed = 0;
   27.59 -    /**
   27.60 -     * The set of tracked memory blocks.
   27.61 -     */
   27.62 -    std::set<void *> tracked;
   27.63 -
   27.64 -    /**
   27.65 -     * Constructs a new testing allocator.
   27.66 -     */
   27.67 -    CxTestingAllocator();
   27.68 -
   27.69 -    /**
   27.70 -     * Verifies that this allocator has been used.
   27.71 -     *
   27.72 -     * @return true if any allocation was attempted using this allocator
   27.73 -     */
   27.74 -    [[nodiscard]] bool used() const;
   27.75 -
   27.76 -    /**
   27.77 -     * Verifies that all allocated memory blocks are freed and no free occurred twice.
   27.78 -     *
   27.79 -     * @return true iff all tracked allocations / deallocations were valid
   27.80 -     */
   27.81 -    [[nodiscard]] bool verify() const;
   27.82 -};
   27.83 -
   27.84 -#endif // UCX_UTIL_ALLOCATOR_H
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/tests/.clang-tidy	Wed Feb 08 20:26:26 2023 +0100
    28.3 @@ -0,0 +1,2 @@
    28.4 +# Disable static initialization warning for test code
    28.5 +Checks: '-cert-err58-cpp'
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/tests/CMakeLists.txt	Wed Feb 08 20:26:26 2023 +0100
    29.3 @@ -0,0 +1,32 @@
    29.4 +# Load Google Test Framework
    29.5 +set(CMAKE_CXX_STANDARD 17)
    29.6 +
    29.7 +include(FetchContent)
    29.8 +FetchContent_Declare(
    29.9 +        googletest
   29.10 +        GIT_REPOSITORY https://github.com/google/googletest.git
   29.11 +        GIT_TAG e2239ee6043f73722e7aa812a459f54a28552929 # release 1.11.0
   29.12 +)
   29.13 +# For Windows: Prevent overriding the parent project's compiler/linker settings
   29.14 +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
   29.15 +FetchContent_MakeAvailable(googletest)
   29.16 +include(GoogleTest)
   29.17 +message(STATUS "Google Test made available")
   29.18 +
   29.19 +add_executable(ucxtest
   29.20 +        test_utils.cpp
   29.21 +        test_allocator.cpp
   29.22 +        test_compare.cpp
   29.23 +        test_string.cpp
   29.24 +        test_buffer.cpp
   29.25 +        test_list.cpp
   29.26 +        test_tree.cpp
   29.27 +        test_hash_key.cpp
   29.28 +        test_map.cpp
   29.29 +        test_basic_mempool.cpp
   29.30 +        test_printf.cpp
   29.31 +        selftest.cpp
   29.32 +        util_allocator.cpp
   29.33 +        )
   29.34 +target_link_libraries(ucxtest PRIVATE ucx_static gtest_main)
   29.35 +gtest_discover_tests(ucxtest)
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/tests/selftest.cpp	Wed Feb 08 20:26:26 2023 +0100
    30.3 @@ -0,0 +1,39 @@
    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 <gtest/gtest.h>
   30.33 +#include <cx/common.h>
   30.34 +
   30.35 +TEST(SelfTest, BasicAssertion) {
   30.36 +    EXPECT_EQ(7 * 6, 42);
   30.37 +}
   30.38 +
   30.39 +TEST(SelfTest, UcxVersion) {
   30.40 +    EXPECT_GE(UCX_VERSION_MAJOR, 3);
   30.41 +    EXPECT_GE(UCX_VERSION, 3 << 16);
   30.42 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/tests/test_allocator.cpp	Wed Feb 08 20:26:26 2023 +0100
    31.3 @@ -0,0 +1,96 @@
    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/allocator.h"
   31.33 +#include <gtest/gtest.h>
   31.34 +
   31.35 +TEST(Allocator, DefaultAllocator) {
   31.36 +    cx_allocator_class *clazz = cxDefaultAllocator->cl;
   31.37 +    ASSERT_NE(clazz, nullptr);
   31.38 +}
   31.39 +
   31.40 +TEST(Allocator, DefaultMalloc) {
   31.41 +    void *test = cxMalloc(cxDefaultAllocator, 16);
   31.42 +    ASSERT_NE(test, nullptr);
   31.43 +    free(test);
   31.44 +}
   31.45 +
   31.46 +TEST(Allocator, DefaultRealloc) {
   31.47 +    void *test = calloc(8, 1);
   31.48 +    memcpy(test, "Test", 5);
   31.49 +    test = cxRealloc(cxDefaultAllocator, test, 16);
   31.50 +    ASSERT_NE(test, nullptr);
   31.51 +    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
   31.52 +    free(test);
   31.53 +}
   31.54 +
   31.55 +TEST(Allocator, Reallocate) {
   31.56 +    void *test = calloc(8, 1);
   31.57 +    memcpy(test, "Test", 5);
   31.58 +    int ret = cxReallocate(cxDefaultAllocator, &test, 16);
   31.59 +    EXPECT_EQ(ret, 0);
   31.60 +    ASSERT_NE(test, nullptr);
   31.61 +    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
   31.62 +    free(test);
   31.63 +}
   31.64 +
   31.65 +TEST(Allocator, DefaultCalloc) {
   31.66 +    char *test = reinterpret_cast<char *>(cxCalloc(cxDefaultAllocator, 8, 2));
   31.67 +    ASSERT_NE(test, nullptr);
   31.68 +    for (int i = 0; i < 16; i++) ASSERT_EQ(test[i], 0);
   31.69 +    free(test);
   31.70 +}
   31.71 +
   31.72 +TEST(Allocator, DefaultFree) {
   31.73 +    void *test = malloc(16);
   31.74 +    EXPECT_NO_FATAL_FAILURE(
   31.75 +            cxFree(cxDefaultAllocator, test);
   31.76 +    );
   31.77 +}
   31.78 +
   31.79 +TEST(Allocator, FailingReallocate) {
   31.80 +    // Mock an allocator that always returns nullptr on realloc
   31.81 +    cx_allocator_class mock_cl;
   31.82 +    mock_cl.realloc = [](
   31.83 +            [[maybe_unused]]void *p,
   31.84 +            [[maybe_unused]]void *d,
   31.85 +            [[maybe_unused]]size_t n
   31.86 +    ) -> void * { return nullptr; };
   31.87 +    cx_allocator_s mock{&mock_cl, nullptr};
   31.88 +
   31.89 +    void *test = calloc(8, 1);
   31.90 +    memcpy(test, "Test", 5);
   31.91 +    void *original = test;
   31.92 +    int ret = cxReallocate(&mock, &test, 16);
   31.93 +    // non-zero return code because of the failure
   31.94 +    EXPECT_NE(ret, 0);
   31.95 +    // the test pointer was not changed and still points to the same memory
   31.96 +    EXPECT_EQ(test, original);
   31.97 +    EXPECT_STREQ(reinterpret_cast<char *>(test), "Test");
   31.98 +    free(test);
   31.99 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/tests/test_basic_mempool.cpp	Wed Feb 08 20:26:26 2023 +0100
    32.3 @@ -0,0 +1,154 @@
    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 "cx/basic_mempool.h"
   32.33 +#include "util_allocator.h"
   32.34 +#include <gtest/gtest.h>
   32.35 +
   32.36 +class CxBasicMempool : public ::testing::Test {
   32.37 +protected:
   32.38 +    CxMempool *pool = nullptr;
   32.39 +
   32.40 +    void TearDown() override {
   32.41 +        if (pool != nullptr) {
   32.42 +            cxMempoolDestroy(pool);
   32.43 +        }
   32.44 +    }
   32.45 +};
   32.46 +
   32.47 +TEST_F(CxBasicMempool, Create) {
   32.48 +    pool = cxBasicMempoolCreate(16);
   32.49 +    ASSERT_NE(pool->allocator, nullptr);
   32.50 +    ASSERT_NE(pool->cl, nullptr);
   32.51 +    EXPECT_NE(pool->cl->destroy, nullptr);
   32.52 +    ASSERT_NE(pool->allocator->cl, nullptr);
   32.53 +    EXPECT_EQ(pool->allocator->data, pool);
   32.54 +    EXPECT_NE(pool->allocator->cl->malloc, nullptr);
   32.55 +    EXPECT_NE(pool->allocator->cl->calloc, nullptr);
   32.56 +    EXPECT_NE(pool->allocator->cl->realloc, nullptr);
   32.57 +    EXPECT_NE(pool->allocator->cl->free, nullptr);
   32.58 +
   32.59 +    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
   32.60 +    EXPECT_EQ(basic_pool->size, 16);
   32.61 +    EXPECT_EQ(basic_pool->ndata, 0);
   32.62 +    EXPECT_NE(basic_pool->data, nullptr);
   32.63 +}
   32.64 +
   32.65 +TEST_F(CxBasicMempool, malloc) {
   32.66 +    pool = cxBasicMempoolCreate(4);
   32.67 +    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
   32.68 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   32.69 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   32.70 +    EXPECT_EQ(basic_pool->ndata, 2);
   32.71 +    EXPECT_EQ(basic_pool->size, 4);
   32.72 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   32.73 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   32.74 +    EXPECT_EQ(basic_pool->ndata, 4);
   32.75 +    EXPECT_EQ(basic_pool->size, 4);
   32.76 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   32.77 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
   32.78 +    EXPECT_EQ(basic_pool->ndata, 6);
   32.79 +    EXPECT_GE(basic_pool->size, 6);
   32.80 +}
   32.81 +
   32.82 +TEST_F(CxBasicMempool, calloc) {
   32.83 +    pool = cxBasicMempoolCreate(4);
   32.84 +
   32.85 +    auto test = (int *) cxCalloc(pool->allocator, 2, sizeof(int));
   32.86 +    ASSERT_NE(test, nullptr);
   32.87 +    EXPECT_EQ(test[0], 0);
   32.88 +    EXPECT_EQ(test[1], 0);
   32.89 +}
   32.90 +
   32.91 +static unsigned test_destructor_called = 0;
   32.92 +
   32.93 +static void test_destructor([[maybe_unused]] void *mem) {
   32.94 +    test_destructor_called++;
   32.95 +}
   32.96 +
   32.97 +TEST_F(CxBasicMempool, destructor) {
   32.98 +    pool = cxBasicMempoolCreate(4);
   32.99 +    auto data = cxMalloc(pool->allocator, sizeof(int));
  32.100 +    *((int *) data) = 13;
  32.101 +    cxMempoolSetDestructor(pool, data, test_destructor);
  32.102 +    EXPECT_EQ(*((int *) data), 13);
  32.103 +    test_destructor_called = 0;
  32.104 +    cxFree(pool->allocator, data);
  32.105 +    EXPECT_EQ(test_destructor_called, 1);
  32.106 +    data = cxMalloc(pool->allocator, sizeof(int));
  32.107 +    cxMempoolSetDestructor(pool, data, test_destructor);
  32.108 +    cxMempoolDestroy(pool);
  32.109 +    pool = nullptr;
  32.110 +    EXPECT_EQ(test_destructor_called, 2);
  32.111 +}
  32.112 +
  32.113 +TEST_F(CxBasicMempool, realloc) {
  32.114 +    pool = cxBasicMempoolCreate(4);
  32.115 +    auto data = cxMalloc(pool->allocator, sizeof(int));
  32.116 +    *((int *) data) = 13;
  32.117 +    cxMempoolSetDestructor(pool, data, test_destructor);
  32.118 +
  32.119 +    void *rdata = data;
  32.120 +    unsigned n = 1;
  32.121 +    while (rdata == data) {
  32.122 +        n <<= 1;
  32.123 +        ASSERT_LT(n, 65536); // eventually the memory should be moved elsewhere
  32.124 +        rdata = cxRealloc(pool->allocator, data, n * sizeof(intptr_t));
  32.125 +    }
  32.126 +
  32.127 +    EXPECT_EQ(*((int *) rdata), 13);
  32.128 +    // test if destructor is still intact
  32.129 +    test_destructor_called = 0;
  32.130 +    cxFree(pool->allocator, rdata);
  32.131 +    EXPECT_EQ(test_destructor_called, 1);
  32.132 +}
  32.133 +
  32.134 +
  32.135 +TEST_F(CxBasicMempool, free) {
  32.136 +    pool = cxBasicMempoolCreate(4);
  32.137 +    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
  32.138 +
  32.139 +    void *mem1;
  32.140 +    void *mem2;
  32.141 +
  32.142 +    mem1 = cxMalloc(pool->allocator, 16);
  32.143 +    cxFree(pool->allocator, mem1);
  32.144 +    EXPECT_EQ(basic_pool->ndata, 0);
  32.145 +
  32.146 +    cxMalloc(pool->allocator, 16);
  32.147 +    cxMalloc(pool->allocator, 16);
  32.148 +    mem1 = cxMalloc(pool->allocator, 16);
  32.149 +    cxMalloc(pool->allocator, 16);
  32.150 +    mem2 = cxMalloc(pool->allocator, 16);
  32.151 +
  32.152 +    EXPECT_EQ(basic_pool->ndata, 5);
  32.153 +    cxFree(pool->allocator, mem1);
  32.154 +    EXPECT_EQ(basic_pool->ndata, 4);
  32.155 +    cxFree(pool->allocator, mem2);
  32.156 +    EXPECT_EQ(basic_pool->ndata, 3);
  32.157 +}
  32.158 \ No newline at end of file
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/tests/test_buffer.cpp	Wed Feb 08 20:26:26 2023 +0100
    33.3 @@ -0,0 +1,815 @@
    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 +#include "cx/buffer.h"
   33.33 +
   33.34 +#include <gtest/gtest.h>
   33.35 +#include "util_allocator.h"
   33.36 +
   33.37 +class BufferFixture : public ::testing::Test {
   33.38 +protected:
   33.39 +    void SetUp() override {
   33.40 +        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   33.41 +        buf.size = 6;
   33.42 +        buf.pos = 3;
   33.43 +    }
   33.44 +
   33.45 +    void TearDown() override {
   33.46 +        cxBufferDestroy(&buf);
   33.47 +    }
   33.48 +
   33.49 +    CxBuffer buf{};
   33.50 +};
   33.51 +
   33.52 +static void expect_default_flush_config(CxBuffer *buf) {
   33.53 +    EXPECT_EQ(buf->flush_blkmax, 0);
   33.54 +    EXPECT_EQ(buf->flush_blksize, 4096);
   33.55 +    EXPECT_EQ(buf->flush_threshold, SIZE_MAX);
   33.56 +    EXPECT_EQ(buf->flush_func, nullptr);
   33.57 +    EXPECT_EQ(buf->flush_target, nullptr);
   33.58 +}
   33.59 +
   33.60 +TEST(BufferInit, WrapSpace) {
   33.61 +    CxTestingAllocator alloc;
   33.62 +    CxBuffer buf;
   33.63 +    void *space = cxMalloc(&alloc, 16);
   33.64 +    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_DEFAULT);
   33.65 +    expect_default_flush_config(&buf);
   33.66 +    EXPECT_EQ(buf.space, space);
   33.67 +    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
   33.68 +    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
   33.69 +    EXPECT_EQ(buf.pos, 0);
   33.70 +    EXPECT_EQ(buf.size, 0);
   33.71 +    EXPECT_EQ(buf.capacity, 16);
   33.72 +    EXPECT_EQ(buf.allocator, &alloc);
   33.73 +    cxBufferDestroy(&buf);
   33.74 +    EXPECT_FALSE(alloc.verify());
   33.75 +    cxFree(&alloc, space);
   33.76 +    EXPECT_TRUE(alloc.verify());
   33.77 +}
   33.78 +
   33.79 +TEST(BufferInit, WrapSpaceAutoExtend) {
   33.80 +    CxTestingAllocator alloc;
   33.81 +    CxBuffer buf;
   33.82 +    void *space = cxMalloc(&alloc, 16);
   33.83 +    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_AUTO_EXTEND);
   33.84 +    expect_default_flush_config(&buf);
   33.85 +    EXPECT_EQ(buf.space, space);
   33.86 +    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, CX_BUFFER_AUTO_EXTEND);
   33.87 +    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
   33.88 +    EXPECT_EQ(buf.pos, 0);
   33.89 +    EXPECT_EQ(buf.size, 0);
   33.90 +    EXPECT_EQ(buf.capacity, 16);
   33.91 +    EXPECT_EQ(buf.allocator, &alloc);
   33.92 +    cxBufferDestroy(&buf);
   33.93 +    EXPECT_FALSE(alloc.verify());
   33.94 +    cxFree(&alloc, space);
   33.95 +    EXPECT_TRUE(alloc.verify());
   33.96 +}
   33.97 +
   33.98 +TEST(BufferInit, WrapSpaceAutoFree) {
   33.99 +    CxTestingAllocator alloc;
  33.100 +    CxBuffer buf;
  33.101 +    void *space = cxMalloc(&alloc, 16);
  33.102 +    cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_FREE_CONTENTS);
  33.103 +    expect_default_flush_config(&buf);
  33.104 +    EXPECT_EQ(buf.space, space);
  33.105 +    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
  33.106 +    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
  33.107 +    EXPECT_EQ(buf.pos, 0);
  33.108 +    EXPECT_EQ(buf.size, 0);
  33.109 +    EXPECT_EQ(buf.capacity, 16);
  33.110 +    EXPECT_EQ(buf.allocator, &alloc);
  33.111 +    EXPECT_FALSE(alloc.verify());
  33.112 +    cxBufferDestroy(&buf);
  33.113 +    EXPECT_TRUE(alloc.verify());
  33.114 +}
  33.115 +
  33.116 +TEST(BufferInit, FreshSpace) {
  33.117 +    CxTestingAllocator alloc;
  33.118 +    CxBuffer buf;
  33.119 +    cxBufferInit(&buf, nullptr, 8, &alloc, CX_BUFFER_DEFAULT);
  33.120 +    expect_default_flush_config(&buf);
  33.121 +    EXPECT_NE(buf.space, nullptr);
  33.122 +    EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
  33.123 +    EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
  33.124 +    EXPECT_EQ(buf.pos, 0);
  33.125 +    EXPECT_EQ(buf.size, 0);
  33.126 +    EXPECT_EQ(buf.capacity, 8);
  33.127 +    EXPECT_EQ(buf.allocator, &alloc);
  33.128 +    EXPECT_FALSE(alloc.verify()); // space is still allocated
  33.129 +    cxBufferDestroy(&buf);
  33.130 +    EXPECT_TRUE(alloc.verify());
  33.131 +}
  33.132 +
  33.133 +class BufferShiftFixture : public ::testing::Test {
  33.134 +protected:
  33.135 +    void SetUp() override {
  33.136 +        ASSERT_TRUE(alloc.verify());
  33.137 +        cxBufferInit(&buf, nullptr, 16, &alloc, CX_BUFFER_DEFAULT);
  33.138 +        memcpy(buf.space, "test____________", 16);
  33.139 +        buf.capacity = 8; // purposely pretend that the buffer has less capacity s.t. we can test beyond the range
  33.140 +        buf.pos = 4;
  33.141 +        buf.size = 4;
  33.142 +    }
  33.143 +
  33.144 +    void TearDown() override {
  33.145 +        cxBufferDestroy(&buf);
  33.146 +        EXPECT_TRUE(alloc.verify());
  33.147 +    }
  33.148 +
  33.149 +    CxTestingAllocator alloc;
  33.150 +    CxBuffer buf{};
  33.151 +};
  33.152 +
  33.153 +class BufferShiftLeft : public BufferShiftFixture {
  33.154 +};
  33.155 +
  33.156 +TEST_F(BufferShiftLeft, Zero) {
  33.157 +    ASSERT_EQ(buf.pos, 4);
  33.158 +    ASSERT_EQ(buf.size, 4);
  33.159 +    int ret = cxBufferShiftLeft(&buf, 0);
  33.160 +    EXPECT_EQ(ret, 0);
  33.161 +    EXPECT_EQ(buf.pos, 4);
  33.162 +    EXPECT_EQ(buf.size, 4);
  33.163 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  33.164 +}
  33.165 +
  33.166 +TEST_F(BufferShiftLeft, ZeroOffsetInterface) {
  33.167 +    ASSERT_EQ(buf.pos, 4);
  33.168 +    ASSERT_EQ(buf.size, 4);
  33.169 +    int ret = cxBufferShift(&buf, -0);
  33.170 +    EXPECT_EQ(ret, 0);
  33.171 +    EXPECT_EQ(buf.pos, 4);
  33.172 +    EXPECT_EQ(buf.size, 4);
  33.173 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  33.174 +}
  33.175 +
  33.176 +TEST_F(BufferShiftLeft, Standard) {
  33.177 +    ASSERT_EQ(buf.pos, 4);
  33.178 +    ASSERT_EQ(buf.size, 4);
  33.179 +    int ret = cxBufferShiftLeft(&buf, 2);
  33.180 +    EXPECT_EQ(ret, 0);
  33.181 +    EXPECT_EQ(buf.pos, 2);
  33.182 +    EXPECT_EQ(buf.size, 2);
  33.183 +    EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
  33.184 +}
  33.185 +
  33.186 +TEST_F(BufferShiftLeft, Overshift) {
  33.187 +    ASSERT_LT(buf.pos, 6);
  33.188 +    ASSERT_LT(buf.size, 6);
  33.189 +    int ret = cxBufferShiftLeft(&buf, 6);
  33.190 +    EXPECT_EQ(ret, 0);
  33.191 +    EXPECT_EQ(buf.pos, 0);
  33.192 +    EXPECT_EQ(buf.size, 0);
  33.193 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  33.194 +}
  33.195 +
  33.196 +TEST_F(BufferShiftLeft, OvershiftPosOnly) {
  33.197 +    buf.pos = 2;
  33.198 +    ASSERT_EQ(buf.size, 4);
  33.199 +    int ret = cxBufferShiftLeft(&buf, 3);
  33.200 +    EXPECT_EQ(ret, 0);
  33.201 +    EXPECT_EQ(buf.pos, 0);
  33.202 +    EXPECT_EQ(buf.size, 1);
  33.203 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  33.204 +}
  33.205 +
  33.206 +TEST_F(BufferShiftLeft, OffsetInterface) {
  33.207 +    buf.pos = 3;
  33.208 +    ASSERT_EQ(buf.size, 4);
  33.209 +    int ret = cxBufferShift(&buf, -2);
  33.210 +    EXPECT_EQ(ret, 0);
  33.211 +    EXPECT_EQ(buf.pos, 1);
  33.212 +    EXPECT_EQ(buf.size, 2);
  33.213 +    EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
  33.214 +}
  33.215 +
  33.216 +class BufferShiftRight : public BufferShiftFixture {
  33.217 +};
  33.218 +
  33.219 +TEST_F(BufferShiftRight, Zero) {
  33.220 +    ASSERT_EQ(buf.pos, 4);
  33.221 +    ASSERT_EQ(buf.size, 4);
  33.222 +    int ret = cxBufferShiftRight(&buf, 0);
  33.223 +    EXPECT_EQ(ret, 0);
  33.224 +    EXPECT_EQ(buf.pos, 4);
  33.225 +    EXPECT_EQ(buf.size, 4);
  33.226 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  33.227 +}
  33.228 +
  33.229 +TEST_F(BufferShiftRight, ZeroOffsetInterface) {
  33.230 +    ASSERT_EQ(buf.pos, 4);
  33.231 +    ASSERT_EQ(buf.size, 4);
  33.232 +    int ret = cxBufferShift(&buf, +0);
  33.233 +    EXPECT_EQ(ret, 0);
  33.234 +    EXPECT_EQ(buf.pos, 4);
  33.235 +    EXPECT_EQ(buf.size, 4);
  33.236 +    EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
  33.237 +}
  33.238 +
  33.239 +TEST_F(BufferShiftRight, Standard) {
  33.240 +    ASSERT_EQ(buf.pos, 4);
  33.241 +    ASSERT_EQ(buf.size, 4);
  33.242 +    int ret = cxBufferShiftRight(&buf, 3);
  33.243 +    EXPECT_EQ(ret, 0);
  33.244 +    EXPECT_EQ(buf.pos, 7);
  33.245 +    EXPECT_EQ(buf.size, 7);
  33.246 +    EXPECT_TRUE(memcmp(buf.space, "testest_____", 8) == 0);
  33.247 +}
  33.248 +
  33.249 +TEST_F(BufferShiftRight, OvershiftDiscard) {
  33.250 +    ASSERT_EQ(buf.pos, 4);
  33.251 +    ASSERT_EQ(buf.size, 4);
  33.252 +    ASSERT_EQ(buf.capacity, 8);
  33.253 +    int ret = cxBufferShiftRight(&buf, 6);
  33.254 +    EXPECT_EQ(ret, 0);
  33.255 +    EXPECT_EQ(buf.pos, 8);
  33.256 +    EXPECT_EQ(buf.size, 8);
  33.257 +    EXPECT_EQ(buf.capacity, 8);
  33.258 +    EXPECT_TRUE(memcmp(buf.space, "test__te____", 8) == 0);
  33.259 +}
  33.260 +
  33.261 +TEST_F(BufferShiftRight, OvershiftExtend) {
  33.262 +    ASSERT_EQ(buf.pos, 4);
  33.263 +    ASSERT_EQ(buf.size, 4);
  33.264 +    ASSERT_EQ(buf.capacity, 8);
  33.265 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  33.266 +    int ret = cxBufferShiftRight(&buf, 6);
  33.267 +    EXPECT_EQ(ret, 0);
  33.268 +    EXPECT_EQ(buf.pos, 10);
  33.269 +    EXPECT_EQ(buf.size, 10);
  33.270 +    EXPECT_GE(buf.capacity, 10);
  33.271 +    EXPECT_TRUE(memcmp(buf.space, "test__test__", 8) == 0);
  33.272 +}
  33.273 +
  33.274 +TEST_F(BufferShiftRight, OffsetInterface) {
  33.275 +    buf.pos = 3;
  33.276 +    ASSERT_EQ(buf.size, 4);
  33.277 +    int ret = cxBufferShift(&buf, 2);
  33.278 +    EXPECT_EQ(ret, 0);
  33.279 +    EXPECT_EQ(buf.pos, 5);
  33.280 +    EXPECT_EQ(buf.size, 6);
  33.281 +    EXPECT_TRUE(memcmp(buf.space, "tetest______", 8) == 0);
  33.282 +}
  33.283 +
  33.284 +TEST(BufferMinimumCapacity, Sufficient) {
  33.285 +    CxTestingAllocator alloc;
  33.286 +    auto space = cxMalloc(&alloc, 8);
  33.287 +    CxBuffer buf;
  33.288 +    cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS);
  33.289 +    memcpy(space, "Testing", 8);
  33.290 +    buf.size = 8;
  33.291 +    cxBufferMinimumCapacity(&buf, 6);
  33.292 +    EXPECT_EQ(buf.capacity, 8);
  33.293 +    EXPECT_EQ(buf.size, 8);
  33.294 +    EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
  33.295 +    cxBufferDestroy(&buf);
  33.296 +    EXPECT_TRUE(alloc.verify());
  33.297 +}
  33.298 +
  33.299 +TEST(BufferMinimumCapacity, Extend) {
  33.300 +    CxTestingAllocator alloc;
  33.301 +    auto space = cxMalloc(&alloc, 8);
  33.302 +    CxBuffer buf;
  33.303 +    cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS); // NO auto extend!
  33.304 +    memcpy(space, "Testing", 8);
  33.305 +    buf.size = 8;
  33.306 +    cxBufferMinimumCapacity(&buf, 16);
  33.307 +    EXPECT_EQ(buf.capacity, 16);
  33.308 +    EXPECT_EQ(buf.size, 8);
  33.309 +    EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
  33.310 +    cxBufferDestroy(&buf);
  33.311 +    EXPECT_TRUE(alloc.verify());
  33.312 +}
  33.313 +
  33.314 +TEST(BufferClear, Test) {
  33.315 +    char space[16];
  33.316 +    strcpy(space, "clear test");
  33.317 +    CxBuffer buf;
  33.318 +    cxBufferInit(&buf, space, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
  33.319 +    ASSERT_EQ(buf.size, 0);
  33.320 +    // only clear the used part of the buffer
  33.321 +    cxBufferClear(&buf);
  33.322 +    EXPECT_EQ(memcmp(space, "clear test", 10), 0);
  33.323 +    buf.size = 5;
  33.324 +    buf.pos = 3;
  33.325 +    cxBufferClear(&buf);
  33.326 +    EXPECT_EQ(memcmp(space, "\0\0\0\0\0 test", 10), 0);
  33.327 +    EXPECT_EQ(buf.size, 0);
  33.328 +    EXPECT_EQ(buf.pos, 0);
  33.329 +    cxBufferDestroy(&buf);
  33.330 +}
  33.331 +
  33.332 +class BufferWrite : public ::testing::Test {
  33.333 +protected:
  33.334 +    CxBuffer buf{}, target{};
  33.335 +
  33.336 +    void SetUp() override {
  33.337 +        cxBufferInit(&target, nullptr, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
  33.338 +        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
  33.339 +        buf.capacity = 8; // artificially reduce capacity to check OOB writes
  33.340 +        memset(buf.space, 0, 16);
  33.341 +        memcpy(buf.space, "prep", 4);
  33.342 +        buf.size = buf.pos = 4;
  33.343 +    }
  33.344 +
  33.345 +    void TearDown() override {
  33.346 +        cxBufferDestroy(&buf);
  33.347 +        cxBufferDestroy(&target);
  33.348 +    }
  33.349 +
  33.350 +    void enableFlushing() {
  33.351 +        buf.flush_target = &target;
  33.352 +        buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
  33.353 +        buf.flush_blkmax = 1;
  33.354 +    }
  33.355 +};
  33.356 +
  33.357 +static size_t mock_write_limited_rate(
  33.358 +        void const *ptr,
  33.359 +        size_t size,
  33.360 +        __attribute__((unused)) size_t nitems,
  33.361 +        CxBuffer *buffer
  33.362 +) {
  33.363 +    // simulate limited target drain capacity
  33.364 +    static bool full = false;
  33.365 +    if (full) {
  33.366 +        full = false;
  33.367 +        return 0;
  33.368 +    } else {
  33.369 +        full = true;
  33.370 +        return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
  33.371 +    }
  33.372 +}
  33.373 +
  33.374 +TEST_F(BufferWrite, SizeOneFit) {
  33.375 +    const char *data = "test";
  33.376 +    ASSERT_EQ(buf.capacity, 8);
  33.377 +    ASSERT_EQ(buf.pos, 4);
  33.378 +    ASSERT_EQ(buf.size, 4);
  33.379 +    size_t written = cxBufferWrite(data, 1, 4, &buf);
  33.380 +    EXPECT_EQ(written, 4);
  33.381 +    EXPECT_EQ(buf.size, 8);
  33.382 +    EXPECT_EQ(buf.pos, 8);
  33.383 +    EXPECT_EQ(buf.capacity, 8);
  33.384 +    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
  33.385 +}
  33.386 +
  33.387 +TEST_F(BufferWrite, SizeOneDiscard) {
  33.388 +    const char *data = "testing";
  33.389 +    ASSERT_EQ(buf.capacity, 8);
  33.390 +    ASSERT_EQ(buf.pos, 4);
  33.391 +    ASSERT_EQ(buf.size, 4);
  33.392 +    size_t written = cxBufferWrite(data, 1, 7, &buf);
  33.393 +    EXPECT_EQ(written, 4);
  33.394 +    EXPECT_EQ(buf.size, 8);
  33.395 +    EXPECT_EQ(buf.pos, 8);
  33.396 +    EXPECT_EQ(buf.capacity, 8);
  33.397 +    EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
  33.398 +}
  33.399 +
  33.400 +TEST_F(BufferWrite, SizeOneExtend) {
  33.401 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  33.402 +    const char *data = "testing";
  33.403 +    ASSERT_EQ(buf.capacity, 8);
  33.404 +    ASSERT_EQ(buf.pos, 4);
  33.405 +    ASSERT_EQ(buf.size, 4);
  33.406 +    size_t written = cxBufferWrite(data, 1, 7, &buf);
  33.407 +    EXPECT_EQ(written, 7);
  33.408 +    EXPECT_EQ(buf.size, 11);
  33.409 +    EXPECT_EQ(buf.pos, 11);
  33.410 +    EXPECT_GE(buf.capacity, 11);
  33.411 +    EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
  33.412 +}
  33.413 +
  33.414 +TEST_F(BufferWrite, MultibyteFit) {
  33.415 +    const char *data = "test";
  33.416 +    ASSERT_EQ(buf.capacity, 8);
  33.417 +    ASSERT_EQ(buf.pos, 4);
  33.418 +    ASSERT_EQ(buf.size, 4);
  33.419 +    size_t written = cxBufferWrite(data, 2, 2, &buf);
  33.420 +    EXPECT_EQ(written, 2);
  33.421 +    EXPECT_EQ(buf.size, 8);
  33.422 +    EXPECT_EQ(buf.pos, 8);
  33.423 +    EXPECT_EQ(buf.capacity, 8);
  33.424 +    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
  33.425 +}
  33.426 +
  33.427 +TEST_F(BufferWrite, MultibyteDiscard) {
  33.428 +    const char *data = "testing";
  33.429 +    ASSERT_EQ(buf.capacity, 8);
  33.430 +    ASSERT_EQ(buf.size, 4);
  33.431 +    buf.pos = 3;
  33.432 +    size_t written = cxBufferWrite(data, 2, 4, &buf);
  33.433 +    // remember: whole elements are discarded if they do not fit
  33.434 +    EXPECT_EQ(written, 2);
  33.435 +    EXPECT_EQ(buf.size, 7);
  33.436 +    EXPECT_EQ(buf.pos, 7);
  33.437 +    EXPECT_EQ(buf.capacity, 8);
  33.438 +    EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0);
  33.439 +}
  33.440 +
  33.441 +TEST_F(BufferWrite, MultibyteExtend) {
  33.442 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  33.443 +    const char *data = "tester";
  33.444 +    ASSERT_EQ(buf.capacity, 8);
  33.445 +    ASSERT_EQ(buf.size, 4);
  33.446 +    buf.pos = 3;
  33.447 +    size_t written = cxBufferWrite(data, 2, 3, &buf);
  33.448 +    // remember: whole elements are discarded if they do not fit
  33.449 +    EXPECT_EQ(written, 3);
  33.450 +    EXPECT_EQ(buf.size, 9);
  33.451 +    EXPECT_EQ(buf.pos, 9);
  33.452 +    EXPECT_GE(buf.capacity, 9);
  33.453 +    EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0);
  33.454 +}
  33.455 +
  33.456 +TEST_F(BufferWrite, PutcWrapperFit) {
  33.457 +    ASSERT_EQ(buf.capacity, 8);
  33.458 +    ASSERT_EQ(buf.pos, 4);
  33.459 +    ASSERT_EQ(buf.size, 4);
  33.460 +    int c = cxBufferPut(&buf, 0x200 | 'a');
  33.461 +    EXPECT_EQ(c, 'a');
  33.462 +    EXPECT_EQ(buf.size, 5);
  33.463 +    EXPECT_EQ(buf.pos, 5);
  33.464 +    EXPECT_EQ(buf.capacity, 8);
  33.465 +    EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0);
  33.466 +}
  33.467 +
  33.468 +TEST_F(BufferWrite, PutcWrapperDiscard) {
  33.469 +    ASSERT_EQ(buf.capacity, 8);
  33.470 +    ASSERT_EQ(buf.size, 4);
  33.471 +    buf.pos = 8;
  33.472 +    int c = cxBufferPut(&buf, 0x200 | 'a');
  33.473 +    EXPECT_EQ(c, EOF);
  33.474 +    EXPECT_EQ(buf.size, 4);
  33.475 +    EXPECT_EQ(buf.pos, 8);
  33.476 +    EXPECT_EQ(buf.capacity, 8);
  33.477 +    EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0);
  33.478 +}
  33.479 +
  33.480 +TEST_F(BufferWrite, PutcWrapperExtend) {
  33.481 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  33.482 +    ASSERT_EQ(buf.capacity, 8);
  33.483 +    ASSERT_EQ(buf.size, 4);
  33.484 +    buf.pos = 8;
  33.485 +    int c = cxBufferPut(&buf, 0x200 | 'a');
  33.486 +    EXPECT_EQ(c, 'a');
  33.487 +    EXPECT_EQ(buf.size, 9);
  33.488 +    EXPECT_EQ(buf.pos, 9);
  33.489 +    EXPECT_GE(buf.capacity, 9);
  33.490 +    EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0);
  33.491 +}
  33.492 +
  33.493 +TEST_F(BufferWrite, PutStringWrapperFit) {
  33.494 +    const char *data = "test";
  33.495 +    ASSERT_EQ(buf.capacity, 8);
  33.496 +    ASSERT_EQ(buf.pos, 4);
  33.497 +    ASSERT_EQ(buf.size, 4);
  33.498 +    size_t written = cxBufferPutString(&buf, data);
  33.499 +    EXPECT_EQ(written, 4);
  33.500 +    EXPECT_EQ(buf.size, 8);
  33.501 +    EXPECT_EQ(buf.pos, 8);
  33.502 +    EXPECT_EQ(buf.capacity, 8);
  33.503 +    EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
  33.504 +}
  33.505 +
  33.506 +TEST_F(BufferWrite, PutStringWrapperDiscard) {
  33.507 +    const char *data = "testing";
  33.508 +    ASSERT_EQ(buf.capacity, 8);
  33.509 +    ASSERT_EQ(buf.pos, 4);
  33.510 +    ASSERT_EQ(buf.size, 4);
  33.511 +    size_t written = cxBufferPutString(&buf, data);
  33.512 +    EXPECT_EQ(written, 4);
  33.513 +    EXPECT_EQ(buf.size, 8);
  33.514 +    EXPECT_EQ(buf.pos, 8);
  33.515 +    EXPECT_EQ(buf.capacity, 8);
  33.516 +    EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
  33.517 +}
  33.518 +
  33.519 +TEST_F(BufferWrite, PutStringWrapperExtend) {
  33.520 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  33.521 +    const char *data = "testing";
  33.522 +    ASSERT_EQ(buf.capacity, 8);
  33.523 +    ASSERT_EQ(buf.pos, 4);
  33.524 +    ASSERT_EQ(buf.size, 4);
  33.525 +    size_t written = cxBufferPutString(&buf, data);
  33.526 +    EXPECT_EQ(written, 7);
  33.527 +    EXPECT_EQ(buf.size, 11);
  33.528 +    EXPECT_EQ(buf.pos, 11);
  33.529 +    EXPECT_GE(buf.capacity, 11);
  33.530 +    EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
  33.531 +}
  33.532 +
  33.533 +TEST_F(BufferWrite, MultOverflow) {
  33.534 +    const char *data = "testing";
  33.535 +    ASSERT_EQ(buf.capacity, 8);
  33.536 +    ASSERT_EQ(buf.pos, 4);
  33.537 +    ASSERT_EQ(buf.size, 4);
  33.538 +    size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf);
  33.539 +    EXPECT_EQ(written, 0);
  33.540 +    EXPECT_EQ(buf.capacity, 8);
  33.541 +    EXPECT_EQ(buf.pos, 4);
  33.542 +    EXPECT_EQ(buf.size, 4);
  33.543 +    EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
  33.544 +}
  33.545 +
  33.546 +TEST_F(BufferWrite, MaxCapaOverflow) {
  33.547 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  33.548 +    const char *data = "testing";
  33.549 +    ASSERT_EQ(buf.capacity, 8);
  33.550 +    ASSERT_EQ(buf.pos, 4);
  33.551 +    ASSERT_EQ(buf.size, 4);
  33.552 +    size_t written = cxBufferWrite(data, 1, SIZE_MAX - 2, &buf);
  33.553 +    EXPECT_EQ(written, 0);
  33.554 +    EXPECT_EQ(buf.capacity, 8);
  33.555 +    EXPECT_EQ(buf.pos, 4);
  33.556 +    EXPECT_EQ(buf.size, 4);
  33.557 +    EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
  33.558 +}
  33.559 +
  33.560 +TEST_F(BufferWrite, OnlyOverwrite) {
  33.561 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  33.562 +    ASSERT_EQ(buf.capacity, 8);
  33.563 +    memcpy(buf.space, "preptest", 8);
  33.564 +    buf.pos = 3;
  33.565 +    buf.size = 8;
  33.566 +    size_t written = cxBufferWrite("XXX", 2, 2, &buf);
  33.567 +    EXPECT_EQ(written, 2);
  33.568 +    EXPECT_EQ(buf.capacity, 8);
  33.569 +    EXPECT_EQ(buf.size, 8);
  33.570 +    EXPECT_EQ(buf.pos, 7);
  33.571 +    EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0);
  33.572 +}
  33.573 +
  33.574 +TEST_F(BufferWrite, FlushAtCapacity) {
  33.575 +    enableFlushing();
  33.576 +    ASSERT_EQ(buf.capacity, 8);
  33.577 +    ASSERT_EQ(buf.pos, 4);
  33.578 +    size_t written = cxBufferWrite("foo", 1, 3, &buf);
  33.579 +    EXPECT_EQ(written, 3);
  33.580 +    ASSERT_EQ(buf.pos, 7);
  33.581 +    ASSERT_EQ(buf.size, 7);
  33.582 +    ASSERT_EQ(target.pos, 0);
  33.583 +    ASSERT_EQ(target.size, 0);
  33.584 +    written = cxBufferWrite("hello", 1, 5, &buf);
  33.585 +    EXPECT_EQ(written, 5);
  33.586 +    EXPECT_EQ(buf.pos, 0);
  33.587 +    EXPECT_EQ(buf.size, 0);
  33.588 +    EXPECT_EQ(buf.capacity, 8);
  33.589 +    EXPECT_EQ(target.pos, 12);
  33.590 +    ASSERT_EQ(target.size, 12);
  33.591 +    EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0);
  33.592 +}
  33.593 +
  33.594 +TEST_F(BufferWrite, FlushAtThreshold) {
  33.595 +    enableFlushing();
  33.596 +    buf.flush_threshold = 12;
  33.597 +    buf.flags |= CX_BUFFER_AUTO_EXTEND;
  33.598 +    ASSERT_EQ(buf.capacity, 8);
  33.599 +    ASSERT_EQ(buf.pos, 4);
  33.600 +    size_t written = cxBufferWrite("foobar", 1, 6, &buf);
  33.601 +    EXPECT_EQ(written, 6);
  33.602 +    ASSERT_EQ(buf.pos, 10);
  33.603 +    ASSERT_EQ(buf.size, 10);
  33.604 +    ASSERT_GE(buf.capacity, 10);
  33.605 +    ASSERT_LE(buf.capacity, 12);
  33.606 +    ASSERT_EQ(target.pos, 0);
  33.607 +    ASSERT_EQ(target.size, 0);
  33.608 +    written = cxBufferWrite("hello", 1, 5, &buf);
  33.609 +    EXPECT_EQ(written, 5);
  33.610 +    EXPECT_EQ(buf.pos, 0);
  33.611 +    EXPECT_EQ(buf.size, 0);
  33.612 +    EXPECT_LE(buf.capacity, 12);
  33.613 +    EXPECT_EQ(target.pos, 15);
  33.614 +    ASSERT_EQ(target.size, 15);
  33.615 +    EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0);
  33.616 +}
  33.617 +
  33.618 +TEST_F(BufferWrite, FlushRateLimited) {
  33.619 +    enableFlushing();
  33.620 +    // limit the rate of the flush function and the capacity of the target
  33.621 +    target.capacity = 16;
  33.622 +    target.flags &= ~CX_BUFFER_AUTO_EXTEND;
  33.623 +    buf.flush_func = (cx_write_func) mock_write_limited_rate;
  33.624 +    ASSERT_EQ(buf.capacity, 8);
  33.625 +    ASSERT_EQ(buf.pos, 4);
  33.626 +    size_t written = cxBufferWrite("foo", 1, 3, &buf);
  33.627 +    EXPECT_EQ(written, 3);
  33.628 +    ASSERT_EQ(buf.pos, 7);
  33.629 +    ASSERT_EQ(buf.size, 7);
  33.630 +    ASSERT_EQ(target.pos, 0);
  33.631 +    ASSERT_EQ(target.size, 0);
  33.632 +    written = cxBufferWrite("hello, world!", 1, 13, &buf);
  33.633 +    // " world!" fits into this buffer, the remaining stuff is flushed out
  33.634 +    EXPECT_EQ(written, 13);
  33.635 +    EXPECT_EQ(buf.pos, 7);
  33.636 +    EXPECT_EQ(buf.size, 7);
  33.637 +    EXPECT_EQ(buf.capacity, 8);
  33.638 +    EXPECT_EQ(memcmp(buf.space, " world!", 7), 0);
  33.639 +    EXPECT_EQ(target.pos, 13);
  33.640 +    ASSERT_EQ(target.size, 13);
  33.641 +    EXPECT_EQ(target.capacity, 16);
  33.642 +    EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0);
  33.643 +}
  33.644 +
  33.645 +class BufferSeek : public BufferFixture {
  33.646 +};
  33.647 +
  33.648 +TEST_F(BufferSeek, SetZero) {
  33.649 +    int result = cxBufferSeek(&buf, 0, SEEK_SET);
  33.650 +    EXPECT_EQ(result, 0);
  33.651 +    EXPECT_EQ(buf.pos, 0);
  33.652 +}
  33.653 +
  33.654 +TEST_F(BufferSeek, SetValid) {
  33.655 +    int result = cxBufferSeek(&buf, 5, SEEK_SET);
  33.656 +    EXPECT_EQ(result, 0);
  33.657 +    EXPECT_EQ(buf.pos, 5);
  33.658 +}
  33.659 +
  33.660 +TEST_F(BufferSeek, SetInvalid) {
  33.661 +    ASSERT_EQ(buf.pos, 3);
  33.662 +    int result = cxBufferSeek(&buf, 6, SEEK_SET);
  33.663 +    EXPECT_NE(result, 0);
  33.664 +    EXPECT_EQ(buf.pos, 3);
  33.665 +}
  33.666 +
  33.667 +TEST_F(BufferSeek, CurZero) {
  33.668 +    ASSERT_EQ(buf.pos, 3);
  33.669 +    int result = cxBufferSeek(&buf, 0, SEEK_CUR);
  33.670 +    EXPECT_EQ(result, 0);
  33.671 +    EXPECT_EQ(buf.pos, 3);
  33.672 +}
  33.673 +
  33.674 +TEST_F(BufferSeek, CurValidPositive) {
  33.675 +    ASSERT_EQ(buf.pos, 3);
  33.676 +    int result = cxBufferSeek(&buf, 2, SEEK_CUR);
  33.677 +    EXPECT_EQ(result, 0);
  33.678 +    EXPECT_EQ(buf.pos, 5);
  33.679 +}
  33.680 +
  33.681 +TEST_F(BufferSeek, CurValidNegative) {
  33.682 +    ASSERT_EQ(buf.pos, 3);
  33.683 +    int result = cxBufferSeek(&buf, -3, SEEK_CUR);
  33.684 +    EXPECT_EQ(result, 0);
  33.685 +    EXPECT_EQ(buf.pos, 0);
  33.686 +}
  33.687 +
  33.688 +TEST_F(BufferSeek, CurInvalidPositive) {
  33.689 +    ASSERT_EQ(buf.pos, 3);
  33.690 +    int result = cxBufferSeek(&buf, 3, SEEK_CUR);
  33.691 +    EXPECT_NE(result, 0);
  33.692 +    EXPECT_EQ(buf.pos, 3);
  33.693 +}
  33.694 +
  33.695 +TEST_F(BufferSeek, CurInvalidNegative) {
  33.696 +    ASSERT_EQ(buf.pos, 3);
  33.697 +    int result = cxBufferSeek(&buf, -4, SEEK_CUR);
  33.698 +    EXPECT_NE(result, 0);
  33.699 +    EXPECT_EQ(buf.pos, 3);
  33.700 +}
  33.701 +
  33.702 +TEST_F(BufferSeek, EndZero) {
  33.703 +    ASSERT_EQ(buf.size, 6);
  33.704 +    int result = cxBufferSeek(&buf, 0, SEEK_END);
  33.705 +    // the (past-the-)end position is always invalid
  33.706 +    EXPECT_NE(result, 0);
  33.707 +    EXPECT_EQ(buf.pos, 3);
  33.708 +}
  33.709 +
  33.710 +TEST_F(BufferSeek, EndValid) {
  33.711 +    ASSERT_EQ(buf.size, 6);
  33.712 +    int result = cxBufferSeek(&buf, -6, SEEK_END);
  33.713 +    EXPECT_EQ(result, 0);
  33.714 +    EXPECT_EQ(buf.pos, 0);
  33.715 +}
  33.716 +
  33.717 +TEST_F(BufferSeek, EndInvalid) {
  33.718 +    ASSERT_EQ(buf.size, 6);
  33.719 +    int result = cxBufferSeek(&buf, 1, SEEK_END);
  33.720 +    EXPECT_NE(result, 0);
  33.721 +    EXPECT_EQ(buf.pos, 3);
  33.722 +}
  33.723 +
  33.724 +TEST_F(BufferSeek, WhenceInvalid) {
  33.725 +    ASSERT_EQ(buf.size, 6);
  33.726 +    ASSERT_EQ(buf.pos, 3);
  33.727 +    int result = cxBufferSeek(&buf, 2, 9000);
  33.728 +    EXPECT_NE(result, 0);
  33.729 +    EXPECT_EQ(buf.size, 6);
  33.730 +    EXPECT_EQ(buf.pos, 3);
  33.731 +}
  33.732 +
  33.733 +class BufferEof : public BufferFixture {
  33.734 +};
  33.735 +
  33.736 +TEST_F(BufferEof, Reached) {
  33.737 +    buf.pos = buf.size;
  33.738 +    EXPECT_TRUE(cxBufferEof(&buf));
  33.739 +    buf.pos = buf.size - 1;
  33.740 +    ASSERT_FALSE(cxBufferEof(&buf));
  33.741 +    cxBufferPut(&buf, 'a');
  33.742 +    EXPECT_TRUE(cxBufferEof(&buf));
  33.743 +}
  33.744 +
  33.745 +TEST_F(BufferEof, NotReached) {
  33.746 +    buf.pos = buf.size - 1;
  33.747 +    EXPECT_FALSE(cxBufferEof(&buf));
  33.748 +    buf.pos = 0;
  33.749 +    cxBufferWrite("test", 1, 5, &buf);
  33.750 +    EXPECT_FALSE(cxBufferEof(&buf));
  33.751 +}
  33.752 +
  33.753 +class BufferRead : public ::testing::Test {
  33.754 +protected:
  33.755 +    CxBuffer buf{};
  33.756 +
  33.757 +    void SetUp() override {
  33.758 +        cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
  33.759 +        buf.capacity = 8; // artificially reduce capacity to check OOB writes
  33.760 +        memset(buf.space, 0, 16);
  33.761 +        memcpy(buf.space, "some data", 9);
  33.762 +        buf.size = 9;
  33.763 +    }
  33.764 +
  33.765 +    void TearDown() override {
  33.766 +        cxBufferDestroy(&buf);
  33.767 +    }
  33.768 +};
  33.769 +
  33.770 +TEST_F(BufferRead, GetByte) {
  33.771 +    buf.pos = 2;
  33.772 +    EXPECT_EQ(cxBufferGet(&buf), 'm');
  33.773 +    EXPECT_EQ(cxBufferGet(&buf), 'e');
  33.774 +    EXPECT_EQ(cxBufferGet(&buf), ' ');
  33.775 +    EXPECT_EQ(cxBufferGet(&buf), 'd');
  33.776 +    EXPECT_EQ(buf.pos, 6);
  33.777 +}
  33.778 +
  33.779 +TEST_F(BufferRead, GetEof) {
  33.780 +    buf.pos = buf.size;
  33.781 +    EXPECT_EQ(cxBufferGet(&buf), EOF);
  33.782 +}
  33.783 +
  33.784 +TEST_F(BufferRead, ReadWithinBounds) {
  33.785 +    buf.pos = 2;
  33.786 +    char target[4];
  33.787 +    auto read = cxBufferRead(&target, 1, 4, &buf);
  33.788 +    ASSERT_EQ(read, 4);
  33.789 +    EXPECT_EQ(memcmp(&target, "me d", 4), 0);
  33.790 +    EXPECT_EQ(buf.pos, 6);
  33.791 +}
  33.792 +
  33.793 +TEST_F(BufferRead, ReadOutOfBounds) {
  33.794 +    buf.pos = 6;
  33.795 +    char target[4];
  33.796 +    auto read = cxBufferRead(&target, 1, 4, &buf);
  33.797 +    ASSERT_EQ(read, 3);
  33.798 +    EXPECT_EQ(memcmp(&target, "ata", 3), 0);
  33.799 +    EXPECT_EQ(buf.pos, 9);
  33.800 +}
  33.801 +
  33.802 +TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
  33.803 +    buf.pos = 6;
  33.804 +    char target[4];
  33.805 +    target[2] = '\0';
  33.806 +    auto read = cxBufferRead(&target, 2, 2, &buf);
  33.807 +    ASSERT_EQ(read, 1);
  33.808 +    EXPECT_EQ(memcmp(&target, "at\0", 3), 0);
  33.809 +    EXPECT_EQ(buf.pos, 8);
  33.810 +}
  33.811 +
  33.812 +TEST_F(BufferRead, ReadEof) {
  33.813 +    buf.pos = 9;
  33.814 +    char target[4];
  33.815 +    auto read = cxBufferRead(&target, 1, 1, &buf);
  33.816 +    ASSERT_EQ(read, 0);
  33.817 +    EXPECT_EQ(buf.pos, 9);
  33.818 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/tests/test_compare.cpp	Wed Feb 08 20:26:26 2023 +0100
    34.3 @@ -0,0 +1,127 @@
    34.4 +/*
    34.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    34.6 + *
    34.7 + * Copyright 2022 Mike Becker, Olaf Wintermann All rights reserved.
    34.8 + *
    34.9 + * Redistribution and use in source and binary forms, with or without
   34.10 + * modification, are permitted provided that the following conditions are met:
   34.11 + *
   34.12 + *   1. Redistributions of source code must retain the above copyright
   34.13 + *      notice, this list of conditions and the following disclaimer.
   34.14 + *
   34.15 + *   2. Redistributions in binary form must reproduce the above copyright
   34.16 + *      notice, this list of conditions and the following disclaimer in the
   34.17 + *      documentation and/or other materials provided with the distribution.
   34.18 + *
   34.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   34.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   34.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   34.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   34.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   34.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   34.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   34.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34.29 + * POSSIBILITY OF SUCH DAMAGE.
   34.30 + */
   34.31 +
   34.32 +#include "cx/compare.h"
   34.33 +
   34.34 +#include <gtest/gtest.h>
   34.35 +
   34.36 +template<typename T>
   34.37 +static void test_compare(
   34.38 +        int (*fnc)(
   34.39 +                void const *,
   34.40 +                void const *
   34.41 +        )
   34.42 +) {
   34.43 +    auto m = std::numeric_limits<T>::max() / 400;
   34.44 +    T x, y;
   34.45 +
   34.46 +    x = (std::is_signed_v<T> ? -3 : 3) * m;
   34.47 +    y = 5 * m;
   34.48 +    EXPECT_LT(fnc(&x, &y), 0);
   34.49 +    EXPECT_GT(fnc(&y, &x), 0);
   34.50 +
   34.51 +    x = 120 * m;
   34.52 +    y = 348 * m;
   34.53 +    EXPECT_LT(fnc(&x, &y), 0);
   34.54 +    EXPECT_GT(fnc(&y, &x), 0);
   34.55 +
   34.56 +    if constexpr (std::is_signed_v<T>) {
   34.57 +        x = -120 * m;
   34.58 +        y = -348 * m;
   34.59 +        EXPECT_GT(fnc(&x, &y), 0);
   34.60 +        EXPECT_LT(fnc(&y, &x), 0);
   34.61 +    }
   34.62 +
   34.63 +    x = y;
   34.64 +    EXPECT_EQ(fnc(&x, &y), 0);
   34.65 +    EXPECT_EQ(fnc(&y, &x), 0);
   34.66 +}
   34.67 +
   34.68 +TEST(Compare, Int) {
   34.69 +    test_compare<int>(cx_cmp_int);
   34.70 +}
   34.71 +
   34.72 +TEST(Compare, Longint) {
   34.73 +    test_compare<long int>(cx_cmp_longint);
   34.74 +}
   34.75 +
   34.76 +TEST(Compare, Longlong) {
   34.77 +    test_compare<long long>(cx_cmp_longlong);
   34.78 +}
   34.79 +
   34.80 +TEST(Compare, Int16) {
   34.81 +    test_compare<int16_t>(cx_cmp_int16);
   34.82 +}
   34.83 +
   34.84 +TEST(Compare, Int32) {
   34.85 +    test_compare<int32_t>(cx_cmp_int32);
   34.86 +}
   34.87 +
   34.88 +TEST(Compare, Int64) {
   34.89 +    test_compare<int64_t>(cx_cmp_int64);
   34.90 +}
   34.91 +
   34.92 +TEST(Compare, Uint) {
   34.93 +    test_compare<unsigned int>(cx_cmp_uint);
   34.94 +}
   34.95 +
   34.96 +TEST(Compare, Ulongint) {
   34.97 +    test_compare<unsigned long int>(cx_cmp_ulongint);
   34.98 +}
   34.99 +
  34.100 +TEST(Compare, Ulonglong) {
  34.101 +    test_compare<unsigned long long>(cx_cmp_ulonglong);
  34.102 +}
  34.103 +
  34.104 +TEST(Compare, Uint16) {
  34.105 +    test_compare<uint16_t>(cx_cmp_uint16);
  34.106 +}
  34.107 +
  34.108 +TEST(Compare, Uint32) {
  34.109 +    test_compare<uint32_t>(cx_cmp_uint32);
  34.110 +}
  34.111 +
  34.112 +TEST(Compare, Uint64) {
  34.113 +    test_compare<uint64_t>(cx_cmp_uint64);
  34.114 +}
  34.115 +
  34.116 +TEST(Compare, Float) {
  34.117 +    test_compare<float>(cx_cmp_float);
  34.118 +}
  34.119 +
  34.120 +TEST(Compare, Double) {
  34.121 +    test_compare<double>(cx_cmp_double);
  34.122 +}
  34.123 +
  34.124 +TEST(Compare, IntPtr) {
  34.125 +    test_compare<intptr_t>(cx_cmp_intptr);
  34.126 +}
  34.127 +
  34.128 +TEST(Compare, UintPtr) {
  34.129 +    test_compare<uintptr_t>(cx_cmp_uintptr);
  34.130 +}
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/tests/test_hash_key.cpp	Wed Feb 08 20:26:26 2023 +0100
    35.3 @@ -0,0 +1,87 @@
    35.4 +/*
    35.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    35.6 + *
    35.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    35.8 + *
    35.9 + * Redistribution and use in source and binary forms, with or without
   35.10 + * modification, are permitted provided that the following conditions are met:
   35.11 + *
   35.12 + *   1. Redistributions of source code must retain the above copyright
   35.13 + *      notice, this list of conditions and the following disclaimer.
   35.14 + *
   35.15 + *   2. Redistributions in binary form must reproduce the above copyright
   35.16 + *      notice, this list of conditions and the following disclaimer in the
   35.17 + *      documentation and/or other materials provided with the distribution.
   35.18 + *
   35.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   35.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   35.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   35.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   35.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   35.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   35.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   35.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35.29 + * POSSIBILITY OF SUCH DAMAGE.
   35.30 + */
   35.31 +
   35.32 +#include "cx/hash_key.h"
   35.33 +
   35.34 +#include <gtest/gtest.h>
   35.35 +
   35.36 +TEST(cx_hash_key, functions) {
   35.37 +    auto str = "my key";
   35.38 +    auto len = strlen(str);
   35.39 +
   35.40 +    auto str_key = cx_hash_key_str(str);
   35.41 +    auto bytes_key = cx_hash_key_bytes(
   35.42 +            reinterpret_cast<unsigned char const *>(str), len);
   35.43 +    auto obj_key = cx_hash_key(
   35.44 +            reinterpret_cast<void const *>(str), len);
   35.45 +
   35.46 +    EXPECT_EQ(str_key.hash, bytes_key.hash);
   35.47 +    EXPECT_EQ(obj_key.hash, bytes_key.hash);
   35.48 +    EXPECT_EQ(str_key.len, len);
   35.49 +    EXPECT_EQ(bytes_key.len, len);
   35.50 +    EXPECT_EQ(bytes_key.len, len);
   35.51 +    EXPECT_EQ(str_key.data.cstr, str);
   35.52 +    EXPECT_EQ(bytes_key.data.cbytes, reinterpret_cast<unsigned char const *>(str));
   35.53 +    EXPECT_EQ(bytes_key.data.cobj, reinterpret_cast<void const *>(str));
   35.54 +}
   35.55 +
   35.56 +TEST(cx_hash_key, empty_string) {
   35.57 +    auto str = "";
   35.58 +
   35.59 +    auto str_key = cx_hash_key_str(str);
   35.60 +    auto bytes_key = cx_hash_key_bytes(
   35.61 +            reinterpret_cast<unsigned char const *>(str), 0);
   35.62 +    auto obj_key = cx_hash_key(
   35.63 +            reinterpret_cast<void const *>(str), 0);
   35.64 +
   35.65 +    EXPECT_EQ(bytes_key.hash, 4152238450u);
   35.66 +    EXPECT_EQ(str_key.hash, 4152238450u);
   35.67 +    EXPECT_EQ(obj_key.hash, 4152238450u);
   35.68 +    EXPECT_EQ(str_key.len, 0);
   35.69 +    EXPECT_EQ(bytes_key.len, 0);
   35.70 +    EXPECT_EQ(bytes_key.len, 0);
   35.71 +    EXPECT_EQ(str_key.data.cstr, str);
   35.72 +    EXPECT_EQ(bytes_key.data.cbytes, reinterpret_cast<unsigned char const *>(str));
   35.73 +    EXPECT_EQ(bytes_key.data.cobj, reinterpret_cast<void const *>(str));
   35.74 +}
   35.75 +
   35.76 +TEST(cx_hash_key, null_ptr) {
   35.77 +    auto str_key = cx_hash_key_str(nullptr);
   35.78 +    auto bytes_key = cx_hash_key_bytes(nullptr, 0);
   35.79 +    auto obj_key = cx_hash_key(nullptr, 0);
   35.80 +
   35.81 +    EXPECT_EQ(bytes_key.hash, 1574210520u);
   35.82 +    EXPECT_EQ(str_key.hash, 1574210520u);
   35.83 +    EXPECT_EQ(obj_key.hash, 1574210520u);
   35.84 +    EXPECT_EQ(str_key.len, 0);
   35.85 +    EXPECT_EQ(bytes_key.len, 0);
   35.86 +    EXPECT_EQ(bytes_key.len, 0);
   35.87 +    EXPECT_EQ(str_key.data.cstr, nullptr);
   35.88 +    EXPECT_EQ(bytes_key.data.cbytes, nullptr);
   35.89 +    EXPECT_EQ(bytes_key.data.cobj, nullptr);
   35.90 +}
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/tests/test_list.cpp	Wed Feb 08 20:26:26 2023 +0100
    36.3 @@ -0,0 +1,1159 @@
    36.4 +/*
    36.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    36.6 + *
    36.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    36.8 + *
    36.9 + * Redistribution and use in source and binary forms, with or without
   36.10 + * modification, are permitted provided that the following conditions are met:
   36.11 + *
   36.12 + *   1. Redistributions of source code must retain the above copyright
   36.13 + *      notice, this list of conditions and the following disclaimer.
   36.14 + *
   36.15 + *   2. Redistributions in binary form must reproduce the above copyright
   36.16 + *      notice, this list of conditions and the following disclaimer in the
   36.17 + *      documentation and/or other materials provided with the distribution.
   36.18 + *
   36.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   36.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   36.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   36.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   36.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   36.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   36.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   36.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   36.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36.29 + * POSSIBILITY OF SUCH DAMAGE.
   36.30 + */
   36.31 +
   36.32 +#include "cx/linked_list.h"
   36.33 +#include "cx/array_list.h"
   36.34 +#include "cx/utils.h"
   36.35 +#include "cx/compare.h"
   36.36 +#include "util_allocator.h"
   36.37 +
   36.38 +#include <gtest/gtest.h>
   36.39 +#include <array>
   36.40 +#include <vector>
   36.41 +#include <unordered_set>
   36.42 +#include <algorithm>
   36.43 +
   36.44 +struct node {
   36.45 +    node *next = nullptr;
   36.46 +    node *prev = nullptr;
   36.47 +    int data = 0;
   36.48 +};
   36.49 +
   36.50 +const ptrdiff_t loc_prev = offsetof(struct node, prev);
   36.51 +const ptrdiff_t loc_next = offsetof(struct node, next);
   36.52 +const ptrdiff_t loc_data = offsetof(struct node, data);
   36.53 +
   36.54 +struct node_test_data {
   36.55 +    node *begin = nullptr;
   36.56 +
   36.57 +    explicit node_test_data(node *begin) : begin(begin) {
   36.58 +        auto n = begin;
   36.59 +        while (n != nullptr) {
   36.60 +            nodes.push_back(n);
   36.61 +            n = n->next;
   36.62 +        }
   36.63 +    }
   36.64 +
   36.65 +    node_test_data(node_test_data &) = delete;
   36.66 +
   36.67 +    node_test_data(node_test_data &&) = default;
   36.68 +
   36.69 +    ~node_test_data() {
   36.70 +        for (auto &&n: nodes) delete n;
   36.71 +    }
   36.72 +
   36.73 +private:
   36.74 +    std::vector<node *> nodes;
   36.75 +};
   36.76 +
   36.77 +static node_test_data create_nodes_test_data(size_t len) {
   36.78 +    if (len == 0) return node_test_data{nullptr};
   36.79 +    auto begin = new node;
   36.80 +    auto prev = begin;
   36.81 +    for (size_t i = 1; i < len; i++) {
   36.82 +        auto n = new node;
   36.83 +        cx_linked_list_link(prev, n, loc_prev, loc_next);
   36.84 +        prev = n;
   36.85 +    }
   36.86 +    return node_test_data{begin};
   36.87 +}
   36.88 +
   36.89 +template<typename InputIter>
   36.90 +static node_test_data create_nodes_test_data(
   36.91 +        InputIter begin,
   36.92 +        InputIter end
   36.93 +) {
   36.94 +    if (begin == end) return node_test_data{nullptr};
   36.95 +    node *first = new node;
   36.96 +    first->data = *begin;
   36.97 +    node *prev = first;
   36.98 +    begin++;
   36.99 +    for (; begin != end; begin++) {
  36.100 +        auto n = new node;
  36.101 +        n->data = *begin;
  36.102 +        cx_linked_list_link(prev, n, loc_prev, loc_next);
  36.103 +        prev = n;
  36.104 +    }
  36.105 +    return node_test_data{first};
  36.106 +}
  36.107 +
  36.108 +static node_test_data create_nodes_test_data(std::initializer_list<int> data) {
  36.109 +    return create_nodes_test_data(data.begin(), data.end());
  36.110 +}
  36.111 +
  36.112 +template<size_t N>
  36.113 +struct int_test_data {
  36.114 +    std::array<int, N> data;
  36.115 +
  36.116 +    int_test_data() {
  36.117 +        cx_for_n (i, N) data[i] = ::rand(); // NOLINT(cert-msc50-cpp)
  36.118 +    }
  36.119 +};
  36.120 +
  36.121 +TEST(LinkedList_LowLevel, link_unlink) {
  36.122 +    node a, b, c;
  36.123 +
  36.124 +    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  36.125 +    EXPECT_EQ(a.prev, nullptr);
  36.126 +    EXPECT_EQ(a.next, &b);
  36.127 +    EXPECT_EQ(b.prev, &a);
  36.128 +    EXPECT_EQ(b.next, nullptr);
  36.129 +
  36.130 +    cx_linked_list_unlink(&a, &b, loc_prev, loc_next);
  36.131 +    EXPECT_EQ(a.prev, nullptr);
  36.132 +    EXPECT_EQ(a.next, nullptr);
  36.133 +    EXPECT_EQ(b.prev, nullptr);
  36.134 +    EXPECT_EQ(b.next, nullptr);
  36.135 +
  36.136 +    cx_linked_list_link(&b, &c, loc_prev, loc_next);
  36.137 +    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  36.138 +    cx_linked_list_unlink(&b, &c, loc_prev, loc_next);
  36.139 +    EXPECT_EQ(a.prev, nullptr);
  36.140 +    EXPECT_EQ(a.next, &b);
  36.141 +    EXPECT_EQ(b.prev, &a);
  36.142 +    EXPECT_EQ(b.next, nullptr);
  36.143 +    EXPECT_EQ(c.prev, nullptr);
  36.144 +    EXPECT_EQ(c.next, nullptr);
  36.145 +}
  36.146 +
  36.147 +TEST(LinkedList_LowLevel, cx_linked_list_at) {
  36.148 +    node a, b, c, d;
  36.149 +    cx_linked_list_link(&a, &b, loc_prev, loc_next);
  36.150 +    cx_linked_list_link(&b, &c, loc_prev, loc_next);
  36.151 +    cx_linked_list_link(&c, &d, loc_prev, loc_next);
  36.152 +
  36.153 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 0), &a);
  36.154 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 1), &b);
  36.155 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 2), &c);
  36.156 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 3), &d);
  36.157 +    EXPECT_EQ(cx_linked_list_at(&a, 0, loc_next, 4), nullptr);
  36.158 +
  36.159 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_prev, 0), &a);
  36.160 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 1), &b);
  36.161 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 2), &c);
  36.162 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 3), &d);
  36.163 +    EXPECT_EQ(cx_linked_list_at(&b, 1, loc_next, 4), nullptr);
  36.164 +
  36.165 +    EXPECT_EQ(cx_linked_list_at(&d, 3, loc_prev, 0), &a);
  36.166 +    EXPECT_EQ(cx_linked_list_at(&d, 3, loc_prev, 1), &b);
  36.167 +}
  36.168 +
  36.169 +TEST(LinkedList_LowLevel, cx_linked_list_find) {
  36.170 +    auto testdata = create_nodes_test_data({2, 4, 6, 8});
  36.171 +    auto list = testdata.begin;
  36.172 +    int s;
  36.173 +
  36.174 +    s = 2;
  36.175 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 0);
  36.176 +    s = 4;
  36.177 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 1);
  36.178 +    s = 6;
  36.179 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 2);
  36.180 +    s = 8;
  36.181 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 3);
  36.182 +    s = 10;
  36.183 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 4);
  36.184 +    s = -2;
  36.185 +    EXPECT_EQ(cx_linked_list_find(list, loc_next, loc_data, cx_cmp_int, &s), 4);
  36.186 +}
  36.187 +
  36.188 +TEST(LinkedList_LowLevel, cx_linked_list_compare) {
  36.189 +    auto ta = create_nodes_test_data({2, 4, 6, 8});
  36.190 +    auto tb = create_nodes_test_data({2, 4, 6});
  36.191 +    auto tc = create_nodes_test_data({2, 4, 6, 9});
  36.192 +    auto la = ta.begin, lb = tb.begin, lc = tc.begin;
  36.193 +
  36.194 +    EXPECT_GT(cx_linked_list_compare(la, lb, loc_next, loc_data, cx_cmp_int), 0);
  36.195 +    EXPECT_LT(cx_linked_list_compare(lb, la, loc_next, loc_data, cx_cmp_int), 0);
  36.196 +    EXPECT_GT(cx_linked_list_compare(lc, la, loc_next, loc_data, cx_cmp_int), 0);
  36.197 +    EXPECT_LT(cx_linked_list_compare(la, lc, loc_next, loc_data, cx_cmp_int), 0);
  36.198 +    EXPECT_EQ(cx_linked_list_compare(la, la, loc_next, loc_data, cx_cmp_int), 0);
  36.199 +}
  36.200 +
  36.201 +TEST(LinkedList_LowLevel, cx_linked_list_add) {
  36.202 +    // test with begin, end / prev, next
  36.203 +    {
  36.204 +        node nodes[4];
  36.205 +        void *begin = nullptr, *end = nullptr;
  36.206 +
  36.207 +        cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[0]);
  36.208 +        EXPECT_EQ(begin, &nodes[0]);
  36.209 +        EXPECT_EQ(end, &nodes[0]);
  36.210 +        EXPECT_EQ(nodes[0].prev, nullptr);
  36.211 +        EXPECT_EQ(nodes[0].next, nullptr);
  36.212 +
  36.213 +        cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[1]);
  36.214 +        EXPECT_EQ(begin, &nodes[0]);
  36.215 +        EXPECT_EQ(end, &nodes[1]);
  36.216 +        EXPECT_EQ(nodes[0].next, &nodes[1]);
  36.217 +        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  36.218 +    }
  36.219 +
  36.220 +    // test with begin only / prev, next
  36.221 +    {
  36.222 +        node nodes[4];
  36.223 +        void *begin = nullptr;
  36.224 +
  36.225 +        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[0]);
  36.226 +        EXPECT_EQ(begin, &nodes[0]);
  36.227 +        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[1]);
  36.228 +        EXPECT_EQ(begin, &nodes[0]);
  36.229 +        EXPECT_EQ(nodes[0].next, &nodes[1]);
  36.230 +        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  36.231 +
  36.232 +        cx_linked_list_add(&begin, nullptr, loc_prev, loc_next, &nodes[2]);
  36.233 +        EXPECT_EQ(nodes[1].next, &nodes[2]);
  36.234 +        EXPECT_EQ(nodes[2].prev, &nodes[1]);
  36.235 +    }
  36.236 +
  36.237 +    // test with end only / prev, next
  36.238 +    {
  36.239 +        node nodes[4];
  36.240 +        void *end = nullptr;
  36.241 +
  36.242 +        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[0]);
  36.243 +        EXPECT_EQ(end, &nodes[0]);
  36.244 +        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[1]);
  36.245 +        EXPECT_EQ(end, &nodes[1]);
  36.246 +        EXPECT_EQ(nodes[0].next, &nodes[1]);
  36.247 +        EXPECT_EQ(nodes[1].prev, &nodes[0]);
  36.248 +
  36.249 +        cx_linked_list_add(nullptr, &end, loc_prev, loc_next, &nodes[2]);
  36.250 +        EXPECT_EQ(end, &nodes[2]);
  36.251 +        EXPECT_EQ(nodes[1].next, &nodes[2]);
  36.252 +        EXPECT_EQ(nodes[2].prev, &nodes[1]);
  36.253 +    }
  36.254 +
  36.255 +    // test with begin, end / next
  36.256 +    {
  36.257 +        node nodes[4];
  36.258 +        void *begin = nullptr, *end = nullptr;
  36.259 +
  36.260 +        cx_linked_list_add(&begin, &end, -1, loc_next, &nodes[0]);
  36.261 +        EXPECT_EQ(begin, &nodes[0]);
  36.262 +        EXPECT_EQ(end, &nodes[0]);
  36.263 +        cx_linked_list_add(&begin, &end, -1, loc_next, &nodes[1]);
  36.264 +        EXPECT_EQ(end, &nodes[1]);
  36.265 +        EXPECT_EQ(nodes[0].next, &nodes[1]);
  36.266 +        EXPECT_EQ(nodes[1].prev, nullptr);
  36.267 +    }
  36.268 +}
  36.269 +
  36.270 +TEST(LinkedList_LowLevel, cx_linked_list_prepend) {
  36.271 +    // test with begin, end / prev, next
  36.272 +    {
  36.273 +        node nodes[4];
  36.274 +        void *begin = nullptr, *end = nullptr;
  36.275 +
  36.276 +        cx_linked_list_prepend(&begin, &end, loc_prev, loc_next, &nodes[0]);
  36.277 +        EXPECT_EQ(begin, &nodes[0]);
  36.278 +        EXPECT_EQ(end, &nodes[0]);
  36.279 +        EXPECT_EQ(nodes[0].prev, nullptr);
  36.280 +        EXPECT_EQ(nodes[0].next, nullptr);
  36.281 +
  36.282 +        cx_linked_list_prepend(&begin, &end, loc_prev, loc_next, &nodes[1]);
  36.283 +        EXPECT_EQ(begin, &nodes[1]);
  36.284 +        EXPECT_EQ(end, &nodes[0]);
  36.285 +        EXPECT_EQ(nodes[1].next, &nodes[0]);
  36.286 +        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  36.287 +    }
  36.288 +
  36.289 +    // test with begin only / prev, next
  36.290 +    {
  36.291 +        node nodes[4];
  36.292 +        void *begin = nullptr;
  36.293 +
  36.294 +        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[0]);
  36.295 +        EXPECT_EQ(begin, &nodes[0]);
  36.296 +        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[1]);
  36.297 +        EXPECT_EQ(begin, &nodes[1]);
  36.298 +        EXPECT_EQ(nodes[1].next, &nodes[0]);
  36.299 +        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  36.300 +
  36.301 +        cx_linked_list_prepend(&begin, nullptr, loc_prev, loc_next, &nodes[2]);
  36.302 +        EXPECT_EQ(begin, &nodes[2]);
  36.303 +        EXPECT_EQ(nodes[2].next, &nodes[1]);
  36.304 +        EXPECT_EQ(nodes[1].prev, &nodes[2]);
  36.305 +    }
  36.306 +
  36.307 +    // test with end only / prev, next
  36.308 +    {
  36.309 +        node nodes[4];
  36.310 +        void *end = nullptr;
  36.311 +
  36.312 +        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[0]);
  36.313 +        EXPECT_EQ(end, &nodes[0]);
  36.314 +        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[1]);
  36.315 +        EXPECT_EQ(end, &nodes[0]);
  36.316 +        EXPECT_EQ(nodes[1].next, &nodes[0]);
  36.317 +        EXPECT_EQ(nodes[0].prev, &nodes[1]);
  36.318 +
  36.319 +        cx_linked_list_prepend(nullptr, &end, loc_prev, loc_next, &nodes[2]);
  36.320 +        EXPECT_EQ(end, &nodes[0]);
  36.321 +        EXPECT_EQ(nodes[2].next, &nodes[1]);
  36.322 +        EXPECT_EQ(nodes[1].prev, &nodes[2]);
  36.323 +    }
  36.324 +
  36.325 +    // test with begin, end / next
  36.326 +    {
  36.327 +        node nodes[4];
  36.328 +        void *begin = nullptr, *end = nullptr;
  36.329 +
  36.330 +        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[0]);
  36.331 +        EXPECT_EQ(begin, &nodes[0]);
  36.332 +        EXPECT_EQ(end, &nodes[0]);
  36.333 +        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[1]);
  36.334 +        cx_linked_list_prepend(&begin, &end, -1, loc_next, &nodes[2]);
  36.335 +        EXPECT_EQ(begin, &nodes[2]);
  36.336 +        EXPECT_EQ(end, &nodes[0]);
  36.337 +        EXPECT_EQ(nodes[1].next, &nodes[0]);
  36.338 +        EXPECT_EQ(nodes[2].next, &nodes[1]);
  36.339 +        EXPECT_EQ(nodes[1].prev, nullptr);
  36.340 +        EXPECT_EQ(nodes[0].prev, nullptr);
  36.341 +    }
  36.342 +}
  36.343 +
  36.344 +TEST(LinkedList_LowLevel, cx_linked_list_insert) {
  36.345 +    // insert mid list
  36.346 +    {
  36.347 +        node nodes[4];
  36.348 +        void *begin = &nodes[0], *end = &nodes[2];
  36.349 +
  36.350 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  36.351 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  36.352 +
  36.353 +        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, &nodes[1], &nodes[3]);
  36.354 +        EXPECT_EQ(begin, &nodes[0]);
  36.355 +        EXPECT_EQ(end, &nodes[2]);
  36.356 +        EXPECT_EQ(nodes[1].next, &nodes[3]);
  36.357 +        EXPECT_EQ(nodes[2].prev, &nodes[3]);
  36.358 +        EXPECT_EQ(nodes[3].prev, &nodes[1]);
  36.359 +        EXPECT_EQ(nodes[3].next, &nodes[2]);
  36.360 +    }
  36.361 +
  36.362 +    // insert end
  36.363 +    {
  36.364 +        node nodes[4];
  36.365 +        void *begin = &nodes[0], *end = &nodes[2];
  36.366 +
  36.367 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  36.368 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  36.369 +
  36.370 +        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, &nodes[2], &nodes[3]);
  36.371 +        EXPECT_EQ(begin, &nodes[0]);
  36.372 +        EXPECT_EQ(end, &nodes[3]);
  36.373 +        EXPECT_EQ(nodes[2].next, &nodes[3]);
  36.374 +        EXPECT_EQ(nodes[3].prev, &nodes[2]);
  36.375 +        EXPECT_EQ(nodes[3].next, nullptr);
  36.376 +    }
  36.377 +
  36.378 +    // insert begin
  36.379 +    {
  36.380 +        node nodes[4];
  36.381 +        void *begin = &nodes[0], *end = &nodes[2];
  36.382 +
  36.383 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  36.384 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  36.385 +
  36.386 +        cx_linked_list_insert(&begin, &end, loc_prev, loc_next, nullptr, &nodes[3]);
  36.387 +        EXPECT_EQ(begin, &nodes[3]);
  36.388 +        EXPECT_EQ(end, &nodes[2]);
  36.389 +        EXPECT_EQ(nodes[0].prev, &nodes[3]);
  36.390 +        EXPECT_EQ(nodes[3].prev, nullptr);
  36.391 +        EXPECT_EQ(nodes[3].next, &nodes[0]);
  36.392 +    }
  36.393 +}
  36.394 +
  36.395 +TEST(LinkedList_LowLevel, cx_linked_list_insert_chain) {
  36.396 +    // insert mid list
  36.397 +    {
  36.398 +        node nodes[5];
  36.399 +        void *begin = &nodes[0], *end = &nodes[2];
  36.400 +
  36.401 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  36.402 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  36.403 +        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  36.404 +
  36.405 +        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, &nodes[1], &nodes[3], nullptr);
  36.406 +        EXPECT_EQ(begin, &nodes[0]);
  36.407 +        EXPECT_EQ(end, &nodes[2]);
  36.408 +        EXPECT_EQ(nodes[1].next, &nodes[3]);
  36.409 +        EXPECT_EQ(nodes[2].prev, &nodes[4]);
  36.410 +        EXPECT_EQ(nodes[3].prev, &nodes[1]);
  36.411 +        EXPECT_EQ(nodes[4].next, &nodes[2]);
  36.412 +    }
  36.413 +
  36.414 +    // insert end
  36.415 +    {
  36.416 +        node nodes[5];
  36.417 +        void *begin = &nodes[0], *end = &nodes[2];
  36.418 +
  36.419 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  36.420 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  36.421 +        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  36.422 +
  36.423 +        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, &nodes[2], &nodes[3], nullptr);
  36.424 +        EXPECT_EQ(begin, &nodes[0]);
  36.425 +        EXPECT_EQ(end, &nodes[4]);
  36.426 +        EXPECT_EQ(nodes[2].next, &nodes[3]);
  36.427 +        EXPECT_EQ(nodes[3].prev, &nodes[2]);
  36.428 +        EXPECT_EQ(nodes[4].next, nullptr);
  36.429 +    }
  36.430 +
  36.431 +    // insert begin
  36.432 +    {
  36.433 +        node nodes[5];
  36.434 +        void *begin = &nodes[0], *end = &nodes[2];
  36.435 +
  36.436 +        cx_linked_list_link(&nodes[0], &nodes[1], loc_prev, loc_next);
  36.437 +        cx_linked_list_link(&nodes[1], &nodes[2], loc_prev, loc_next);
  36.438 +        cx_linked_list_link(&nodes[3], &nodes[4], loc_prev, loc_next);
  36.439 +
  36.440 +        cx_linked_list_insert_chain(&begin, &end, loc_prev, loc_next, nullptr, &nodes[3], nullptr);
  36.441 +        EXPECT_EQ(begin, &nodes[3]);
  36.442 +        EXPECT_EQ(end, &nodes[2]);
  36.443 +        EXPECT_EQ(nodes[0].prev, &nodes[4]);
  36.444 +        EXPECT_EQ(nodes[3].prev, nullptr);
  36.445 +        EXPECT_EQ(nodes[4].next, &nodes[0]);
  36.446 +    }
  36.447 +}
  36.448 +
  36.449 +TEST(LinkedList_LowLevel, cx_linked_list_first) {
  36.450 +    auto testdata = create_nodes_test_data(3);
  36.451 +    auto begin = testdata.begin;
  36.452 +    EXPECT_EQ(cx_linked_list_first(begin, loc_prev), begin);
  36.453 +    EXPECT_EQ(cx_linked_list_first(begin->next, loc_prev), begin);
  36.454 +    EXPECT_EQ(cx_linked_list_first(begin->next->next, loc_prev), begin);
  36.455 +}
  36.456 +
  36.457 +TEST(LinkedList_LowLevel, cx_linked_list_last) {
  36.458 +    auto testdata = create_nodes_test_data(3);
  36.459 +    auto begin = testdata.begin;
  36.460 +    auto end = begin->next->next;
  36.461 +    EXPECT_EQ(cx_linked_list_last(begin, loc_next), end);
  36.462 +    EXPECT_EQ(cx_linked_list_last(begin->next, loc_next), end);
  36.463 +    EXPECT_EQ(cx_linked_list_last(begin->next->next, loc_next), end);
  36.464 +}
  36.465 +
  36.466 +TEST(LinkedList_LowLevel, cx_linked_list_prev) {
  36.467 +    auto testdata = create_nodes_test_data(3);
  36.468 +    auto begin = testdata.begin;
  36.469 +    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin), nullptr);
  36.470 +    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin->next), begin);
  36.471 +    EXPECT_EQ(cx_linked_list_prev(begin, loc_next, begin->next->next), begin->next);
  36.472 +}
  36.473 +
  36.474 +TEST(LinkedList_LowLevel, cx_linked_list_remove) {
  36.475 +    auto testdata = create_nodes_test_data({2, 4, 6});
  36.476 +    auto begin = reinterpret_cast<void *>(testdata.begin);
  36.477 +    auto first = testdata.begin;
  36.478 +    auto second = first->next;
  36.479 +    auto third = second->next;
  36.480 +    auto end = reinterpret_cast<void *>(third);
  36.481 +
  36.482 +    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, second);
  36.483 +    EXPECT_EQ(begin, first);
  36.484 +    EXPECT_EQ(end, third);
  36.485 +    EXPECT_EQ(first->prev, nullptr);
  36.486 +    EXPECT_EQ(first->next, third);
  36.487 +    EXPECT_EQ(third->prev, first);
  36.488 +    EXPECT_EQ(third->next, nullptr);
  36.489 +
  36.490 +    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, third);
  36.491 +    EXPECT_EQ(begin, first);
  36.492 +    EXPECT_EQ(end, first);
  36.493 +    EXPECT_EQ(first->prev, nullptr);
  36.494 +    EXPECT_EQ(first->next, nullptr);
  36.495 +
  36.496 +    cx_linked_list_remove(&begin, &end, loc_prev, loc_next, first);
  36.497 +    EXPECT_EQ(begin, nullptr);
  36.498 +    EXPECT_EQ(end, nullptr);
  36.499 +}
  36.500 +
  36.501 +TEST(LinkedList_LowLevel, cx_linked_list_size) {
  36.502 +    EXPECT_EQ(cx_linked_list_size(nullptr, loc_next), 0);
  36.503 +
  36.504 +    {
  36.505 +        auto testdata = create_nodes_test_data(5);
  36.506 +        EXPECT_EQ(cx_linked_list_size(testdata.begin, loc_next), 5);
  36.507 +    }
  36.508 +
  36.509 +    {
  36.510 +        auto testdata = create_nodes_test_data(13);
  36.511 +        EXPECT_EQ(cx_linked_list_size(testdata.begin, loc_next), 13);
  36.512 +    }
  36.513 +}
  36.514 +
  36.515 +TEST(LinkedList_LowLevel, cx_linked_list_sort) {
  36.516 +    int_test_data<1500> testdata;
  36.517 +    std::array<int, 1500> sorted{};
  36.518 +    std::partial_sort_copy(testdata.data.begin(), testdata.data.end(), sorted.begin(), sorted.end());
  36.519 +
  36.520 +    auto scrambled = create_nodes_test_data(testdata.data.begin(), testdata.data.end());
  36.521 +    void *begin = scrambled.begin;
  36.522 +    void *end = cx_linked_list_last(begin, loc_next);
  36.523 +
  36.524 +    cx_linked_list_sort(&begin, &end, loc_prev, loc_next, loc_data, cx_cmp_int);
  36.525 +
  36.526 +    node *check = reinterpret_cast<node *>(begin);
  36.527 +    node *check_last = nullptr;
  36.528 +    cx_for_n (i, sorted.size()) {
  36.529 +        EXPECT_EQ(check->data, sorted[i]);
  36.530 +        EXPECT_EQ(check->prev, check_last);
  36.531 +        if (i < sorted.size() - 1) {
  36.532 +            ASSERT_NE(check->next, nullptr);
  36.533 +        }
  36.534 +        check_last = check;
  36.535 +        check = check->next;
  36.536 +    }
  36.537 +    EXPECT_EQ(check, nullptr);
  36.538 +    EXPECT_EQ(end, check_last);
  36.539 +}
  36.540 +
  36.541 +TEST(LinkedList_LowLevel, cx_linked_list_reverse) {
  36.542 +    auto testdata = create_nodes_test_data({2, 4, 6, 8});
  36.543 +    auto expected = create_nodes_test_data({8, 6, 4, 2});
  36.544 +
  36.545 +    auto begin = reinterpret_cast<void *>(testdata.begin);
  36.546 +    auto end = cx_linked_list_last(begin, loc_next);
  36.547 +    auto orig_begin = begin, orig_end = end;
  36.548 +
  36.549 +    cx_linked_list_reverse(&begin, &end, loc_prev, loc_next);
  36.550 +    EXPECT_EQ(end, orig_begin);
  36.551 +    EXPECT_EQ(begin, orig_end);
  36.552 +    EXPECT_EQ(cx_linked_list_compare(begin, expected.begin, loc_next, loc_data, cx_cmp_int), 0);
  36.553 +}
  36.554 +
  36.555 +class HighLevelTest : public ::testing::Test {
  36.556 +    mutable std::unordered_set<CxList *> lists;
  36.557 +protected:
  36.558 +    CxTestingAllocator testingAllocator;
  36.559 +
  36.560 +    void TearDown() override {
  36.561 +        for (auto &&l: lists) cxListDestroy(l);
  36.562 +        EXPECT_TRUE(testingAllocator.verify());
  36.563 +    }
  36.564 +
  36.565 +    static constexpr size_t testdata_len = 250;
  36.566 +    int_test_data<testdata_len> testdata;
  36.567 +
  36.568 +    auto autofree(CxList *list) const -> CxList * {
  36.569 +        if (list != nullptr) lists.insert(list);
  36.570 +        return list;
  36.571 +    }
  36.572 +
  36.573 +    auto linkedListFromTestData() const -> CxList * {
  36.574 +        auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  36.575 +        cxListAddArray(list, testdata.data.data(), testdata_len);
  36.576 +        return list;
  36.577 +    }
  36.578 +
  36.579 +    auto pointerLinkedListFromTestData() const -> CxList * {
  36.580 +        auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  36.581 +        cxListStorePointers(list);
  36.582 +        // note: cannot use cxListAddArray() because we don't have a list of pointers
  36.583 +        cx_for_n(i, testdata_len) cxListAdd(list, &testdata.data[i]);
  36.584 +        return list;
  36.585 +    }
  36.586 +
  36.587 +    auto arrayListFromTestData() const -> CxList * {
  36.588 +        auto list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), testdata_len));
  36.589 +        cxListAddArray(list, testdata.data.data(), testdata_len);
  36.590 +        return list;
  36.591 +    }
  36.592 +
  36.593 +    void verifyCreate(CxList *list) const {
  36.594 +        EXPECT_EQ(list->content_destructor_type, CX_DESTRUCTOR_NONE);
  36.595 +        EXPECT_EQ(list->size, 0);
  36.596 +        EXPECT_EQ(list->allocator, &testingAllocator);
  36.597 +        EXPECT_EQ(list->cmpfunc, cx_cmp_int);
  36.598 +    }
  36.599 +
  36.600 +    void verifyAdd(
  36.601 +            CxList *list,
  36.602 +            bool as_pointer
  36.603 +    ) {
  36.604 +        auto len = testdata_len;
  36.605 +        cx_for_n (i, len) EXPECT_EQ(cxListAdd(list, &testdata.data[i]), 0);
  36.606 +        EXPECT_EQ(list->size, len);
  36.607 +        EXPECT_GE(list->capacity, list->size);
  36.608 +        cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  36.609 +        cx_for_n (i, len) ++testdata.data[i];
  36.610 +        if (as_pointer) {
  36.611 +            cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  36.612 +        } else {
  36.613 +            cx_for_n (i, len) EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i] - 1);
  36.614 +        }
  36.615 +    }
  36.616 +
  36.617 +    static void verifyInsert(CxList *list) {
  36.618 +        int a = 5, b = 47, c = 13, d = 42;
  36.619 +
  36.620 +        EXPECT_NE(cxListInsert(list, 1, &a), 0);
  36.621 +        EXPECT_EQ(list->size, 0);
  36.622 +        EXPECT_EQ(cxListInsert(list, 0, &a), 0);
  36.623 +        EXPECT_EQ(list->size, 1);
  36.624 +        EXPECT_EQ(cxListInsert(list, 0, &b), 0);
  36.625 +        EXPECT_EQ(list->size, 2);
  36.626 +        EXPECT_EQ(cxListInsert(list, 1, &c), 0);
  36.627 +        EXPECT_EQ(list->size, 3);
  36.628 +        EXPECT_EQ(cxListInsert(list, 3, &d), 0);
  36.629 +
  36.630 +        ASSERT_EQ(list->size, 4);
  36.631 +        EXPECT_GE(list->capacity, list->size);
  36.632 +
  36.633 +        EXPECT_EQ(*(int *) cxListAt(list, 0), 47);
  36.634 +        EXPECT_EQ(*(int *) cxListAt(list, 1), 13);
  36.635 +        EXPECT_EQ(*(int *) cxListAt(list, 2), 5);
  36.636 +        EXPECT_EQ(*(int *) cxListAt(list, 3), 42);
  36.637 +    }
  36.638 +
  36.639 +    static void verifyInsertArray(
  36.640 +            CxList *list,
  36.641 +            bool pointers = false
  36.642 +    ) {
  36.643 +        int a[5] = {5, 47, 11, 13, 42};
  36.644 +        int b[5] = {9, 18, 72, 50, 7};
  36.645 +        int *aptr[5];
  36.646 +        int *bptr[5];
  36.647 +        cx_for_n(i, 5) {
  36.648 +            aptr[i] = &a[i];
  36.649 +            bptr[i] = &b[i];
  36.650 +        }
  36.651 +
  36.652 +        size_t inserted;
  36.653 +
  36.654 +        if (pointers) {
  36.655 +            inserted = cxListInsertArray(list, 0, aptr, 5);
  36.656 +        } else {
  36.657 +            inserted = cxListInsertArray(list, 0, a, 5);
  36.658 +        }
  36.659 +        EXPECT_EQ(inserted, 5);
  36.660 +        EXPECT_EQ(*(int *) cxListAt(list, 0), 5);
  36.661 +        EXPECT_EQ(*(int *) cxListAt(list, 1), 47);
  36.662 +        EXPECT_EQ(*(int *) cxListAt(list, 2), 11);
  36.663 +        EXPECT_EQ(*(int *) cxListAt(list, 3), 13);
  36.664 +        EXPECT_EQ(*(int *) cxListAt(list, 4), 42);
  36.665 +        if (pointers) {
  36.666 +            inserted = cxListInsertArray(list, 3, bptr, 5);
  36.667 +        } else {
  36.668 +            inserted = cxListInsertArray(list, 3, b, 5);
  36.669 +        }
  36.670 +        EXPECT_EQ(inserted, 5);
  36.671 +        EXPECT_EQ(*(int *) cxListAt(list, 0), 5);
  36.672 +        EXPECT_EQ(*(int *) cxListAt(list, 1), 47);
  36.673 +        EXPECT_EQ(*(int *) cxListAt(list, 2), 11);
  36.674 +        EXPECT_EQ(*(int *) cxListAt(list, 3), 9);
  36.675 +        EXPECT_EQ(*(int *) cxListAt(list, 4), 18);
  36.676 +        EXPECT_EQ(*(int *) cxListAt(list, 5), 72);
  36.677 +        EXPECT_EQ(*(int *) cxListAt(list, 6), 50);
  36.678 +        EXPECT_EQ(*(int *) cxListAt(list, 7), 7);
  36.679 +        EXPECT_EQ(*(int *) cxListAt(list, 8), 13);
  36.680 +        EXPECT_EQ(*(int *) cxListAt(list, 9), 42);
  36.681 +    }
  36.682 +
  36.683 +    void verifyRemove(CxList *list) const {
  36.684 +        EXPECT_EQ(cxListRemove(list, 2), 0);
  36.685 +        EXPECT_EQ(cxListRemove(list, 4), 0);
  36.686 +        EXPECT_EQ(list->size, testdata_len - 2);
  36.687 +        EXPECT_GE(list->capacity, list->size);
  36.688 +        EXPECT_EQ(*(int *) cxListAt(list, 0), testdata.data[0]);
  36.689 +        EXPECT_EQ(*(int *) cxListAt(list, 1), testdata.data[1]);
  36.690 +        EXPECT_EQ(*(int *) cxListAt(list, 2), testdata.data[3]);
  36.691 +        EXPECT_EQ(*(int *) cxListAt(list, 3), testdata.data[4]);
  36.692 +        EXPECT_EQ(*(int *) cxListAt(list, 4), testdata.data[6]);
  36.693 +
  36.694 +        EXPECT_EQ(cxListRemove(list, 0), 0);
  36.695 +        EXPECT_EQ(list->size, testdata_len - 3);
  36.696 +        EXPECT_GE(list->capacity, list->size);
  36.697 +        EXPECT_EQ(*(int *) cxListAt(list, 0), testdata.data[1]);
  36.698 +        EXPECT_EQ(*(int *) cxListAt(list, 1), testdata.data[3]);
  36.699 +
  36.700 +        EXPECT_NE(cxListRemove(list, testdata_len), 0);
  36.701 +    }
  36.702 +
  36.703 +    static void verifySwap(CxList *list) {
  36.704 +        ASSERT_EQ(list->size, 0);
  36.705 +
  36.706 +        int original[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
  36.707 +        int swapped[16] = {8, 4, 14, 3, 1, 5, 9, 12, 0, 6, 11, 10, 7, 15, 2, 13};
  36.708 +
  36.709 +        // we have to add the items one by one, because it could be a pointer list
  36.710 +        cx_for_n(i, 16) {
  36.711 +            cxListAdd(list, &original[i]);
  36.712 +        }
  36.713 +
  36.714 +        int result;
  36.715 +
  36.716 +        // execute the test two times with different item sizes
  36.717 +        result = cxListSwap(list, 1, 4);
  36.718 +        EXPECT_EQ(0, result);
  36.719 +        result = cxListSwap(list, 2, 14);
  36.720 +        EXPECT_EQ(0, result);
  36.721 +        result = cxListSwap(list, 9, 6);
  36.722 +        EXPECT_EQ(0, result);
  36.723 +        result = cxListSwap(list, 3, 3);
  36.724 +        EXPECT_EQ(0, result);
  36.725 +        result = cxListSwap(list, 10, 11);
  36.726 +        EXPECT_EQ(0, result);
  36.727 +        result = cxListSwap(list, 8, 0);
  36.728 +        EXPECT_EQ(0, result);
  36.729 +        result = cxListSwap(list, 7, 12);
  36.730 +        EXPECT_EQ(0, result);
  36.731 +        result = cxListSwap(list, 13, 15);
  36.732 +        EXPECT_EQ(0, result);
  36.733 +
  36.734 +        result = cxListSwap(list, 5, 16);
  36.735 +        EXPECT_NE(0, result);
  36.736 +        result = cxListSwap(list, 16, 6);
  36.737 +        EXPECT_NE(0, result);
  36.738 +        result = cxListSwap(list, 16, 17);
  36.739 +        EXPECT_NE(0, result);
  36.740 +
  36.741 +        auto iter = cxListBegin(list);
  36.742 +        cx_foreach(int*, e, iter) {
  36.743 +            EXPECT_EQ(*e, swapped[iter.index]);
  36.744 +        }
  36.745 +        // TODO: replace with backward iterator
  36.746 +        cx_for_n(i, 16) {
  36.747 +            EXPECT_EQ(*((int *) cxListAt(list, i)), swapped[i]);
  36.748 +        }
  36.749 +    }
  36.750 +
  36.751 +    void verifyAt(CxList *list) const {
  36.752 +        auto len = testdata_len;
  36.753 +        EXPECT_EQ(list->size, len);
  36.754 +        cx_for_n (i, len) {
  36.755 +            EXPECT_EQ(*(int *) cxListAt(list, i), testdata.data[i]);
  36.756 +        }
  36.757 +        EXPECT_EQ(cxListAt(list, list->size), nullptr);
  36.758 +    }
  36.759 +
  36.760 +    void verifyFind(CxList *list) const {
  36.761 +        cx_for_n (attempt, 25) {
  36.762 +            size_t exp = rand() % testdata_len; // NOLINT(cert-msc50-cpp)
  36.763 +            int val = testdata.data[exp];
  36.764 +            // randomly picked number could occur earlier in list - find first position
  36.765 +            cx_for_n (i, exp) {
  36.766 +                if (testdata.data[i] == val) {
  36.767 +                    exp = i;
  36.768 +                    break;
  36.769 +                }
  36.770 +            }
  36.771 +            EXPECT_EQ(cxListFind(list, &val), exp);
  36.772 +        }
  36.773 +    }
  36.774 +
  36.775 +    void verifySort(CxList *list) const {
  36.776 +        std::array<int, testdata_len> expected{};
  36.777 +        std::partial_sort_copy(testdata.data.begin(), testdata.data.end(), expected.begin(), expected.end());
  36.778 +        cxListSort(list);
  36.779 +        cx_for_n (i, testdata_len) ASSERT_EQ(*(int *) cxListAt(list, i), expected[i]);
  36.780 +    }
  36.781 +
  36.782 +    void verifyIterator(CxList *list) const {
  36.783 +        int i = 0;
  36.784 +        auto iter = cxListBeginMut(list);
  36.785 +        cx_foreach(int*, x, iter) {
  36.786 +            ASSERT_EQ(iter.index, (size_t) (i + 1) / 2);
  36.787 +            ASSERT_EQ(*x, testdata.data[i]);
  36.788 +            if (i % 2 == 1) cxIteratorFlagRemoval(iter);
  36.789 +            i++;
  36.790 +        }
  36.791 +        auto len = testdata_len;
  36.792 +        EXPECT_EQ(i, len);
  36.793 +        ASSERT_EQ(list->size, len / 2);
  36.794 +        cx_for_n(j, len / 2) ASSERT_EQ(*(int *) cxListAt(list, j), testdata.data[j * 2]);
  36.795 +    }
  36.796 +
  36.797 +    static void verifyInsertViaIterator(CxList *list) {
  36.798 +        int newdata[] = {10, 20, 30, 40, 50};
  36.799 +
  36.800 +        auto iter = cxListMutIterator(list, 2);
  36.801 +        EXPECT_TRUE(cxIteratorValid(iter));
  36.802 +        EXPECT_EQ(iter.index, 2);
  36.803 +        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  36.804 +        cxListInsertAfter(&iter, &newdata[0]);
  36.805 +        EXPECT_TRUE(cxIteratorValid(iter));
  36.806 +        EXPECT_EQ(iter.index, 2);
  36.807 +        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  36.808 +        cxListInsertBefore(&iter, &newdata[1]);
  36.809 +        EXPECT_TRUE(cxIteratorValid(iter));
  36.810 +        EXPECT_EQ(iter.index, 3);
  36.811 +        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 2);
  36.812 +
  36.813 +        iter = cxListBeginMut(list);
  36.814 +        cxListInsertBefore(&iter, &newdata[2]);
  36.815 +        EXPECT_TRUE(cxIteratorValid(iter));
  36.816 +        EXPECT_EQ(iter.index, 1);
  36.817 +        EXPECT_EQ(*(int *) cxIteratorCurrent(iter), 0);
  36.818 +        iter = cxListMutIterator(list, list->size);
  36.819 +        cxListInsertBefore(&iter, &newdata[3]);
  36.820 +        EXPECT_FALSE(cxIteratorValid(iter));
  36.821 +        EXPECT_EQ(iter.index, 9);
  36.822 +        iter = cxListMutIterator(list, list->size);
  36.823 +        cxListInsertAfter(&iter, &newdata[4]);
  36.824 +        EXPECT_FALSE(cxIteratorValid(iter));
  36.825 +        EXPECT_EQ(iter.index, 10);
  36.826 +
  36.827 +        int expdata[] = {30, 0, 1, 20, 2, 10, 3, 4, 40, 50};
  36.828 +        cx_for_n (j, 10) EXPECT_EQ(*(int *) cxListAt(list, j), expdata[j]);
  36.829 +    }
  36.830 +
  36.831 +    void verifyReverse(CxList *list) const {
  36.832 +        cxListReverse(list);
  36.833 +        cx_for_n(i, testdata_len) {
  36.834 +            ASSERT_EQ(*(int *) cxListAt(list, i), testdata.data[testdata_len - 1 - i]);
  36.835 +        }
  36.836 +    }
  36.837 +
  36.838 +    static void verifyCompare(
  36.839 +            CxList *left,
  36.840 +            CxList *right
  36.841 +    ) {
  36.842 +        EXPECT_EQ(cxListCompare(left, right), 0);
  36.843 +        int x = 42;
  36.844 +        cxListAdd(left, &x);
  36.845 +        ASSERT_GT(left->size, right->size);
  36.846 +        EXPECT_GT(cxListCompare(left, right), 0);
  36.847 +        EXPECT_LT(cxListCompare(right, left), 0);
  36.848 +        cxListAdd(right, &x);
  36.849 +        ASSERT_EQ(left->size, right->size);
  36.850 +        EXPECT_EQ(cxListCompare(left, right), 0);
  36.851 +        int a = 5, b = 10;
  36.852 +        cxListInsert(left, 15, &a);
  36.853 +        cxListInsert(right, 15, &b);
  36.854 +        ASSERT_EQ(left->size, right->size);
  36.855 +        EXPECT_LT(cxListCompare(left, right), 0);
  36.856 +        EXPECT_GT(cxListCompare(right, left), 0);
  36.857 +        *(int *) cxListAt(left, 15) = 10;
  36.858 +        EXPECT_EQ(cxListCompare(left, right), 0);
  36.859 +    }
  36.860 +};
  36.861 +
  36.862 +class LinkedList : public HighLevelTest {
  36.863 +};
  36.864 +
  36.865 +class PointerLinkedList : public HighLevelTest {
  36.866 +};
  36.867 +
  36.868 +class ArrayList : public HighLevelTest {
  36.869 +};
  36.870 +
  36.871 +TEST_F(PointerLinkedList, cxListStorePointers) {
  36.872 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, 47));
  36.873 +    EXPECT_FALSE(cxListIsStoringPointers(list));
  36.874 +    cxListStorePointers(list);
  36.875 +    EXPECT_EQ(list->itemsize, sizeof(void *));
  36.876 +    EXPECT_NE(list->cl, nullptr);
  36.877 +    EXPECT_NE(list->climpl, nullptr);
  36.878 +    EXPECT_TRUE(cxListIsStoringPointers(list));
  36.879 +    cxListStoreObjects(list);
  36.880 +    EXPECT_NE(list->cl, nullptr);
  36.881 +    EXPECT_EQ(list->climpl, nullptr);
  36.882 +    EXPECT_FALSE(cxListIsStoringPointers(list));
  36.883 +}
  36.884 +
  36.885 +TEST_F(LinkedList, cxLinkedListCreate) {
  36.886 +    CxList *list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  36.887 +    ASSERT_NE(list, nullptr);
  36.888 +    EXPECT_EQ(list->itemsize, sizeof(int));
  36.889 +    EXPECT_EQ(list->capacity, (size_t) -1);
  36.890 +    verifyCreate(list);
  36.891 +}
  36.892 +
  36.893 +TEST_F(ArrayList, cxArrayListCreate) {
  36.894 +    CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8));
  36.895 +    ASSERT_NE(list, nullptr);
  36.896 +    EXPECT_EQ(list->itemsize, sizeof(int));
  36.897 +    EXPECT_EQ(list->capacity, 8);
  36.898 +    verifyCreate(list);
  36.899 +}
  36.900 +
  36.901 +TEST_F(LinkedList, cxListAdd) {
  36.902 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
  36.903 +    verifyAdd(list, false);
  36.904 +}
  36.905 +
  36.906 +TEST_F(PointerLinkedList, cxListAdd) {
  36.907 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  36.908 +    cxListStorePointers(list);
  36.909 +    verifyAdd(list, true);
  36.910 +}
  36.911 +
  36.912 +TEST_F(ArrayList, cxListAdd) {
  36.913 +    auto list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8));
  36.914 +    verifyAdd(list, false);
  36.915 +}
  36.916 +
  36.917 +TEST_F(LinkedList, cxListInsert) {
  36.918 +    verifyInsert(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  36.919 +}
  36.920 +
  36.921 +TEST_F(PointerLinkedList, cxListInsert) {
  36.922 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  36.923 +    cxListStorePointers(list);
  36.924 +    verifyInsert(list);
  36.925 +}
  36.926 +
  36.927 +TEST_F(ArrayList, cxListInsert) {
  36.928 +    verifyInsert(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 2)));
  36.929 +}
  36.930 +
  36.931 +TEST_F(LinkedList, cxListInsertArray) {
  36.932 +    verifyInsertArray(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  36.933 +}
  36.934 +
  36.935 +TEST_F(PointerLinkedList, cxListInsertArray) {
  36.936 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  36.937 +    cxListStorePointers(list);
  36.938 +    verifyInsertArray(list, true);
  36.939 +}
  36.940 +
  36.941 +TEST_F(ArrayList, cxListInsertArray) {
  36.942 +    verifyInsertArray(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 4)));
  36.943 +}
  36.944 +
  36.945 +TEST_F(LinkedList, cxListRemove) {
  36.946 +    verifyRemove(linkedListFromTestData());
  36.947 +}
  36.948 +
  36.949 +TEST_F(PointerLinkedList, cxListRemove) {
  36.950 +    verifyRemove(pointerLinkedListFromTestData());
  36.951 +}
  36.952 +
  36.953 +TEST_F(ArrayList, cxListRemove) {
  36.954 +    verifyRemove(arrayListFromTestData());
  36.955 +}
  36.956 +
  36.957 +TEST_F(LinkedList, cxListSwap) {
  36.958 +    verifySwap(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  36.959 +}
  36.960 +
  36.961 +TEST_F(PointerLinkedList, cxListSwap) {
  36.962 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  36.963 +    cxListStorePointers(list);
  36.964 +    verifySwap(list);
  36.965 +}
  36.966 +
  36.967 +TEST_F(ArrayList, cxListSwap) {
  36.968 +    verifySwap(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 16)));
  36.969 +}
  36.970 +
  36.971 +TEST_F(LinkedList, cxListSwapNoSBO) {
  36.972 +    CX_DISABLE_LINKED_LIST_SWAP_SBO = true;
  36.973 +    verifySwap(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
  36.974 +    CX_DISABLE_LINKED_LIST_SWAP_SBO = false;
  36.975 +}
  36.976 +
  36.977 +TEST_F(PointerLinkedList, cxListSwapNoSBO) {
  36.978 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
  36.979 +    cxListStorePointers(list);
  36.980 +    CX_DISABLE_LINKED_LIST_SWAP_SBO = true;
  36.981 +    verifySwap(list);
  36.982 +    CX_DISABLE_LINKED_LIST_SWAP_SBO = false;
  36.983 +}
  36.984 +
  36.985 +TEST_F(ArrayList, cxListSwapNoSBO) {
  36.986 +    CX_DISABLE_LINKED_LIST_SWAP_SBO = true;
  36.987 +    verifySwap(autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 16)));
  36.988 +    CX_DISABLE_LINKED_LIST_SWAP_SBO = false;
  36.989 +}
  36.990 +
  36.991 +TEST_F(LinkedList, cxListAt) {
  36.992 +    verifyAt(linkedListFromTestData());
  36.993 +}
  36.994 +
  36.995 +TEST_F(PointerLinkedList, cxListAt) {
  36.996 +    verifyAt(pointerLinkedListFromTestData());
  36.997 +}
  36.998 +
  36.999 +TEST_F(ArrayList, cxListAt) {
 36.1000 +    verifyAt(arrayListFromTestData());
 36.1001 +}
 36.1002 +
 36.1003 +TEST_F(LinkedList, cxListFind) {
 36.1004 +    verifyFind(linkedListFromTestData());
 36.1005 +}
 36.1006 +
 36.1007 +TEST_F(PointerLinkedList, cxListFind) {
 36.1008 +    verifyFind(pointerLinkedListFromTestData());
 36.1009 +}
 36.1010 +
 36.1011 +TEST_F(ArrayList, cxListFind) {
 36.1012 +    verifyFind(arrayListFromTestData());
 36.1013 +}
 36.1014 +
 36.1015 +TEST_F(LinkedList, cxListSort) {
 36.1016 +    verifySort(linkedListFromTestData());
 36.1017 +}
 36.1018 +
 36.1019 +TEST_F(PointerLinkedList, cxListSort) {
 36.1020 +    verifySort(pointerLinkedListFromTestData());
 36.1021 +}
 36.1022 +
 36.1023 +TEST_F(ArrayList, cxListSort) {
 36.1024 +    verifySort(arrayListFromTestData());
 36.1025 +}
 36.1026 +
 36.1027 +TEST_F(LinkedList, Iterator) {
 36.1028 +    verifyIterator(linkedListFromTestData());
 36.1029 +}
 36.1030 +
 36.1031 +TEST_F(PointerLinkedList, Iterator) {
 36.1032 +    verifyIterator(pointerLinkedListFromTestData());
 36.1033 +}
 36.1034 +
 36.1035 +TEST_F(ArrayList, Iterator) {
 36.1036 +    verifyIterator(arrayListFromTestData());
 36.1037 +}
 36.1038 +
 36.1039 +TEST_F(LinkedList, InsertViaIterator) {
 36.1040 +    int fivenums[] = {0, 1, 2, 3, 4, 5};
 36.1041 +    CxList *list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int)));
 36.1042 +    cxListAddArray(list, fivenums, 5);
 36.1043 +    verifyInsertViaIterator(list);
 36.1044 +}
 36.1045 +
 36.1046 +TEST_F(PointerLinkedList, InsertViaIterator) {
 36.1047 +    int fivenums[] = {0, 1, 2, 3, 4, 5};
 36.1048 +    auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int *)));
 36.1049 +    cxListStorePointers(list);
 36.1050 +    // note: cannot use cxListAddArray() because we don't have a list of pointers
 36.1051 +    cx_for_n(i, 5) cxListAdd(list, &fivenums[i]);
 36.1052 +    verifyInsertViaIterator(list);
 36.1053 +}
 36.1054 +
 36.1055 +TEST_F(ArrayList, InsertViaIterator) {
 36.1056 +    int fivenums[] = {0, 1, 2, 3, 4, 5};
 36.1057 +    CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 4));
 36.1058 +    cxListAddArray(list, fivenums, 5);
 36.1059 +    verifyInsertViaIterator(list);
 36.1060 +}
 36.1061 +
 36.1062 +TEST_F(LinkedList, cxListReverse) {
 36.1063 +    verifyReverse(linkedListFromTestData());
 36.1064 +}
 36.1065 +
 36.1066 +TEST_F(PointerLinkedList, cxListReverse) {
 36.1067 +    verifyReverse(pointerLinkedListFromTestData());
 36.1068 +}
 36.1069 +
 36.1070 +TEST_F(ArrayList, cxListReverse) {
 36.1071 +    verifyReverse(arrayListFromTestData());
 36.1072 +}
 36.1073 +
 36.1074 +TEST_F(LinkedList, cxListCompare) {
 36.1075 +    auto left = linkedListFromTestData();
 36.1076 +    auto right = linkedListFromTestData();
 36.1077 +    verifyCompare(left, right);
 36.1078 +}
 36.1079 +
 36.1080 +TEST_F(LinkedList, cxListCompareWithPtrList) {
 36.1081 +    auto left = linkedListFromTestData();
 36.1082 +    auto right = pointerLinkedListFromTestData();
 36.1083 +    verifyCompare(left, right);
 36.1084 +}
 36.1085 +
 36.1086 +TEST_F(LinkedList, cxListCompareWithArrayList) {
 36.1087 +    auto left = linkedListFromTestData();
 36.1088 +    auto right = arrayListFromTestData();
 36.1089 +    verifyCompare(left, right);
 36.1090 +}
 36.1091 +
 36.1092 +TEST_F(PointerLinkedList, cxListCompare) {
 36.1093 +    auto left = pointerLinkedListFromTestData();
 36.1094 +    auto right = pointerLinkedListFromTestData();
 36.1095 +    verifyCompare(left, right);
 36.1096 +}
 36.1097 +
 36.1098 +TEST_F(PointerLinkedList, cxListCompareWithNormalList) {
 36.1099 +    auto left = pointerLinkedListFromTestData();
 36.1100 +    auto right = linkedListFromTestData();
 36.1101 +    verifyCompare(left, right);
 36.1102 +}
 36.1103 +
 36.1104 +TEST_F(PointerLinkedList, cxListCompareWithArrayList) {
 36.1105 +    auto left = pointerLinkedListFromTestData();
 36.1106 +    auto right = arrayListFromTestData();
 36.1107 +    verifyCompare(left, right);
 36.1108 +}
 36.1109 +
 36.1110 +TEST_F(ArrayList, cxListCompare) {
 36.1111 +    auto left = arrayListFromTestData();
 36.1112 +    auto right = arrayListFromTestData();
 36.1113 +    verifyCompare(left, right);
 36.1114 +}
 36.1115 +
 36.1116 +TEST_F(ArrayList, cxListCompareWithPtrList) {
 36.1117 +    auto left = arrayListFromTestData();
 36.1118 +    auto right = pointerLinkedListFromTestData();
 36.1119 +    verifyCompare(left, right);
 36.1120 +}
 36.1121 +
 36.1122 +TEST_F(ArrayList, cxListCompareWithNormalList) {
 36.1123 +    auto left = arrayListFromTestData();
 36.1124 +    auto right = linkedListFromTestData();
 36.1125 +    verifyCompare(left, right);
 36.1126 +}
 36.1127 +
 36.1128 +TEST_F(PointerLinkedList, NoDestructor) {
 36.1129 +    void *item = cxMalloc(&testingAllocator, sizeof(int));
 36.1130 +    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 36.1131 +    cxListStorePointers(list);
 36.1132 +    cxListAdd(list, item);
 36.1133 +    ASSERT_FALSE(testingAllocator.verify());
 36.1134 +    cxListDestroy(list);
 36.1135 +    EXPECT_FALSE(testingAllocator.verify());
 36.1136 +    cxFree(&testingAllocator, item);
 36.1137 +    EXPECT_TRUE(testingAllocator.verify());
 36.1138 +}
 36.1139 +
 36.1140 +TEST_F(PointerLinkedList, SimpleDestructor) {
 36.1141 +    int item = 0;
 36.1142 +    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 36.1143 +    cxListStorePointers(list);
 36.1144 +    list->content_destructor_type = CX_DESTRUCTOR_SIMPLE;
 36.1145 +    list->simple_destructor = [](void *elem) { *(int *) elem = 42; };
 36.1146 +    cxListAdd(list, &item);
 36.1147 +    cxListDestroy(list);
 36.1148 +    EXPECT_EQ(item, 42);
 36.1149 +}
 36.1150 +
 36.1151 +TEST_F(PointerLinkedList, AdvancedDestructor) {
 36.1152 +    void *item = cxMalloc(&testingAllocator, sizeof(int));
 36.1153 +    auto list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int *));
 36.1154 +    cxListStorePointers(list);
 36.1155 +    list->content_destructor_type = CX_DESTRUCTOR_ADVANCED;
 36.1156 +    list->advanced_destructor.data = &testingAllocator;
 36.1157 +    list->advanced_destructor.func = (cx_destructor_func2) cxFree;
 36.1158 +    cxListAdd(list, item);
 36.1159 +    ASSERT_FALSE(testingAllocator.verify());
 36.1160 +    cxListDestroy(list);
 36.1161 +    EXPECT_TRUE(testingAllocator.verify());
 36.1162 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/tests/test_map.cpp	Wed Feb 08 20:26:26 2023 +0100
    37.3 @@ -0,0 +1,272 @@
    37.4 +/*
    37.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    37.6 + *
    37.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    37.8 + *
    37.9 + * Redistribution and use in source and binary forms, with or without
   37.10 + * modification, are permitted provided that the following conditions are met:
   37.11 + *
   37.12 + *   1. Redistributions of source code must retain the above copyright
   37.13 + *      notice, this list of conditions and the following disclaimer.
   37.14 + *
   37.15 + *   2. Redistributions in binary form must reproduce the above copyright
   37.16 + *      notice, this list of conditions and the following disclaimer in the
   37.17 + *      documentation and/or other materials provided with the distribution.
   37.18 + *
   37.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   37.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   37.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   37.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   37.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   37.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   37.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   37.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   37.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   37.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37.29 + * POSSIBILITY OF SUCH DAMAGE.
   37.30 + */
   37.31 +
   37.32 +#include "cx/hash_map.h"
   37.33 +#include "cx/utils.h"
   37.34 +#include "util_allocator.h"
   37.35 +
   37.36 +#include <gtest/gtest.h>
   37.37 +#include <unordered_map>
   37.38 +#include <unordered_set>
   37.39 +
   37.40 +struct map_operation {
   37.41 +    enum {
   37.42 +        put, rm
   37.43 +    } op;
   37.44 +    char const *key;
   37.45 +    char const *value;
   37.46 +};
   37.47 +
   37.48 +auto generate_map_operations() -> std::vector<map_operation> {
   37.49 +    return {
   37.50 +            {map_operation::put, "key 1",          "test"},
   37.51 +            {map_operation::put, "key 2",          "blub"},
   37.52 +            {map_operation::put, "key 3",          "hallo"},
   37.53 +            {map_operation::put, "key 2",          "foobar"},
   37.54 +            {map_operation::put, "key 4",          "value 4"},
   37.55 +            {map_operation::put, "key 5",          "value 5"},
   37.56 +            {map_operation::put, "key 6",          "value 6"},
   37.57 +            {map_operation::rm,  "key 4",          nullptr},
   37.58 +            {map_operation::put, "key 7",          "value 7"},
   37.59 +            {map_operation::put, "key 8",          "value 8"},
   37.60 +            {map_operation::rm,  "does not exist", nullptr},
   37.61 +            {map_operation::put, "key 9",          "value 9"},
   37.62 +            {map_operation::put, "key 6",          "other value"},
   37.63 +            {map_operation::put, "key 7",          "something else"},
   37.64 +            {map_operation::rm,  "key 8",          nullptr},
   37.65 +            {map_operation::rm,  "key 2",          nullptr},
   37.66 +            {map_operation::put, "key 8",          "new value"},
   37.67 +    };
   37.68 +}
   37.69 +
   37.70 +static void verify_map_contents(
   37.71 +        CxMap *map,
   37.72 +        std::unordered_map<std::string, std::string> const &refmap
   37.73 +) {
   37.74 +    // verify key iterator
   37.75 +    {
   37.76 +        auto keyiter = cxMapIteratorKeys(map);
   37.77 +        std::unordered_set<std::string> keys;
   37.78 +        cx_foreach(CxHashKey*, elem, keyiter) {
   37.79 +            keys.insert(std::string(elem->data.cstr, elem->len));
   37.80 +        }
   37.81 +        EXPECT_EQ(keyiter.index, map->size);
   37.82 +        ASSERT_EQ(keys.size(), map->size);
   37.83 +        for (auto &&k: keys) {
   37.84 +            EXPECT_NE(refmap.find(k), refmap.end());
   37.85 +        }
   37.86 +    }
   37.87 +
   37.88 +    // verify value iterator
   37.89 +    {
   37.90 +        auto valiter = cxMapIteratorValues(map);
   37.91 +        std::unordered_set<std::string> values; // we use that the values in our test data are unique strings
   37.92 +        cx_foreach(char const*, elem, valiter) {
   37.93 +            values.insert(std::string(elem));
   37.94 +        }
   37.95 +        EXPECT_EQ(valiter.index, map->size);
   37.96 +        ASSERT_EQ(values.size(), map->size);
   37.97 +        for (auto &&v: values) {
   37.98 +            EXPECT_NE(std::find_if(refmap.begin(), refmap.end(),
   37.99 +                                   [v](auto const &e) { return e.second == v; }), refmap.end());
  37.100 +        }
  37.101 +    }
  37.102 +
  37.103 +    // verify pair iterator
  37.104 +    {
  37.105 +        auto pairiter = cxMapIterator(map);
  37.106 +        std::unordered_map<std::string, std::string> pairs;
  37.107 +        cx_foreach(CxMapEntry*, entry, pairiter) {
  37.108 +            pairs[std::string(entry->key->data.cstr, entry->key->len)] = std::string((char *) entry->value);
  37.109 +        }
  37.110 +        EXPECT_EQ(pairiter.index, map->size);
  37.111 +        ASSERT_EQ(pairs.size(), refmap.size());
  37.112 +        for (auto &&p: pairs) {
  37.113 +            ASSERT_EQ(p.second, refmap.at(p.first));
  37.114 +        }
  37.115 +    }
  37.116 +}
  37.117 +
  37.118 +TEST(CxHashMap, Create) {
  37.119 +    CxTestingAllocator allocator;
  37.120 +    auto map = cxHashMapCreate(&allocator, 0);
  37.121 +    auto hmap = reinterpret_cast<struct cx_hash_map_s *>(map);
  37.122 +    EXPECT_GT(hmap->bucket_count, 0);
  37.123 +    cx_for_n(i, hmap->bucket_count) {
  37.124 +        EXPECT_EQ(hmap->buckets[i], nullptr);
  37.125 +    }
  37.126 +    EXPECT_EQ(map->size, 0);
  37.127 +    EXPECT_EQ(map->allocator, &allocator);
  37.128 +
  37.129 +    cxMapDestroy(map);
  37.130 +    EXPECT_TRUE(allocator.verify());
  37.131 +}
  37.132 +
  37.133 +TEST(CxHashMap, BasicOperations) {
  37.134 +    // create the map
  37.135 +    CxTestingAllocator allocator;
  37.136 +    auto map = cxHashMapCreate(&allocator, 8);
  37.137 +
  37.138 +    // create a reference map
  37.139 +    std::unordered_map<std::string, std::string> refmap;
  37.140 +
  37.141 +    // generate operations
  37.142 +    auto ops = generate_map_operations();
  37.143 +
  37.144 +    // verify iterators for empty map
  37.145 +    verify_map_contents(map, refmap);
  37.146 +
  37.147 +    // execute operations and verify results
  37.148 +    for (auto &&op: ops) {
  37.149 +        CxHashKey key = cx_hash_key_str(op.key);
  37.150 +        key.hash = 0; // force the hash map to compute the hash
  37.151 +        if (op.op == map_operation::put) {
  37.152 +            // execute a put operation and verify that the exact value can be read back
  37.153 +            refmap[std::string(op.key)] = std::string(op.value);
  37.154 +            int result = cxMapPut(map, key, (void *) op.value);
  37.155 +            EXPECT_EQ(result, 0);
  37.156 +            auto added = cxMapGet(map, key);
  37.157 +            EXPECT_EQ(memcmp(op.value, added, strlen(op.value)), 0);
  37.158 +        } else {
  37.159 +            // execute a remove and verify that the removed element was returned (or nullptr)
  37.160 +            auto found = refmap.find(op.key);
  37.161 +            auto removed = cxMapRemove(map, key);
  37.162 +            if (found == refmap.end()) {
  37.163 +                EXPECT_EQ(removed, nullptr);
  37.164 +            } else {
  37.165 +                EXPECT_EQ(std::string((char *) removed), found->second);
  37.166 +                refmap.erase(found);
  37.167 +            }
  37.168 +        }
  37.169 +        // compare the current map state with the reference map
  37.170 +        verify_map_contents(map, refmap);
  37.171 +    }
  37.172 +
  37.173 +    // destroy the map and verify the memory (de)allocations
  37.174 +    cxMapDestroy(map);
  37.175 +    EXPECT_TRUE(allocator.verify());
  37.176 +}
  37.177 +
  37.178 +TEST(CxHashMap, RemoveViaIterator) {
  37.179 +    CxTestingAllocator allocator;
  37.180 +    auto map = cxHashMapCreate(&allocator, 4);
  37.181 +
  37.182 +    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  37.183 +    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  37.184 +    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  37.185 +    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  37.186 +    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  37.187 +    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  37.188 +
  37.189 +    auto iter = cxMapMutIterator(map);
  37.190 +    cx_foreach(CxMapEntry*, entry, iter) {
  37.191 +        if (entry->key->data.cstr[4] % 2 == 1) cxIteratorFlagRemoval(iter);
  37.192 +    }
  37.193 +    EXPECT_EQ(map->size, 3);
  37.194 +    EXPECT_EQ(iter.index, map->size);
  37.195 +
  37.196 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
  37.197 +    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
  37.198 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
  37.199 +    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 4")), nullptr);
  37.200 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 5")), nullptr);
  37.201 +    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 6")), nullptr);
  37.202 +
  37.203 +    cxMapDestroy(map);
  37.204 +    EXPECT_TRUE(allocator.verify());
  37.205 +}
  37.206 +
  37.207 +TEST(CxHashMap, RehashNotRequired) {
  37.208 +    CxTestingAllocator allocator;
  37.209 +    auto map = cxHashMapCreate(&allocator, 8);
  37.210 +
  37.211 +    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  37.212 +    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  37.213 +    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  37.214 +    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  37.215 +    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  37.216 +    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  37.217 +
  37.218 +    // 6/8 does not exceed 0.75, therefore the function should not rehash
  37.219 +    int result = cxMapRehash(map);
  37.220 +    EXPECT_EQ(result, 0);
  37.221 +    EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 8);
  37.222 +
  37.223 +    cxMapDestroy(map);
  37.224 +    EXPECT_TRUE(allocator.verify());
  37.225 +}
  37.226 +
  37.227 +TEST(CxHashMap, Rehash) {
  37.228 +    CxTestingAllocator allocator;
  37.229 +    auto map = cxHashMapCreate(&allocator, 8);
  37.230 +
  37.231 +    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  37.232 +    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  37.233 +    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  37.234 +    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
  37.235 +    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
  37.236 +    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
  37.237 +    cxMapPut(map, cx_hash_key_str("key 7"), (void *) "val 7");
  37.238 +
  37.239 +    int result = cxMapRehash(map);
  37.240 +    EXPECT_EQ(result, 0);
  37.241 +    EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 17);
  37.242 +    EXPECT_EQ(map->size, 7);
  37.243 +
  37.244 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 1")), "val 1"), 0);
  37.245 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 2")), "val 2"), 0);
  37.246 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 3")), "val 3"), 0);
  37.247 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 4")), "val 4"), 0);
  37.248 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 5")), "val 5"), 0);
  37.249 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 6")), "val 6"), 0);
  37.250 +    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 7")), "val 7"), 0);
  37.251 +
  37.252 +    cxMapDestroy(map);
  37.253 +    EXPECT_TRUE(allocator.verify());
  37.254 +}
  37.255 +
  37.256 +TEST(CxHashMap, Clear) {
  37.257 +    CxTestingAllocator allocator;
  37.258 +    auto map = cxHashMapCreate(&allocator, 0);
  37.259 +    
  37.260 +    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
  37.261 +    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
  37.262 +    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
  37.263 +
  37.264 +    EXPECT_EQ(map->size, 3);
  37.265 +
  37.266 +    cxMapClear(map);
  37.267 +
  37.268 +    EXPECT_EQ(map->size, 0);
  37.269 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
  37.270 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
  37.271 +    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
  37.272 +
  37.273 +    cxMapDestroy(map);
  37.274 +    EXPECT_TRUE(allocator.verify());
  37.275 +}
  37.276 \ No newline at end of file
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/tests/test_printf.cpp	Wed Feb 08 20:26:26 2023 +0100
    38.3 @@ -0,0 +1,248 @@
    38.4 +/*
    38.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    38.6 + *
    38.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    38.8 + *
    38.9 + * Redistribution and use in source and binary forms, with or without
   38.10 + * modification, are permitted provided that the following conditions are met:
   38.11 + *
   38.12 + *   1. Redistributions of source code must retain the above copyright
   38.13 + *      notice, this list of conditions and the following disclaimer.
   38.14 + *
   38.15 + *   2. Redistributions in binary form must reproduce the above copyright
   38.16 + *      notice, this list of conditions and the following disclaimer in the
   38.17 + *      documentation and/or other materials provided with the distribution.
   38.18 + *
   38.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   38.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   38.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   38.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   38.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   38.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   38.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   38.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   38.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   38.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   38.29 + * POSSIBILITY OF SUCH DAMAGE.
   38.30 + */
   38.31 +
   38.32 +#include "cx/printf.h"
   38.33 +#include "cx/buffer.h"
   38.34 +
   38.35 +#include <gtest/gtest.h>
   38.36 +#include "util_allocator.h"
   38.37 +
   38.38 +class PrintfFixture : public ::testing::Test {
   38.39 +protected:
   38.40 +    std::string buf;
   38.41 +    CxTestingAllocator alloc;
   38.42 +
   38.43 +    void TearDown() override {
   38.44 +        buf.clear();
   38.45 +        ASSERT_TRUE(alloc.verify());
   38.46 +    }
   38.47 +
   38.48 +    static size_t write_func(
   38.49 +            void const *src,
   38.50 +            size_t esize,
   38.51 +            size_t ecount,
   38.52 +            void *target
   38.53 +    ) {
   38.54 +        auto str = reinterpret_cast<char const *>(src);
   38.55 +        auto buf = reinterpret_cast<std::string *>(target);
   38.56 +        EXPECT_EQ(esize, 1);
   38.57 +        EXPECT_EQ(strlen(str), ecount);
   38.58 +        *buf = str;
   38.59 +        return ecount;
   38.60 +    }
   38.61 +};
   38.62 +
   38.63 +
   38.64 +TEST_F(PrintfFixture, BPrintf) {
   38.65 +    CxBuffer buf;
   38.66 +    cxBufferInit(&buf, nullptr, 64, &alloc, 0);
   38.67 +
   38.68 +    auto r = cx_bprintf(&buf, "This %s aged %u years in a %2XSK.", "Test", 10, 0xca);
   38.69 +    EXPECT_EQ(r, 34);
   38.70 +    EXPECT_EQ(buf.size, 34);
   38.71 +    buf.space[r] = '\0';
   38.72 +    EXPECT_STREQ(buf.space, "This Test aged 10 years in a CASK.");
   38.73 +
   38.74 +    cxBufferDestroy(&buf);
   38.75 +}
   38.76 +
   38.77 +TEST_F(PrintfFixture, FPrintf) {
   38.78 +    auto h = "Hello";
   38.79 +    size_t r;
   38.80 +
   38.81 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "teststring");
   38.82 +    EXPECT_EQ(r, 10);
   38.83 +    EXPECT_EQ(buf, "teststring");
   38.84 +
   38.85 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%10s]", h);
   38.86 +    EXPECT_EQ(r, 12);
   38.87 +    EXPECT_EQ(buf, "[     Hello]");
   38.88 +
   38.89 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-10s]", h);
   38.90 +    EXPECT_EQ(r, 12);
   38.91 +    EXPECT_EQ(buf, "[Hello     ]");
   38.92 +
   38.93 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%*s]", 10, h);
   38.94 +    EXPECT_EQ(r, 12);
   38.95 +    EXPECT_EQ(buf, "[     Hello]");
   38.96 +
   38.97 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-10.*s]", 4, h);
   38.98 +    EXPECT_EQ(r, 12);
   38.99 +    EXPECT_EQ(buf, "[Hell      ]");
  38.100 +
  38.101 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "[%-*.*s]", 10, 4, h);
  38.102 +    EXPECT_EQ(r, 12);
  38.103 +    EXPECT_EQ(buf, "[Hell      ]");
  38.104 +
  38.105 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%c", 'A');
  38.106 +    EXPECT_EQ(r, 1);
  38.107 +    EXPECT_EQ(buf, "A");
  38.108 +
  38.109 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
  38.110 +    EXPECT_EQ(r, 19);
  38.111 +    EXPECT_EQ(buf, "1 2 000003 0  +4 -4");
  38.112 +
  38.113 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%x %x %X %#x", 5, 10, 10, 6);
  38.114 +    EXPECT_EQ(r, 9);
  38.115 +    EXPECT_EQ(buf, "5 a A 0x6");
  38.116 +
  38.117 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%o %#o %#o", 10, 10, 4);
  38.118 +    EXPECT_EQ(r, 9);
  38.119 +    EXPECT_EQ(buf, "12 012 04");
  38.120 +
  38.121 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
  38.122 +    EXPECT_EQ(r, 16);
  38.123 +    EXPECT_EQ(buf, "01.50 1.50  1.50");
  38.124 +
  38.125 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "'%*c'", 5, 'x');
  38.126 +    EXPECT_EQ(r, 7);
  38.127 +    EXPECT_EQ(buf, "'    x'");
  38.128 +
  38.129 +    r = cx_fprintf(&buf, PrintfFixture::write_func, "'%*c'", -5, 'x');
  38.130 +    EXPECT_EQ(r, 7);
  38.131 +    EXPECT_EQ(buf, "'x    '");
  38.132 +}
  38.133 +
  38.134 +TEST_F(PrintfFixture, BPrintfLargeString) {
  38.135 +    CxBuffer buf;
  38.136 +    cxBufferInit(&buf, nullptr, 64, &alloc, CX_BUFFER_AUTO_EXTEND);
  38.137 +
  38.138 +    auto aaa = std::string(512, 'a');
  38.139 +    auto bbb = std::string(512, 'b');
  38.140 +
  38.141 +    auto r = cx_bprintf(&buf, "After %s comes %s.", aaa.data(), bbb.data());
  38.142 +    EXPECT_EQ(r, 1038);
  38.143 +    EXPECT_EQ(buf.size, 1038);
  38.144 +    cxBufferPut(&buf, 0);
  38.145 +    EXPECT_EQ(buf.space, std::string("After ") + aaa + " comes " + bbb + ".");
  38.146 +
  38.147 +    cxBufferDestroy(&buf);
  38.148 +}
  38.149 +
  38.150 +TEST_F(PrintfFixture, BPrintfNoCap) {
  38.151 +    CxBuffer buf;
  38.152 +    char space[20];
  38.153 +    memset(space, 'a', 20);
  38.154 +    cxBufferInit(&buf, space, 16, &alloc, 0);
  38.155 +
  38.156 +    auto r = cx_bprintf(&buf, "Hello %s with more than %d chars.", "string", 16);
  38.157 +    EXPECT_EQ(r, 16);
  38.158 +    EXPECT_EQ(buf.size, 16);
  38.159 +    EXPECT_EQ(0, memcmp(space, "Hello string witaaaa", 20));
  38.160 +
  38.161 +    cxBufferDestroy(&buf);
  38.162 +}
  38.163 +
  38.164 +TEST_F(PrintfFixture, SPrintf) {
  38.165 +    auto h = "Hello";
  38.166 +
  38.167 +    std::vector<char *> fl;
  38.168 +    cxmutstr r;
  38.169 +
  38.170 +    r = cx_asprintf_a(&alloc, "teststring");
  38.171 +    EXPECT_EQ(r.length, 10);
  38.172 +    EXPECT_STREQ(r.ptr, "teststring");
  38.173 +    fl.push_back(r.ptr);
  38.174 +
  38.175 +    r = cx_asprintf_a(&alloc, "[%10s]", h);
  38.176 +    EXPECT_EQ(r.length, 12);
  38.177 +    EXPECT_STREQ(r.ptr, "[     Hello]");
  38.178 +    fl.push_back(r.ptr);
  38.179 +
  38.180 +    r = cx_asprintf_a(&alloc, "[%-10s]", h);
  38.181 +    EXPECT_EQ(r.length, 12);
  38.182 +    EXPECT_STREQ(r.ptr, "[Hello     ]");
  38.183 +    fl.push_back(r.ptr);
  38.184 +
  38.185 +    r = cx_asprintf_a(&alloc, "[%*s]", 10, h);
  38.186 +    EXPECT_EQ(r.length, 12);
  38.187 +    EXPECT_STREQ(r.ptr, "[     Hello]");
  38.188 +    fl.push_back(r.ptr);
  38.189 +
  38.190 +    r = cx_asprintf_a(&alloc, "[%-10.*s]", 4, h);
  38.191 +    EXPECT_EQ(r.length, 12);
  38.192 +    EXPECT_STREQ(r.ptr, "[Hell      ]");
  38.193 +    fl.push_back(r.ptr);
  38.194 +
  38.195 +    r = cx_asprintf_a(&alloc, "[%-*.*s]", 10, 4, h);
  38.196 +    EXPECT_EQ(r.length, 12);
  38.197 +    EXPECT_STREQ(r.ptr, "[Hell      ]");
  38.198 +    fl.push_back(r.ptr);
  38.199 +
  38.200 +    r = cx_asprintf_a(&alloc, "%c", 'A');
  38.201 +    EXPECT_EQ(r.length, 1);
  38.202 +    EXPECT_STREQ(r.ptr, "A");
  38.203 +    fl.push_back(r.ptr);
  38.204 +
  38.205 +    r = cx_asprintf_a(&alloc, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
  38.206 +    EXPECT_EQ(r.length, 19);
  38.207 +    EXPECT_STREQ(r.ptr, "1 2 000003 0  +4 -4");
  38.208 +    fl.push_back(r.ptr);
  38.209 +
  38.210 +    r = cx_asprintf_a(&alloc, "%x %x %X %#x", 5, 10, 10, 6);
  38.211 +    EXPECT_EQ(r.length, 9);
  38.212 +    EXPECT_STREQ(r.ptr, "5 a A 0x6");
  38.213 +    fl.push_back(r.ptr);
  38.214 +
  38.215 +    r = cx_asprintf_a(&alloc, "%o %#o %#o", 10, 10, 4);
  38.216 +    EXPECT_EQ(r.length, 9);
  38.217 +    EXPECT_STREQ(r.ptr, "12 012 04");
  38.218 +    fl.push_back(r.ptr);
  38.219 +
  38.220 +    r = cx_asprintf_a(&alloc, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
  38.221 +    EXPECT_EQ(r.length, 16);
  38.222 +    EXPECT_STREQ(r.ptr, "01.50 1.50  1.50");
  38.223 +    fl.push_back(r.ptr);
  38.224 +
  38.225 +    r = cx_asprintf_a(&alloc, "'%*c'", 5, 'x');
  38.226 +    EXPECT_EQ(r.length, 7);
  38.227 +    EXPECT_STREQ(r.ptr, "'    x'");
  38.228 +    fl.push_back(r.ptr);
  38.229 +
  38.230 +    r = cx_asprintf_a(&alloc, "'%*c'", -5, 'x');
  38.231 +    EXPECT_EQ(r.length, 7);
  38.232 +    EXPECT_STREQ(r.ptr, "'x    '");
  38.233 +    fl.push_back(r.ptr);
  38.234 +
  38.235 +    for (auto c: fl) {
  38.236 +        auto s = cx_mutstrn(c, 0);
  38.237 +        cx_strfree_a(&alloc, &s);
  38.238 +    }
  38.239 +}
  38.240 +
  38.241 +TEST_F(PrintfFixture, SPrintfLargeString) {
  38.242 +    auto aaa = std::string(512, 'a');
  38.243 +    auto bbb = std::string(512, 'b');
  38.244 +
  38.245 +    auto r = cx_asprintf_a(&alloc, "After %s comes %s.", aaa.data(), bbb.data());
  38.246 +    EXPECT_EQ(r.length, 1038);
  38.247 +    EXPECT_EQ(r.ptr, std::string("After ") + aaa + " comes " + bbb + ".");
  38.248 +    EXPECT_EQ(r.ptr[1038], '\0');
  38.249 +
  38.250 +    cx_strfree_a(&alloc, &r);
  38.251 +}
  38.252 \ No newline at end of file
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/tests/test_string.cpp	Wed Feb 08 20:26:26 2023 +0100
    39.3 @@ -0,0 +1,865 @@
    39.4 +/*
    39.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    39.6 + *
    39.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    39.8 + *
    39.9 + * Redistribution and use in source and binary forms, with or without
   39.10 + * modification, are permitted provided that the following conditions are met:
   39.11 + *
   39.12 + *   1. Redistributions of source code must retain the above copyright
   39.13 + *      notice, this list of conditions and the following disclaimer.
   39.14 + *
   39.15 + *   2. Redistributions in binary form must reproduce the above copyright
   39.16 + *      notice, this list of conditions and the following disclaimer in the
   39.17 + *      documentation and/or other materials provided with the distribution.
   39.18 + *
   39.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   39.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   39.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   39.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   39.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   39.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   39.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   39.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   39.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   39.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   39.29 + * POSSIBILITY OF SUCH DAMAGE.
   39.30 + */
   39.31 +
   39.32 +#include "cx/string.h"
   39.33 +#include "util_allocator.h"
   39.34 +
   39.35 +#include <gtest/gtest.h>
   39.36 +
   39.37 +#define EXPECT_ZERO_TERMINATED(str) EXPECT_EQ((str).ptr[(str).length], '\0')
   39.38 +
   39.39 +TEST(String, construct) {
   39.40 +    cxstring s1 = cx_str("1234");
   39.41 +    cxstring s2 = cx_strn("abcd", 2);
   39.42 +    cxmutstr s3 = cx_mutstr((char *) "1234");
   39.43 +    cxmutstr s4 = cx_mutstrn((char *) "abcd", 2);
   39.44 +
   39.45 +    EXPECT_EQ(s1.length, 4);
   39.46 +    EXPECT_EQ(s2.length, 2);
   39.47 +    EXPECT_EQ(s3.length, 4);
   39.48 +    EXPECT_EQ(s4.length, 2);
   39.49 +}
   39.50 +
   39.51 +TEST(String, strfree) {
   39.52 +    CxTestingAllocator alloc;
   39.53 +    auto test = (char *) cxMalloc(&alloc, 16);
   39.54 +    cxmutstr str = cx_mutstrn(test, 16);
   39.55 +    ASSERT_EQ(str.ptr, test);
   39.56 +    EXPECT_EQ(str.length, 16);
   39.57 +    cx_strfree_a(&alloc, &str);
   39.58 +    EXPECT_EQ(str.ptr, nullptr);
   39.59 +    EXPECT_EQ(str.length, 0);
   39.60 +    EXPECT_TRUE(alloc.verify());
   39.61 +}
   39.62 +
   39.63 +TEST(String, strdup) {
   39.64 +    cxstring str = CX_STR("test");
   39.65 +    cxmutstr dup = cx_strdup(str);
   39.66 +    ASSERT_EQ(dup.length, str.length);
   39.67 +    EXPECT_STREQ(dup.ptr, str.ptr);
   39.68 +    EXPECT_ZERO_TERMINATED(dup);
   39.69 +    cx_strfree(&dup);
   39.70 +
   39.71 +    str.length = 2;
   39.72 +    dup = cx_strdup(str);
   39.73 +    ASSERT_EQ(dup.length, str.length);
   39.74 +    EXPECT_STREQ(dup.ptr, "te");
   39.75 +    EXPECT_ZERO_TERMINATED(dup);
   39.76 +    cx_strfree(&dup);
   39.77 +}
   39.78 +
   39.79 +TEST(String, strlen) {
   39.80 +    cxstring s1 = CX_STR("1234");
   39.81 +    cxstring s2 = CX_STR(".:.:.");
   39.82 +    cxstring s3 = CX_STR("X");
   39.83 +
   39.84 +    size_t len0 = cx_strlen(0);
   39.85 +    size_t len1 = cx_strlen(1, s1);
   39.86 +    size_t len2 = cx_strlen(2, s1, s2);
   39.87 +    size_t len3 = cx_strlen(3, s1, s2, s3);
   39.88 +
   39.89 +    EXPECT_EQ(len0, 0);
   39.90 +    EXPECT_EQ(len1, 4);
   39.91 +    EXPECT_EQ(len2, 9);
   39.92 +    EXPECT_EQ(len3, 10);
   39.93 +}
   39.94 +
   39.95 +TEST(String, strsubs) {
   39.96 +    cxstring str = CX_STR("A test string");
   39.97 +
   39.98 +    cxstring sub = cx_strsubs(str, 0);
   39.99 +    EXPECT_EQ(cx_strcmp(sub, str), 0);
  39.100 +
  39.101 +    sub = cx_strsubs(str, 2);
  39.102 +    EXPECT_EQ(cx_strcmp(sub, cx_str("test string")), 0);
  39.103 +
  39.104 +    sub = cx_strsubs(str, 7);
  39.105 +    EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
  39.106 +
  39.107 +    sub = cx_strsubs(str, 15);
  39.108 +    EXPECT_EQ(cx_strcmp(sub, cx_str("")), 0);
  39.109 +
  39.110 +    sub = cx_strsubsl(str, 2, 4);
  39.111 +    EXPECT_EQ(cx_strcmp(sub, cx_str("test")), 0);
  39.112 +
  39.113 +    sub = cx_strsubsl(str, 7, 3);
  39.114 +    EXPECT_EQ(cx_strcmp(sub, cx_str("str")), 0);
  39.115 +
  39.116 +    sub = cx_strsubsl(str, 7, 20);
  39.117 +    EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
  39.118 +
  39.119 +    // just for coverage, call the _m variant
  39.120 +    auto m = cx_strsubs_m(cx_mutstrn(nullptr, 0), 0);
  39.121 +    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  39.122 +}
  39.123 +
  39.124 +TEST(String, strchr) {
  39.125 +    cxstring str = CX_STR("I will find you - and I will kill you");
  39.126 +
  39.127 +    cxstring notfound = cx_strchr(str, 'x');
  39.128 +    EXPECT_EQ(notfound.length, 0);
  39.129 +
  39.130 +    cxstring result = cx_strchr(str, 'w');
  39.131 +    EXPECT_EQ(result.length, 35);
  39.132 +    EXPECT_STREQ(result.ptr, "will find you - and I will kill you");
  39.133 +
  39.134 +    // just for coverage, call the _m variant
  39.135 +    auto m = cx_strchr_m(cx_mutstrn(nullptr, 0), 'a');
  39.136 +    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  39.137 +}
  39.138 +
  39.139 +TEST(String, strrchr) {
  39.140 +    cxstring str = CX_STR("I will find you - and I will kill you");
  39.141 +
  39.142 +    cxstring notfound = cx_strrchr(str, 'x');
  39.143 +    EXPECT_EQ(notfound.length, 0);
  39.144 +
  39.145 +    cxstring result = cx_strrchr(str, 'w');
  39.146 +    EXPECT_EQ(result.length, 13);
  39.147 +    EXPECT_STREQ(result.ptr, "will kill you");
  39.148 +
  39.149 +    // just for coverage, call the _m variant
  39.150 +    auto m = cx_strrchr_m(cx_mutstrn(nullptr, 0), 'a');
  39.151 +    EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
  39.152 +}
  39.153 +
  39.154 +TEST(String, strstr) {
  39.155 +    cxstring str = CX_STR("find the match in this string");
  39.156 +    cxstring longstr = CX_STR(
  39.157 +            "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl"
  39.158 +            "mnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx"
  39.159 +            "yzabcdeababababnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij"
  39.160 +            "klmnopqrstuvwxyzaababababababababrstuvwxyzabcdefghijklmnopqrstuv"
  39.161 +            "abababababababababababababababababababababababababababababababab"
  39.162 +            "abababababababababababababababababababababababababababababababab"
  39.163 +            "abababababababababababababababababababababababababababababababab"
  39.164 +            "abababababababababababababababababababababababababababababababab"
  39.165 +            "abababababababababababababababababababababababababababababababab"
  39.166 +            "abababababababababababababababababababababababababababababababab"
  39.167 +            "wxyz1234567890");
  39.168 +    cxstring longstrpattern = CX_STR(
  39.169 +            "abababababababababababababababababababababababababababababababab"
  39.170 +            "abababababababababababababababababababababababababababababababab"
  39.171 +            "abababababababababababababababababababababababababababababababab"
  39.172 +            "abababababababababababababababababababababababababababababababab"
  39.173 +            "abababababababababababababababababababababababababababababababab"
  39.174 +    );
  39.175 +    cxstring longstrresult = CX_STR(
  39.176 +            "abababababababababababababababababababababababababababababababab"
  39.177 +            "abababababababababababababababababababababababababababababababab"
  39.178 +            "abababababababababababababababababababababababababababababababab"
  39.179 +            "abababababababababababababababababababababababababababababababab"
  39.180 +            "abababababababababababababababababababababababababababababababab"
  39.181 +            "abababababababababababababababababababababababababababababababab"
  39.182 +            "wxyz1234567890"
  39.183 +    );
  39.184 +
  39.185 +    cxstring notfound = cx_strstr(str, cx_str("no match"));
  39.186 +    EXPECT_EQ(notfound.length, 0);
  39.187 +
  39.188 +    cxstring result = cx_strstr(str, cx_str("match"));
  39.189 +    EXPECT_EQ(result.length, 20);
  39.190 +    EXPECT_STREQ(result.ptr, "match in this string");
  39.191 +
  39.192 +    result = cx_strstr(str, cx_str(""));
  39.193 +    EXPECT_EQ(result.length, str.length);
  39.194 +    EXPECT_STREQ(result.ptr, str.ptr);
  39.195 +
  39.196 +    result = cx_strstr(longstr, longstrpattern);
  39.197 +    EXPECT_EQ(result.length, longstrresult.length);
  39.198 +    EXPECT_STREQ(result.ptr, longstrresult.ptr);
  39.199 +
  39.200 +    // just for coverage, call the _m variant
  39.201 +    auto mstr = cx_strdup(longstr);
  39.202 +    auto m = cx_strstr_m(mstr, longstrpattern);
  39.203 +    EXPECT_EQ(m.length, longstrresult.length);
  39.204 +    EXPECT_STREQ(m.ptr, longstrresult.ptr);
  39.205 +    cx_strfree(&mstr);
  39.206 +}
  39.207 +
  39.208 +TEST(String, strcmp) {
  39.209 +    cxstring str = CX_STR("compare this");
  39.210 +
  39.211 +    EXPECT_EQ(cx_strcmp(cx_str(""), cx_str("")), 0);
  39.212 +    EXPECT_GT(cx_strcmp(str, cx_str("")), 0);
  39.213 +    EXPECT_EQ(cx_strcmp(str, cx_str("compare this")), 0);
  39.214 +    EXPECT_NE(cx_strcmp(str, cx_str("Compare This")), 0);
  39.215 +    EXPECT_LT(cx_strcmp(str, cx_str("compare tool")), 0);
  39.216 +    EXPECT_GT(cx_strcmp(str, cx_str("compare shit")), 0);
  39.217 +    EXPECT_LT(cx_strcmp(str, cx_str("compare this not")), 0);
  39.218 +    EXPECT_GT(cx_strcmp(str, cx_str("compare")), 0);
  39.219 +}
  39.220 +
  39.221 +TEST(String, strcasecmp) {
  39.222 +    cxstring str = CX_STR("compare this");
  39.223 +
  39.224 +    EXPECT_EQ(cx_strcasecmp(cx_str(""), cx_str("")), 0);
  39.225 +    EXPECT_GT(cx_strcasecmp(str, cx_str("")), 0);
  39.226 +    EXPECT_EQ(cx_strcasecmp(str, cx_str("compare this")), 0);
  39.227 +    EXPECT_EQ(cx_strcasecmp(str, cx_str("Compare This")), 0);
  39.228 +    EXPECT_LT(cx_strcasecmp(str, cx_str("compare tool")), 0);
  39.229 +    EXPECT_GT(cx_strcasecmp(str, cx_str("compare shit")), 0);
  39.230 +    EXPECT_LT(cx_strcasecmp(str, cx_str("compare this not")), 0);
  39.231 +    EXPECT_GT(cx_strcasecmp(str, cx_str("compare")), 0);
  39.232 +}
  39.233 +
  39.234 +TEST(String, strcat) {
  39.235 +    cxstring s1 = CX_STR("12");
  39.236 +    cxstring s2 = CX_STR("34");
  39.237 +    cxstring s3 = CX_STR("56");
  39.238 +    cxstring sn = {nullptr, 0};
  39.239 +
  39.240 +    CxTestingAllocator alloc;
  39.241 +
  39.242 +    cxmutstr t1 = cx_strcat_a(&alloc, 2, s1, s2);
  39.243 +    EXPECT_EQ(cx_strcmp(cx_strcast(t1), cx_str("1234")), 0);
  39.244 +    EXPECT_ZERO_TERMINATED(t1);
  39.245 +    cx_strfree_a(&alloc, &t1);
  39.246 +
  39.247 +    cxmutstr t2 = cx_strcat_a(&alloc, 3, s1, s2, s3);
  39.248 +    EXPECT_EQ(cx_strcmp(cx_strcast(t2), cx_str("123456")), 0);
  39.249 +    EXPECT_ZERO_TERMINATED(t2);
  39.250 +    cx_strfree_a(&alloc, &t2);
  39.251 +
  39.252 +    cxmutstr t3 = cx_strcat_a(&alloc, 6, s1, sn, s2, sn, s3, sn);
  39.253 +    EXPECT_EQ(cx_strcmp(cx_strcast(t3), cx_str("123456")), 0);
  39.254 +    EXPECT_ZERO_TERMINATED(t3);
  39.255 +    cx_strfree_a(&alloc, &t3);
  39.256 +
  39.257 +    cxmutstr t4 = cx_strcat_a(&alloc, 2, sn, sn);
  39.258 +    EXPECT_EQ(cx_strcmp(cx_strcast(t4), cx_str("")), 0);
  39.259 +    EXPECT_ZERO_TERMINATED(t4);
  39.260 +    cx_strfree_a(&alloc, &t4);
  39.261 +
  39.262 +    EXPECT_TRUE(alloc.verify());
  39.263 +
  39.264 +    // use the macro
  39.265 +    cxmutstr t5 = cx_strcat(3, s3, s1, s2);
  39.266 +    EXPECT_EQ(cx_strcmp(cx_strcast(t5), cx_str("561234")), 0);
  39.267 +    EXPECT_ZERO_TERMINATED(t5);
  39.268 +    cx_strfree(&t5);
  39.269 +}
  39.270 +
  39.271 +TEST(String, strsplit) {
  39.272 +
  39.273 +    cxstring test = cx_str("this,is,a,csv,string");
  39.274 +    size_t capa = 8;
  39.275 +    cxstring list[8];
  39.276 +    size_t n;
  39.277 +
  39.278 +    // special case: empty string
  39.279 +    n = cx_strsplit(test, cx_str(""), capa, list);
  39.280 +    ASSERT_EQ(n, 1);
  39.281 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  39.282 +
  39.283 +    // no delimiter occurrence
  39.284 +    n = cx_strsplit(test, cx_str("z"), capa, list);
  39.285 +    ASSERT_EQ(n, 1);
  39.286 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  39.287 +
  39.288 +    // partially matching delimiter
  39.289 +    n = cx_strsplit(test, cx_str("is,not"), capa, list);
  39.290 +    ASSERT_EQ(n, 1);
  39.291 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  39.292 +
  39.293 +    // matching single-char delimiter
  39.294 +    n = cx_strsplit(test, cx_str(","), capa, list);
  39.295 +    ASSERT_EQ(n, 5);
  39.296 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  39.297 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  39.298 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
  39.299 +    EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
  39.300 +    EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
  39.301 +
  39.302 +    // matching multi-char delimiter
  39.303 +    n = cx_strsplit(test, cx_str("is"), capa, list);
  39.304 +    ASSERT_EQ(n, 3);
  39.305 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  39.306 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
  39.307 +    EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
  39.308 +
  39.309 +    // bounded list using single-char delimiter
  39.310 +    n = cx_strsplit(test, cx_str(","), 3, list);
  39.311 +    ASSERT_EQ(n, 3);
  39.312 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  39.313 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  39.314 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  39.315 +
  39.316 +    // bounded list using multi-char delimiter
  39.317 +    n = cx_strsplit(test, cx_str("is"), 2, list);
  39.318 +    ASSERT_EQ(n, 2);
  39.319 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  39.320 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  39.321 +
  39.322 +    // start with delimiter
  39.323 +    n = cx_strsplit(test, cx_str("this"), capa, list);
  39.324 +    ASSERT_EQ(n, 2);
  39.325 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  39.326 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  39.327 +
  39.328 +    // end with delimiter
  39.329 +    n = cx_strsplit(test, cx_str("string"), capa, list);
  39.330 +    ASSERT_EQ(n, 2);
  39.331 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
  39.332 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  39.333 +
  39.334 +
  39.335 +    // end with delimiter exceed bound
  39.336 +    n = cx_strsplit(cx_str("a,b,c,"), cx_str(","), 3, list);
  39.337 +    ASSERT_EQ(n, 3);
  39.338 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
  39.339 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
  39.340 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
  39.341 +
  39.342 +    // exact match
  39.343 +    n = cx_strsplit(test, cx_str("this,is,a,csv,string"), capa, list);
  39.344 +    ASSERT_EQ(n, 2);
  39.345 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  39.346 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  39.347 +
  39.348 +    // string to be split is only substring
  39.349 +    n = cx_strsplit(test, cx_str("this,is,a,csv,string,with,extension"), capa, list);
  39.350 +    ASSERT_EQ(n, 1);
  39.351 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  39.352 +
  39.353 +    // subsequent encounter of delimiter (the string between is empty)
  39.354 +    n = cx_strsplit(test, cx_str("is,"), capa, list);
  39.355 +    ASSERT_EQ(n, 3);
  39.356 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  39.357 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  39.358 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  39.359 +
  39.360 +    // call the _m variant just for coverage
  39.361 +    auto mtest = cx_strdup(test);
  39.362 +    cxmutstr mlist[4];
  39.363 +    n = cx_strsplit_m(mtest, cx_str("is,"), 4, mlist);
  39.364 +    ASSERT_EQ(n, 3);
  39.365 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
  39.366 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
  39.367 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
  39.368 +    cx_strfree(&mtest);
  39.369 +}
  39.370 +
  39.371 +TEST(String, strsplit_a) {
  39.372 +    CxTestingAllocator alloc;
  39.373 +
  39.374 +    cxstring test = cx_str("this,is,a,csv,string");
  39.375 +    size_t capa = 8;
  39.376 +    cxstring *list;
  39.377 +    size_t n;
  39.378 +
  39.379 +    // special case: empty string
  39.380 +    n = cx_strsplit_a(&alloc, test, cx_str(""), capa, &list);
  39.381 +    ASSERT_EQ(n, 1);
  39.382 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  39.383 +    cxFree(&alloc, list);
  39.384 +
  39.385 +    // no delimiter occurrence
  39.386 +    n = cx_strsplit_a(&alloc, test, cx_str("z"), capa, &list);
  39.387 +    ASSERT_EQ(n, 1);
  39.388 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  39.389 +    cxFree(&alloc, list);
  39.390 +
  39.391 +    // partially matching delimiter
  39.392 +    n = cx_strsplit_a(&alloc, test, cx_str("is,not"), capa, &list);
  39.393 +    ASSERT_EQ(n, 1);
  39.394 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  39.395 +    cxFree(&alloc, list);
  39.396 +
  39.397 +    // matching single-char delimiter
  39.398 +    n = cx_strsplit_a(&alloc, test, cx_str(","), capa, &list);
  39.399 +    ASSERT_EQ(n, 5);
  39.400 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  39.401 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  39.402 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
  39.403 +    EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
  39.404 +    EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
  39.405 +    cxFree(&alloc, list);
  39.406 +
  39.407 +    // matching multi-char delimiter
  39.408 +    n = cx_strsplit_a(&alloc, test, cx_str("is"), capa, &list);
  39.409 +    ASSERT_EQ(n, 3);
  39.410 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  39.411 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
  39.412 +    EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
  39.413 +    cxFree(&alloc, list);
  39.414 +
  39.415 +    // bounded list using single-char delimiter
  39.416 +    n = cx_strsplit_a(&alloc, test, cx_str(","), 3, &list);
  39.417 +    ASSERT_EQ(n, 3);
  39.418 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
  39.419 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
  39.420 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  39.421 +    cxFree(&alloc, list);
  39.422 +
  39.423 +    // bounded list using multi-char delimiter
  39.424 +    n = cx_strsplit_a(&alloc, test, cx_str("is"), 2, &list);
  39.425 +    ASSERT_EQ(n, 2);
  39.426 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  39.427 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  39.428 +    cxFree(&alloc, list);
  39.429 +
  39.430 +    // start with delimiter
  39.431 +    n = cx_strsplit_a(&alloc, test, cx_str("this"), capa, &list);
  39.432 +    ASSERT_EQ(n, 2);
  39.433 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  39.434 +    EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
  39.435 +    cxFree(&alloc, list);
  39.436 +
  39.437 +    // end with delimiter
  39.438 +    n = cx_strsplit_a(&alloc, test, cx_str("string"), capa, &list);
  39.439 +    ASSERT_EQ(n, 2);
  39.440 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
  39.441 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  39.442 +    cxFree(&alloc, list);
  39.443 +
  39.444 +    // end with delimiter exceed bound
  39.445 +    n = cx_strsplit_a(&alloc, cx_str("a,b,c,"), cx_str(","), 3, &list);
  39.446 +    ASSERT_EQ(n, 3);
  39.447 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
  39.448 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
  39.449 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
  39.450 +    cxFree(&alloc, list);
  39.451 +
  39.452 +    // exact match
  39.453 +    n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string"), capa, &list);
  39.454 +    ASSERT_EQ(n, 2);
  39.455 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
  39.456 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  39.457 +    cxFree(&alloc, list);
  39.458 +
  39.459 +    // string to be split is only substring
  39.460 +    n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string,with,extension"), capa, &list);
  39.461 +    ASSERT_EQ(n, 1);
  39.462 +    EXPECT_EQ(cx_strcmp(list[0], test), 0);
  39.463 +    cxFree(&alloc, list);
  39.464 +
  39.465 +    // subsequent encounter of delimiter (the string between is empty)
  39.466 +    n = cx_strsplit_a(&alloc, test, cx_str("is,"), capa, &list);
  39.467 +    ASSERT_EQ(n, 3);
  39.468 +    EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
  39.469 +    EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
  39.470 +    EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
  39.471 +    cxFree(&alloc, list);
  39.472 +
  39.473 +    // call the _m variant just for coverage
  39.474 +    auto mtest = cx_strdup(test);
  39.475 +    cxmutstr *mlist;
  39.476 +    n = cx_strsplit_ma(&alloc, mtest, cx_str("is,"), 4, &mlist);
  39.477 +    ASSERT_EQ(n, 3);
  39.478 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
  39.479 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
  39.480 +    EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
  39.481 +    cxFree(&alloc, mlist);
  39.482 +    cx_strfree(&mtest);
  39.483 +
  39.484 +    EXPECT_TRUE(alloc.verify());
  39.485 +}
  39.486 +
  39.487 +TEST(String, strtrim) {
  39.488 +    cxstring t1 = cx_strtrim(cx_str("  ein test  \t "));
  39.489 +    cxstring t2 = cx_strtrim(cx_str("abc"));
  39.490 +    cxstring t3 = cx_strtrim(cx_str(" 123"));
  39.491 +    cxstring t4 = cx_strtrim(cx_str("xyz "));
  39.492 +    cxstring t5 = cx_strtrim(cx_str("   "));
  39.493 +    cxstring empty = cx_strtrim(cx_str(""));
  39.494 +
  39.495 +    EXPECT_EQ(cx_strcmp(t1, cx_str("ein test")), 0);
  39.496 +    EXPECT_EQ(cx_strcmp(t2, cx_str("abc")), 0);
  39.497 +    EXPECT_EQ(cx_strcmp(t3, cx_str("123")), 0);
  39.498 +    EXPECT_EQ(cx_strcmp(t4, cx_str("xyz")), 0);
  39.499 +    EXPECT_EQ(cx_strcmp(t5, cx_str("")), 0);
  39.500 +    EXPECT_EQ(cx_strcmp(empty, cx_str("")), 0);
  39.501 +
  39.502 +    // call the _m variant just for coverage
  39.503 +    cxmutstr m1 = cx_strtrim_m(cx_mutstr((char *) "  ein test  \t "));
  39.504 +    EXPECT_EQ(cx_strcmp(cx_strcast(m1), cx_str("ein test")), 0);
  39.505 +}
  39.506 +
  39.507 +TEST(String, strprefix) {
  39.508 +    cxstring str = CX_STR("test my prefix and my suffix");
  39.509 +    cxstring empty = CX_STR("");
  39.510 +    EXPECT_FALSE(cx_strprefix(empty, cx_str("pref")));
  39.511 +    EXPECT_TRUE(cx_strprefix(str, empty));
  39.512 +    EXPECT_TRUE(cx_strprefix(empty, empty));
  39.513 +    EXPECT_TRUE(cx_strprefix(str, cx_str("test ")));
  39.514 +    EXPECT_FALSE(cx_strprefix(str, cx_str("8-) fsck ")));
  39.515 +}
  39.516 +
  39.517 +TEST(String, strsuffix) {
  39.518 +    cxstring str = CX_STR("test my prefix and my suffix");
  39.519 +    cxstring empty = CX_STR("");
  39.520 +    EXPECT_FALSE(cx_strsuffix(empty, cx_str("suf")));
  39.521 +    EXPECT_TRUE(cx_strsuffix(str, empty));
  39.522 +    EXPECT_TRUE(cx_strsuffix(empty, empty));
  39.523 +    EXPECT_TRUE(cx_strsuffix(str, cx_str("fix")));
  39.524 +    EXPECT_FALSE(cx_strsuffix(str, cx_str("fox")));
  39.525 +}
  39.526 +
  39.527 +TEST(String, strcaseprefix) {
  39.528 +    cxstring str = CX_STR("test my prefix and my suffix");
  39.529 +    cxstring empty = CX_STR("");
  39.530 +    EXPECT_FALSE(cx_strcaseprefix(empty, cx_str("pREf")));
  39.531 +    EXPECT_TRUE(cx_strcaseprefix(str, empty));
  39.532 +    EXPECT_TRUE(cx_strcaseprefix(empty, empty));
  39.533 +    EXPECT_TRUE(cx_strcaseprefix(str, cx_str("TEST ")));
  39.534 +    EXPECT_FALSE(cx_strcaseprefix(str, cx_str("8-) fsck ")));
  39.535 +}
  39.536 +
  39.537 +TEST(String, strcasesuffix) {
  39.538 +    cxstring str = CX_STR("test my prefix and my suffix");
  39.539 +    cxstring empty = CX_STR("");
  39.540 +    EXPECT_FALSE(cx_strcasesuffix(empty, cx_str("sUf")));
  39.541 +    EXPECT_TRUE(cx_strcasesuffix(str, empty));
  39.542 +    EXPECT_TRUE(cx_strcasesuffix(empty, empty));
  39.543 +    EXPECT_TRUE(cx_strcasesuffix(str, cx_str("FIX")));
  39.544 +    EXPECT_FALSE(cx_strcasesuffix(str, cx_str("fox")));
  39.545 +}
  39.546 +
  39.547 +TEST(String, strreplace) {
  39.548 +    CxTestingAllocator alloc;
  39.549 +    cxstring str = CX_STR("test ababab string aba");
  39.550 +    cxstring longstr = CX_STR(
  39.551 +            "xyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacd");
  39.552 +    cxstring notrail = CX_STR("test abab");
  39.553 +    cxstring empty = CX_STR("");
  39.554 +    cxstring astr = CX_STR("aaaaaaaaaa");
  39.555 +    cxstring csstr = CX_STR("test AB ab TEST xyz");
  39.556 +
  39.557 +    cxmutstr repl = cx_strreplace(str, cx_str("abab"), cx_str("muchlonger"));
  39.558 +    auto expected = "test muchlongerab string aba";
  39.559 +
  39.560 +    cxmutstr repln = cx_strreplacen(str, cx_str("ab"), cx_str("c"), 2);
  39.561 +    auto expectedn = "test ccab string aba";
  39.562 +
  39.563 +    cxmutstr longrepl = cx_strreplace(longstr, cx_str("a"), cx_str("z"));
  39.564 +    auto longexpect = "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd";
  39.565 +
  39.566 +    cxmutstr replnotrail = cx_strreplace(notrail, cx_str("ab"), cx_str("z"));
  39.567 +    auto notrailexpect = "test zz";
  39.568 +
  39.569 +    cxmutstr repleq = cx_strreplace(str, str, cx_str("hello"));
  39.570 +    auto eqexpect = "hello";
  39.571 +
  39.572 +    cxmutstr replempty1 = cx_strreplace(empty, cx_str("ab"), cx_str("c")); // expect: empty
  39.573 +    cxmutstr replempty2 = cx_strreplace(str, cx_str("abab"), empty);
  39.574 +    auto emptyexpect2 = "test ab string aba";
  39.575 +
  39.576 +    cxmutstr replpre = cx_strreplace(str, cx_str("test "), cx_str("TEST "));
  39.577 +    auto preexpected = "TEST ababab string aba";
  39.578 +
  39.579 +    cxmutstr replan1 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 1);
  39.580 +    auto an1expected = "xaaaaaaaaa";
  39.581 +
  39.582 +    cxmutstr replan4 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 4);
  39.583 +    auto an4expected = "xxxxaaaaaa";
  39.584 +
  39.585 +    cxmutstr replan9 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 9);
  39.586 +    auto an9expected = "xxxxxxxxxa";
  39.587 +
  39.588 +    cxmutstr replan10 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 10);
  39.589 +    auto an10expected = "xxxxxxxxxx";
  39.590 +
  39.591 +    cxmutstr repl1_a = cx_strreplace_a(&alloc, csstr, cx_str("AB"), cx_str("*"));
  39.592 +    auto expeced1_a = "test * ab TEST xyz";
  39.593 +
  39.594 +    cxmutstr repl2_a = cx_strreplace_a(&alloc, csstr, cx_str("test"), cx_str("TEST"));
  39.595 +    auto expected2_a = "TEST AB ab TEST xyz";
  39.596 +
  39.597 +
  39.598 +    EXPECT_NE(repl.ptr, str.ptr);
  39.599 +    EXPECT_ZERO_TERMINATED(repl);
  39.600 +    EXPECT_STREQ(repl.ptr, expected);
  39.601 +    EXPECT_ZERO_TERMINATED(repln);
  39.602 +    EXPECT_STREQ(repln.ptr, expectedn);
  39.603 +    EXPECT_ZERO_TERMINATED(longrepl);
  39.604 +    EXPECT_STREQ(longrepl.ptr, longexpect);
  39.605 +    EXPECT_ZERO_TERMINATED(replnotrail);
  39.606 +    EXPECT_STREQ(replnotrail.ptr, notrailexpect);
  39.607 +    EXPECT_ZERO_TERMINATED(repleq);
  39.608 +    EXPECT_STREQ(repleq.ptr, eqexpect);
  39.609 +    EXPECT_ZERO_TERMINATED(replempty1);
  39.610 +    EXPECT_STREQ(replempty1.ptr, "");
  39.611 +    EXPECT_ZERO_TERMINATED(replempty2);
  39.612 +    EXPECT_STREQ(replempty2.ptr, emptyexpect2);
  39.613 +    EXPECT_ZERO_TERMINATED(replpre);
  39.614 +    EXPECT_STREQ(replpre.ptr, preexpected);
  39.615 +    EXPECT_ZERO_TERMINATED(replan1);
  39.616 +    EXPECT_STREQ(replan1.ptr, an1expected);
  39.617 +    EXPECT_ZERO_TERMINATED(replan4);
  39.618 +    EXPECT_STREQ(replan4.ptr, an4expected);
  39.619 +    EXPECT_ZERO_TERMINATED(replan9);
  39.620 +    EXPECT_STREQ(replan9.ptr, an9expected);
  39.621 +    EXPECT_ZERO_TERMINATED(replan10);
  39.622 +    EXPECT_STREQ(replan10.ptr, an10expected);
  39.623 +    EXPECT_ZERO_TERMINATED(repl1_a);
  39.624 +    EXPECT_STREQ(repl1_a.ptr, expeced1_a);
  39.625 +    EXPECT_ZERO_TERMINATED(repl2_a);
  39.626 +    EXPECT_STREQ(repl2_a.ptr, expected2_a);
  39.627 +
  39.628 +    cx_strfree(&repl);
  39.629 +    cx_strfree(&repln);
  39.630 +    cx_strfree(&longrepl);
  39.631 +    cx_strfree(&replnotrail);
  39.632 +    cx_strfree(&repleq);
  39.633 +    cx_strfree(&replempty1);
  39.634 +    cx_strfree(&replempty2);
  39.635 +    cx_strfree(&replpre);
  39.636 +    cx_strfree(&replan1);
  39.637 +    cx_strfree(&replan4);
  39.638 +    cx_strfree(&replan9);
  39.639 +    cx_strfree(&replan10);
  39.640 +
  39.641 +    cx_strfree_a(&alloc, &repl1_a);
  39.642 +    cx_strfree_a(&alloc, &repl2_a);
  39.643 +    EXPECT_TRUE(alloc.verify());
  39.644 +}
  39.645 +
  39.646 +TEST(String, strupper) {
  39.647 +    cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
  39.648 +    cx_strupper(str);
  39.649 +    EXPECT_STREQ(str.ptr, "THIS 1S @ TE$T");
  39.650 +    cx_strfree(&str);
  39.651 +}
  39.652 +
  39.653 +TEST(String, strlower) {
  39.654 +    cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
  39.655 +    cx_strlower(str);
  39.656 +    EXPECT_STREQ(str.ptr, "this 1s @ te$t");
  39.657 +    cx_strfree(&str);
  39.658 +}
  39.659 +
  39.660 +TEST(String, strtok) {
  39.661 +    cxstring str = cx_str("a,comma,separated,string");
  39.662 +    cxstring delim = cx_str(",");
  39.663 +    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  39.664 +    EXPECT_EQ(ctx.str.ptr, str.ptr);
  39.665 +    EXPECT_EQ(ctx.str.length, str.length);
  39.666 +    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  39.667 +    EXPECT_EQ(ctx.delim.length, delim.length);
  39.668 +    EXPECT_EQ(ctx.limit, 3);
  39.669 +    EXPECT_EQ(ctx.found, 0);
  39.670 +    EXPECT_EQ(ctx.pos, 0);
  39.671 +    EXPECT_EQ(ctx.next_pos, 0);
  39.672 +    EXPECT_EQ(ctx.delim_more, nullptr);
  39.673 +    EXPECT_EQ(ctx.delim_more_count, 0);
  39.674 +}
  39.675 +
  39.676 +TEST(String, strtok_m) {
  39.677 +    cxmutstr str = cx_strdup(cx_str("a,comma,separated,string"));
  39.678 +    cxstring delim = cx_str(",");
  39.679 +    CxStrtokCtx ctx = cx_strtok_m(str, delim, 3);
  39.680 +    EXPECT_EQ(ctx.str.ptr, str.ptr);
  39.681 +    EXPECT_EQ(ctx.str.length, str.length);
  39.682 +    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  39.683 +    EXPECT_EQ(ctx.delim.length, delim.length);
  39.684 +    EXPECT_EQ(ctx.limit, 3);
  39.685 +    EXPECT_EQ(ctx.found, 0);
  39.686 +    EXPECT_EQ(ctx.pos, 0);
  39.687 +    EXPECT_EQ(ctx.next_pos, 0);
  39.688 +    EXPECT_EQ(ctx.delim_more, nullptr);
  39.689 +    EXPECT_EQ(ctx.delim_more_count, 0);
  39.690 +    cx_strfree(&str);
  39.691 +}
  39.692 +
  39.693 +TEST(String, strtok_delim) {
  39.694 +    cxstring str = cx_str("an,arbitrarily|separated;string");
  39.695 +    cxstring delim = cx_str(",");
  39.696 +    cxstring delim_more[2] = {CX_STR("|"), CX_STR(";")};
  39.697 +    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  39.698 +    cx_strtok_delim(&ctx, delim_more, 2);
  39.699 +    EXPECT_EQ(ctx.str.ptr, str.ptr);
  39.700 +    EXPECT_EQ(ctx.str.length, str.length);
  39.701 +    EXPECT_EQ(ctx.delim.ptr, delim.ptr);
  39.702 +    EXPECT_EQ(ctx.delim.length, delim.length);
  39.703 +    EXPECT_EQ(ctx.limit, 3);
  39.704 +    EXPECT_EQ(ctx.found, 0);
  39.705 +    EXPECT_EQ(ctx.pos, 0);
  39.706 +    EXPECT_EQ(ctx.next_pos, 0);
  39.707 +    EXPECT_EQ(ctx.delim_more, delim_more);
  39.708 +    EXPECT_EQ(ctx.delim_more_count, 2);
  39.709 +}
  39.710 +
  39.711 +TEST(String, strtok_next_easy) {
  39.712 +    cxstring str = cx_str("a,comma,separated,string");
  39.713 +    cxstring delim = cx_str(",");
  39.714 +    CxStrtokCtx ctx = cx_strtok(str, delim, 3);
  39.715 +    bool ret;
  39.716 +    cxstring tok;
  39.717 +
  39.718 +    ret = cx_strtok_next(&ctx, &tok);
  39.719 +    ASSERT_TRUE(ret);
  39.720 +    EXPECT_EQ(cx_strcmp(tok, cx_str("a")), 0);
  39.721 +    EXPECT_EQ(ctx.pos, 0);
  39.722 +    EXPECT_EQ(ctx.next_pos, 2);
  39.723 +    EXPECT_EQ(ctx.delim_pos, 1);
  39.724 +    EXPECT_EQ(ctx.found, 1);
  39.725 +
  39.726 +    ret = cx_strtok_next(&ctx, &tok);
  39.727 +    ASSERT_TRUE(ret);
  39.728 +    EXPECT_EQ(cx_strcmp(tok, cx_str("comma")), 0);
  39.729 +    EXPECT_EQ(ctx.pos, 2);
  39.730 +    EXPECT_EQ(ctx.next_pos, 8);
  39.731 +    EXPECT_EQ(ctx.delim_pos, 7);
  39.732 +    EXPECT_EQ(ctx.found, 2);
  39.733 +
  39.734 +    ret = cx_strtok_next(&ctx, &tok);
  39.735 +    ASSERT_TRUE(ret);
  39.736 +    EXPECT_EQ(cx_strcmp(tok, cx_str("separated")), 0);
  39.737 +    EXPECT_EQ(ctx.pos, 8);
  39.738 +    EXPECT_EQ(ctx.next_pos, 18);
  39.739 +    EXPECT_EQ(ctx.delim_pos, 17);
  39.740 +    EXPECT_EQ(ctx.found, 3);
  39.741 +
  39.742 +    ret = cx_strtok_next(&ctx, &tok);
  39.743 +    ASSERT_FALSE(ret);
  39.744 +    EXPECT_EQ(ctx.pos, 8);
  39.745 +    EXPECT_EQ(ctx.next_pos, 18);
  39.746 +    EXPECT_EQ(ctx.delim_pos, 17);
  39.747 +    EXPECT_EQ(ctx.found, 3);
  39.748 +}
  39.749 +
  39.750 +TEST(String, strtok_next_unlimited) {
  39.751 +    cxstring str = cx_str("some;-;otherwise;-;separated;-;string;-;");
  39.752 +    cxstring delim = cx_str(";-;");
  39.753 +    CxStrtokCtx ctx = cx_strtok(str, delim, SIZE_MAX);
  39.754 +    bool ret;
  39.755 +    cxstring tok;
  39.756 +
  39.757 +    ret = cx_strtok_next(&ctx, &tok);
  39.758 +    ASSERT_TRUE(ret);
  39.759 +    EXPECT_EQ(cx_strcmp(tok, cx_str("some")), 0);
  39.760 +    EXPECT_EQ(ctx.pos, 0);
  39.761 +    EXPECT_EQ(ctx.next_pos, 7);
  39.762 +    EXPECT_EQ(ctx.delim_pos, 4);
  39.763 +    EXPECT_EQ(ctx.found, 1);
  39.764 +
  39.765 +    ret = cx_strtok_next(&ctx, &tok);
  39.766 +    ASSERT_TRUE(ret);
  39.767 +    EXPECT_EQ(cx_strcmp(tok, cx_str("otherwise")), 0);
  39.768 +    EXPECT_EQ(ctx.pos, 7);
  39.769 +    EXPECT_EQ(ctx.next_pos, 19);
  39.770 +    EXPECT_EQ(ctx.delim_pos, 16);
  39.771 +    EXPECT_EQ(ctx.found, 2);
  39.772 +
  39.773 +    ret = cx_strtok_next(&ctx, &tok);
  39.774 +    ASSERT_TRUE(ret);
  39.775 +    EXPECT_EQ(cx_strcmp(tok, cx_str("separated")), 0);
  39.776 +    EXPECT_EQ(ctx.pos, 19);
  39.777 +    EXPECT_EQ(ctx.next_pos, 31);
  39.778 +    EXPECT_EQ(ctx.delim_pos, 28);
  39.779 +    EXPECT_EQ(ctx.found, 3);
  39.780 +
  39.781 +    ret = cx_strtok_next(&ctx, &tok);
  39.782 +    ASSERT_TRUE(ret);
  39.783 +    EXPECT_EQ(cx_strcmp(tok, cx_str("string")), 0);
  39.784 +    EXPECT_EQ(ctx.pos, 31);
  39.785 +    EXPECT_EQ(ctx.next_pos, 40);
  39.786 +    EXPECT_EQ(ctx.delim_pos, 37);
  39.787 +    EXPECT_EQ(ctx.found, 4);
  39.788 +
  39.789 +    ret = cx_strtok_next(&ctx, &tok);
  39.790 +    ASSERT_TRUE(ret);
  39.791 +    EXPECT_EQ(cx_strcmp(tok, cx_str("")), 0);
  39.792 +    EXPECT_EQ(ctx.pos, 40);
  39.793 +    EXPECT_EQ(ctx.next_pos, 40);
  39.794 +    EXPECT_EQ(ctx.delim_pos, 40);
  39.795 +    EXPECT_EQ(ctx.found, 5);
  39.796 +
  39.797 +    ret = cx_strtok_next(&ctx, &tok);
  39.798 +    ASSERT_FALSE(ret);
  39.799 +    EXPECT_EQ(ctx.pos, 40);
  39.800 +    EXPECT_EQ(ctx.delim_pos, 40);
  39.801 +    EXPECT_EQ(ctx.found, 5);
  39.802 +}
  39.803 +
  39.804 +TEST(String, strtok_next_advanced) {
  39.805 +    cxmutstr str = cx_strdup(cx_str("an,arbitrarily;||separated;string"));
  39.806 +    cxstring delim = cx_str(",");
  39.807 +    cxstring delim_more[2] = {CX_STR("||"), CX_STR(";")};
  39.808 +    CxStrtokCtx ctx = cx_strtok_m(str, delim, 10);
  39.809 +    cx_strtok_delim(&ctx, delim_more, 2);
  39.810 +    bool ret;
  39.811 +    cxmutstr tok;
  39.812 +
  39.813 +    ret = cx_strtok_next_m(&ctx, &tok);
  39.814 +    ASSERT_TRUE(ret);
  39.815 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("an")), 0);
  39.816 +    EXPECT_EQ(ctx.pos, 0);
  39.817 +    EXPECT_EQ(ctx.next_pos, 3);
  39.818 +    EXPECT_EQ(ctx.delim_pos, 2);
  39.819 +    EXPECT_EQ(ctx.found, 1);
  39.820 +    cx_strupper(tok);
  39.821 +
  39.822 +    ret = cx_strtok_next_m(&ctx, &tok);
  39.823 +    ASSERT_TRUE(ret);
  39.824 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("arbitrarily")), 0);
  39.825 +    EXPECT_EQ(ctx.pos, 3);
  39.826 +    EXPECT_EQ(ctx.next_pos, 15);
  39.827 +    EXPECT_EQ(ctx.delim_pos, 14);
  39.828 +    EXPECT_EQ(ctx.found, 2);
  39.829 +    cx_strupper(tok);
  39.830 +
  39.831 +    ret = cx_strtok_next_m(&ctx, &tok);
  39.832 +    ASSERT_TRUE(ret);
  39.833 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("")), 0);
  39.834 +    EXPECT_EQ(ctx.pos, 15);
  39.835 +    EXPECT_EQ(ctx.next_pos, 17);
  39.836 +    EXPECT_EQ(ctx.delim_pos, 15);
  39.837 +    EXPECT_EQ(ctx.found, 3);
  39.838 +    cx_strupper(tok);
  39.839 +
  39.840 +    ret = cx_strtok_next_m(&ctx, &tok);
  39.841 +    ASSERT_TRUE(ret);
  39.842 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("separated")), 0);
  39.843 +    EXPECT_EQ(ctx.pos, 17);
  39.844 +    EXPECT_EQ(ctx.next_pos, 27);
  39.845 +    EXPECT_EQ(ctx.delim_pos, 26);
  39.846 +    EXPECT_EQ(ctx.found, 4);
  39.847 +    cx_strupper(tok);
  39.848 +
  39.849 +    ret = cx_strtok_next_m(&ctx, &tok);
  39.850 +    ASSERT_TRUE(ret);
  39.851 +    EXPECT_EQ(cx_strcmp(cx_strcast(tok), cx_str("string")), 0);
  39.852 +    EXPECT_EQ(ctx.pos, 27);
  39.853 +    EXPECT_EQ(ctx.next_pos, 33);
  39.854 +    EXPECT_EQ(ctx.delim_pos, 33);
  39.855 +    EXPECT_EQ(ctx.found, 5);
  39.856 +    cx_strupper(tok);
  39.857 +
  39.858 +    ret = cx_strtok_next_m(&ctx, &tok);
  39.859 +    ASSERT_FALSE(ret);
  39.860 +    EXPECT_EQ(ctx.pos, 27);
  39.861 +    EXPECT_EQ(ctx.next_pos, 33);
  39.862 +    EXPECT_EQ(ctx.delim_pos, 33);
  39.863 +    EXPECT_EQ(ctx.found, 5);
  39.864 +
  39.865 +    EXPECT_EQ(cx_strcmp(cx_strcast(str), cx_str("AN,ARBITRARILY;||SEPARATED;STRING")), 0);
  39.866 +
  39.867 +    cx_strfree(&str);
  39.868 +}
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/tests/test_tree.cpp	Wed Feb 08 20:26:26 2023 +0100
    40.3 @@ -0,0 +1,122 @@
    40.4 +/*
    40.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    40.6 + *
    40.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    40.8 + *
    40.9 + * Redistribution and use in source and binary forms, with or without
   40.10 + * modification, are permitted provided that the following conditions are met:
   40.11 + *
   40.12 + *   1. Redistributions of source code must retain the above copyright
   40.13 + *      notice, this list of conditions and the following disclaimer.
   40.14 + *
   40.15 + *   2. Redistributions in binary form must reproduce the above copyright
   40.16 + *      notice, this list of conditions and the following disclaimer in the
   40.17 + *      documentation and/or other materials provided with the distribution.
   40.18 + *
   40.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   40.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   40.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   40.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   40.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   40.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   40.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   40.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   40.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   40.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   40.29 + * POSSIBILITY OF SUCH DAMAGE.
   40.30 + */
   40.31 +
   40.32 +#include "cx/tree.h"
   40.33 +#include <gtest/gtest.h>
   40.34 +
   40.35 +struct TestNode {
   40.36 +    TestNode *parent = nullptr;
   40.37 +    TestNode *prev = nullptr;
   40.38 +    TestNode *next = nullptr;
   40.39 +
   40.40 +    TestNode *children_begin = nullptr;
   40.41 +    TestNode *children_end = nullptr;
   40.42 +};
   40.43 +
   40.44 +TEST(Tree, cx_tree_add_sibling) {
   40.45 +    // prepare test tree
   40.46 +    TestNode root, a;
   40.47 +    root.children_begin = &a;
   40.48 +    root.children_end = &a;
   40.49 +    a.parent = &root;
   40.50 +
   40.51 +    // new test nodes
   40.52 +    TestNode b, c;
   40.53 +
   40.54 +    // test
   40.55 +    cx_tree_add_sibling(&a, offsetof(TestNode, prev), offsetof(TestNode, next), offsetof(TestNode, parent), &b);
   40.56 +    EXPECT_EQ(b.parent, &root);
   40.57 +    EXPECT_EQ(b.prev, &a);
   40.58 +    EXPECT_EQ(b.next, nullptr);
   40.59 +    EXPECT_EQ(a.next, &b);
   40.60 +
   40.61 +    cx_tree_add_sibling(&a, -1, offsetof(TestNode, next), -1, &c);
   40.62 +    EXPECT_EQ(c.parent, nullptr);
   40.63 +    EXPECT_EQ(c.prev, nullptr);
   40.64 +    EXPECT_EQ(c.next, nullptr);
   40.65 +    EXPECT_EQ(b.next, &c);
   40.66 +}
   40.67 +
   40.68 +TEST(Tree, cx_tree_add_child) {
   40.69 +    TestNode root, a, b, c, a1;
   40.70 +
   40.71 +    cx_tree_add_child(
   40.72 +            (void **) &root.children_begin,
   40.73 +            (void **) &root.children_end,
   40.74 +            offsetof(TestNode, prev),
   40.75 +            offsetof(TestNode, next),
   40.76 +            &a,
   40.77 +            offsetof(TestNode, parent),
   40.78 +            &root);
   40.79 +    EXPECT_EQ(root.children_begin, &a);
   40.80 +    EXPECT_EQ(root.children_end, &a);
   40.81 +    EXPECT_EQ(a.parent, &root);
   40.82 +    EXPECT_EQ(a.prev, nullptr);
   40.83 +    EXPECT_EQ(a.next, nullptr);
   40.84 +
   40.85 +    cx_tree_add_child(
   40.86 +            (void **) &root.children_begin,
   40.87 +            (void **) &root.children_end,
   40.88 +            offsetof(TestNode, prev),
   40.89 +            offsetof(TestNode, next),
   40.90 +            &b,
   40.91 +            offsetof(TestNode, parent),
   40.92 +            &root);
   40.93 +    EXPECT_EQ(root.children_begin, &a);
   40.94 +    EXPECT_EQ(root.children_begin->next, &b);
   40.95 +    EXPECT_EQ(root.children_end, &b);
   40.96 +    EXPECT_EQ(b.parent, &root);
   40.97 +    EXPECT_EQ(b.prev, &a);
   40.98 +
   40.99 +    cx_tree_add_child(
  40.100 +            (void **) &root.children_begin,
  40.101 +            nullptr,
  40.102 +            -1,
  40.103 +            offsetof(TestNode, next),
  40.104 +            &c,
  40.105 +            -1,
  40.106 +            &root);
  40.107 +    EXPECT_EQ(root.children_end, &b); // children_end unchanged
  40.108 +    EXPECT_EQ(b.next, &c);
  40.109 +    EXPECT_EQ(c.prev, nullptr);
  40.110 +    EXPECT_EQ(c.next, nullptr);
  40.111 +    EXPECT_EQ(c.parent, nullptr);
  40.112 +
  40.113 +    cx_tree_add_child(
  40.114 +            (void **) &a.children_begin,
  40.115 +            (void **) &a.children_end,
  40.116 +            offsetof(TestNode, prev),
  40.117 +            offsetof(TestNode, next),
  40.118 +            &a1,
  40.119 +            offsetof(TestNode, parent),
  40.120 +            &a);
  40.121 +    EXPECT_EQ(a.children_begin, &a1);
  40.122 +    EXPECT_EQ(a1.parent, &a);
  40.123 +    EXPECT_EQ(root.children_begin, &a);
  40.124 +    EXPECT_EQ(root.children_begin->children_begin, &a1);
  40.125 +}
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/tests/test_utils.cpp	Wed Feb 08 20:26:26 2023 +0100
    41.3 @@ -0,0 +1,165 @@
    41.4 +/*
    41.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    41.6 + *
    41.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    41.8 + *
    41.9 + * Redistribution and use in source and binary forms, with or without
   41.10 + * modification, are permitted provided that the following conditions are met:
   41.11 + *
   41.12 + *   1. Redistributions of source code must retain the above copyright
   41.13 + *      notice, this list of conditions and the following disclaimer.
   41.14 + *
   41.15 + *   2. Redistributions in binary form must reproduce the above copyright
   41.16 + *      notice, this list of conditions and the following disclaimer in the
   41.17 + *      documentation and/or other materials provided with the distribution.
   41.18 + *
   41.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   41.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   41.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   41.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   41.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   41.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   41.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   41.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   41.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   41.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   41.29 + * POSSIBILITY OF SUCH DAMAGE.
   41.30 + */
   41.31 +
   41.32 +#include "cx/utils.h"
   41.33 +
   41.34 +#include <gtest/gtest.h>
   41.35 +
   41.36 +TEST(Utils, ForN) {
   41.37 +    unsigned j;
   41.38 +    j = 0;
   41.39 +    cx_for_n(i, 50) {
   41.40 +        EXPECT_EQ(i, j);
   41.41 +        j++;
   41.42 +    }
   41.43 +}
   41.44 +
   41.45 +TEST(Utils, swap_ptr) {
   41.46 +    int i = 5;
   41.47 +    int j = 8;
   41.48 +    int *ip = &i;
   41.49 +    int *jp = &j;
   41.50 +    cx_swap_ptr(ip, jp);
   41.51 +    EXPECT_EQ(ip, &j);
   41.52 +    EXPECT_EQ(jp, &i);
   41.53 +}
   41.54 +
   41.55 +TEST(Utils, szmul) {
   41.56 +    size_t r;
   41.57 +    int e;
   41.58 +    e = cx_szmul(5, 7, &r);
   41.59 +    EXPECT_EQ(0, e);
   41.60 +    EXPECT_EQ(35, r);
   41.61 +
   41.62 +    size_t s = SIZE_MAX & ~3;
   41.63 +
   41.64 +    e = cx_szmul(s / 4, 2, &r);
   41.65 +    EXPECT_EQ(0, e);
   41.66 +    EXPECT_EQ(s / 2, r);
   41.67 +    e = cx_szmul(2, s / 4, &r);
   41.68 +    EXPECT_EQ(0, e);
   41.69 +    EXPECT_EQ(s / 2, r);
   41.70 +
   41.71 +    e = cx_szmul(s / 4, 4, &r);
   41.72 +    EXPECT_EQ(0, e);
   41.73 +    EXPECT_EQ(s, r);
   41.74 +
   41.75 +    e = cx_szmul(4, s / 4, &r);
   41.76 +    EXPECT_EQ(0, e);
   41.77 +    EXPECT_EQ(s, r);
   41.78 +
   41.79 +    e = cx_szmul(s / 4, 5, &r);
   41.80 +    EXPECT_NE(0, e);
   41.81 +
   41.82 +    e = cx_szmul(5, s / 4, &r);
   41.83 +    EXPECT_NE(0, e);
   41.84 +
   41.85 +    e = cx_szmul(SIZE_MAX - 4, 0, &r);
   41.86 +    EXPECT_EQ(0, e);
   41.87 +    EXPECT_EQ(0, r);
   41.88 +
   41.89 +    e = cx_szmul(0, SIZE_MAX - 1, &r);
   41.90 +    EXPECT_EQ(0, e);
   41.91 +    EXPECT_EQ(0, r);
   41.92 +
   41.93 +    e = cx_szmul(SIZE_MAX, 0, &r);
   41.94 +    EXPECT_EQ(0, e);
   41.95 +    EXPECT_EQ(0, r);
   41.96 +
   41.97 +    e = cx_szmul(0, SIZE_MAX, &r);
   41.98 +    EXPECT_EQ(0, e);
   41.99 +    EXPECT_EQ(0, r);
  41.100 +
  41.101 +    e = cx_szmul(0, 0, &r);
  41.102 +    EXPECT_EQ(0, e);
  41.103 +    EXPECT_EQ(0, r);
  41.104 +}
  41.105 +
  41.106 +#ifdef CX_SZMUL_BUILTIN
  41.107 +
  41.108 +// also test the custom implementation
  41.109 +struct Utils_szmul_impl : ::testing::Test {
  41.110 +#undef CX_SZMUL_BUILTIN
  41.111 +
  41.112 +#include "../src/utils.c"
  41.113 +
  41.114 +#define CX_SZMUL_BUILTIN
  41.115 +};
  41.116 +
  41.117 +TEST_F(Utils_szmul_impl, Test) {
  41.118 +    size_t r;
  41.119 +    int e;
  41.120 +    e = cx_szmul_impl(5, 7, &r);
  41.121 +    EXPECT_EQ(0, e);
  41.122 +    EXPECT_EQ(35, r);
  41.123 +
  41.124 +    size_t s = SIZE_MAX & ~3;
  41.125 +
  41.126 +    e = cx_szmul_impl(s / 4, 2, &r);
  41.127 +    EXPECT_EQ(0, e);
  41.128 +    EXPECT_EQ(s / 2, r);
  41.129 +    e = cx_szmul_impl(2, s / 4, &r);
  41.130 +    EXPECT_EQ(0, e);
  41.131 +    EXPECT_EQ(s / 2, r);
  41.132 +
  41.133 +    e = cx_szmul_impl(s / 4, 4, &r);
  41.134 +    EXPECT_EQ(0, e);
  41.135 +    EXPECT_EQ(s, r);
  41.136 +
  41.137 +    e = cx_szmul_impl(4, s / 4, &r);
  41.138 +    EXPECT_EQ(0, e);
  41.139 +    EXPECT_EQ(s, r);
  41.140 +
  41.141 +    e = cx_szmul_impl(s / 4, 5, &r);
  41.142 +    EXPECT_NE(0, e);
  41.143 +
  41.144 +    e = cx_szmul_impl(5, s / 4, &r);
  41.145 +    EXPECT_NE(0, e);
  41.146 +
  41.147 +    e = cx_szmul_impl(SIZE_MAX - 4, 0, &r);
  41.148 +    EXPECT_EQ(0, e);
  41.149 +    EXPECT_EQ(0, r);
  41.150 +
  41.151 +    e = cx_szmul_impl(0, SIZE_MAX - 1, &r);
  41.152 +    EXPECT_EQ(0, e);
  41.153 +    EXPECT_EQ(0, r);
  41.154 +
  41.155 +    e = cx_szmul_impl(SIZE_MAX, 0, &r);
  41.156 +    EXPECT_EQ(0, e);
  41.157 +    EXPECT_EQ(0, r);
  41.158 +
  41.159 +    e = cx_szmul_impl(0, SIZE_MAX, &r);
  41.160 +    EXPECT_EQ(0, e);
  41.161 +    EXPECT_EQ(0, r);
  41.162 +
  41.163 +    e = cx_szmul_impl(0, 0, &r);
  41.164 +    EXPECT_EQ(0, e);
  41.165 +    EXPECT_EQ(0, r);
  41.166 +}
  41.167 +
  41.168 +#endif // CX_SZMUL_BUILTIN
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/tests/util_allocator.cpp	Wed Feb 08 20:26:26 2023 +0100
    42.3 @@ -0,0 +1,167 @@
    42.4 +/*
    42.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    42.6 + *
    42.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    42.8 + *
    42.9 + * Redistribution and use in source and binary forms, with or without
   42.10 + * modification, are permitted provided that the following conditions are met:
   42.11 + *
   42.12 + *   1. Redistributions of source code must retain the above copyright
   42.13 + *      notice, this list of conditions and the following disclaimer.
   42.14 + *
   42.15 + *   2. Redistributions in binary form must reproduce the above copyright
   42.16 + *      notice, this list of conditions and the following disclaimer in the
   42.17 + *      documentation and/or other materials provided with the distribution.
   42.18 + *
   42.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   42.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   42.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   42.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   42.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   42.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   42.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   42.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   42.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   42.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   42.29 + * POSSIBILITY OF SUCH DAMAGE.
   42.30 + */
   42.31 +
   42.32 +#include "util_allocator.h"
   42.33 +
   42.34 +void *cx_malloc_testing(void *d, size_t n) {
   42.35 +    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   42.36 +    void *ptr = malloc(n);
   42.37 +    data->alloc_total++;
   42.38 +    if (ptr == nullptr) {
   42.39 +        data->alloc_failed++;
   42.40 +    } else {
   42.41 +        data->tracked.insert(ptr);
   42.42 +    }
   42.43 +    return ptr;
   42.44 +}
   42.45 +
   42.46 +void *cx_realloc_testing(void *d, void *mem, size_t n) {
   42.47 +    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   42.48 +    void *ptr = realloc(mem, n);
   42.49 +    if (ptr == mem) {
   42.50 +        return ptr;
   42.51 +    } else {
   42.52 +        data->alloc_total++;
   42.53 +        if (ptr == nullptr) {
   42.54 +            data->alloc_failed++;
   42.55 +        } else {
   42.56 +            data->free_total++;
   42.57 +            if (data->tracked.erase(mem) == 0) {
   42.58 +                data->free_failed++;
   42.59 +            }
   42.60 +            data->tracked.insert(ptr);
   42.61 +        }
   42.62 +        return ptr;
   42.63 +    }
   42.64 +}
   42.65 +
   42.66 +void *cx_calloc_testing(void *d, size_t nelem, size_t n) {
   42.67 +    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   42.68 +    void *ptr = calloc(nelem, n);
   42.69 +    data->alloc_total++;
   42.70 +    if (ptr == nullptr) {
   42.71 +        data->alloc_failed++;
   42.72 +    } else {
   42.73 +        data->tracked.insert(ptr);
   42.74 +    }
   42.75 +    return ptr;
   42.76 +}
   42.77 +
   42.78 +void cx_free_testing(void *d, void *mem) {
   42.79 +    auto data = reinterpret_cast<CxTestingAllocator *>(d);
   42.80 +    data->free_total++;
   42.81 +    if (data->tracked.erase(mem) == 0) {
   42.82 +        data->free_failed++;
   42.83 +        // do not even attempt to free mem, because it is likely to segfault
   42.84 +    } else {
   42.85 +        free(mem);
   42.86 +    }
   42.87 +}
   42.88 +
   42.89 +cx_allocator_class cx_testing_allocator_class = {
   42.90 +        cx_malloc_testing,
   42.91 +        cx_realloc_testing,
   42.92 +        cx_calloc_testing,
   42.93 +        cx_free_testing
   42.94 +};
   42.95 +
   42.96 +CxTestingAllocator::CxTestingAllocator() : CxAllocator() {
   42.97 +    cl = &cx_testing_allocator_class;
   42.98 +    data = this;
   42.99 +}
  42.100 +
  42.101 +bool CxTestingAllocator::used() const {
  42.102 +    return alloc_total > 0;
  42.103 +}
  42.104 +
  42.105 +bool CxTestingAllocator::verify() const {
  42.106 +    return tracked.empty() && alloc_failed == 0 && free_failed == 0 && alloc_total == free_total;
  42.107 +}
  42.108 +
  42.109 +// SELF-TEST
  42.110 +
  42.111 +#include <gtest/gtest.h>
  42.112 +
  42.113 +TEST(TestingAllocator, ExpectFree) {
  42.114 +    CxTestingAllocator allocator;
  42.115 +
  42.116 +    ASSERT_TRUE(allocator.verify());
  42.117 +    EXPECT_FALSE(allocator.used());
  42.118 +    auto ptr = cxMalloc(&allocator, 16);
  42.119 +    EXPECT_TRUE(allocator.used());
  42.120 +    ASSERT_NE(ptr, nullptr);
  42.121 +    EXPECT_FALSE(allocator.verify());
  42.122 +
  42.123 +    cxFree(&allocator, ptr);
  42.124 +    EXPECT_TRUE(allocator.verify());
  42.125 +}
  42.126 +
  42.127 +TEST(TestingAllocator, DetectDoubleFree) {
  42.128 +    CxTestingAllocator allocator;
  42.129 +
  42.130 +    ASSERT_TRUE(allocator.verify());
  42.131 +    auto ptr = cxMalloc(&allocator, 16);
  42.132 +    ASSERT_NE(ptr, nullptr);
  42.133 +
  42.134 +    cxFree(&allocator, ptr);
  42.135 +    EXPECT_TRUE(allocator.verify());
  42.136 +    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
  42.137 +    EXPECT_FALSE(allocator.verify());
  42.138 +}
  42.139 +
  42.140 +TEST(TestingAllocator, FreeUntracked) {
  42.141 +    CxTestingAllocator allocator;
  42.142 +
  42.143 +    auto ptr = malloc(16);
  42.144 +    ASSERT_TRUE(allocator.verify());
  42.145 +    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
  42.146 +    EXPECT_FALSE(allocator.verify());
  42.147 +    ASSERT_NO_FATAL_FAILURE(free(ptr));
  42.148 +}
  42.149 +
  42.150 +TEST(TestingAllocator, FullLifecycleWithRealloc) {
  42.151 +    CxTestingAllocator allocator;
  42.152 +    ASSERT_TRUE(allocator.verify());
  42.153 +    auto ptr = cxMalloc(&allocator, 16);
  42.154 +    ASSERT_NE(ptr, nullptr);
  42.155 +    EXPECT_EQ(allocator.tracked.size(), 1);
  42.156 +    ptr = cxRealloc(&allocator, ptr, 256);
  42.157 +    ASSERT_NE(ptr, nullptr);
  42.158 +    EXPECT_EQ(allocator.tracked.size(), 1);
  42.159 +    cxFree(&allocator, ptr);
  42.160 +    EXPECT_TRUE(allocator.verify());
  42.161 +}
  42.162 +
  42.163 +TEST(TestingAllocator, CallocInitializes) {
  42.164 +    CxTestingAllocator allocator;
  42.165 +    const char zeros[16] = {0};
  42.166 +    auto ptr = cxCalloc(&allocator, 16, 1);
  42.167 +    EXPECT_EQ(memcmp(ptr, zeros, 16), 0);
  42.168 +    cxFree(&allocator, ptr);
  42.169 +    EXPECT_TRUE(allocator.verify());
  42.170 +}
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/tests/util_allocator.h	Wed Feb 08 20:26:26 2023 +0100
    43.3 @@ -0,0 +1,81 @@
    43.4 +/*
    43.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    43.6 + *
    43.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
    43.8 + *
    43.9 + * Redistribution and use in source and binary forms, with or without
   43.10 + * modification, are permitted provided that the following conditions are met:
   43.11 + *
   43.12 + *   1. Redistributions of source code must retain the above copyright
   43.13 + *      notice, this list of conditions and the following disclaimer.
   43.14 + *
   43.15 + *   2. Redistributions in binary form must reproduce the above copyright
   43.16 + *      notice, this list of conditions and the following disclaimer in the
   43.17 + *      documentation and/or other materials provided with the distribution.
   43.18 + *
   43.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   43.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   43.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   43.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   43.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   43.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   43.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   43.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   43.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   43.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   43.29 + * POSSIBILITY OF SUCH DAMAGE.
   43.30 + */
   43.31 +
   43.32 +#ifndef UCX_UTIL_ALLOCATOR_H
   43.33 +#define UCX_UTIL_ALLOCATOR_H
   43.34 +
   43.35 +#include "cx/allocator.h"
   43.36 +
   43.37 +#include <set>
   43.38 +
   43.39 +struct CxTestingAllocator : public CxAllocator {
   43.40 +    /**
   43.41 +     * Total number of all allocations (malloc, calloc, realloc).
   43.42 +     * A realloc() does only count when the memory has to be moved.
   43.43 +     */
   43.44 +    unsigned alloc_total = 0;
   43.45 +    /**
   43.46 +     * Number of failed allocations (malloc, calloc, realloc).
   43.47 +     */
   43.48 +    unsigned alloc_failed = 0;
   43.49 +    /**
   43.50 +     * Total number of freed pointers.
   43.51 +     * A reallocation also counts as a free when the memory has to be moved.
   43.52 +     */
   43.53 +    unsigned free_total = 0;
   43.54 +    /**
   43.55 +     * Number of failed free invocations.
   43.56 +     * A free() is considered failed, if it has not been performed on tracked memory.
   43.57 +     */
   43.58 +    unsigned free_failed = 0;
   43.59 +    /**
   43.60 +     * The set of tracked memory blocks.
   43.61 +     */
   43.62 +    std::set<void *> tracked;
   43.63 +
   43.64 +    /**
   43.65 +     * Constructs a new testing allocator.
   43.66 +     */
   43.67 +    CxTestingAllocator();
   43.68 +
   43.69 +    /**
   43.70 +     * Verifies that this allocator has been used.
   43.71 +     *
   43.72 +     * @return true if any allocation was attempted using this allocator
   43.73 +     */
   43.74 +    [[nodiscard]] bool used() const;
   43.75 +
   43.76 +    /**
   43.77 +     * Verifies that all allocated memory blocks are freed and no free occurred twice.
   43.78 +     *
   43.79 +     * @return true iff all tracked allocations / deallocations were valid
   43.80 +     */
   43.81 +    [[nodiscard]] bool verify() const;
   43.82 +};
   43.83 +
   43.84 +#endif // UCX_UTIL_ALLOCATOR_H

mercurial