migrates self-test for testing allocator - relates to #342

Wed, 27 Dec 2023 16:04:38 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 27 Dec 2023 16:04:38 +0100
changeset 770
ed710122af44
parent 769
b53e0e003d7e
child 771
1c7202701bd6

migrates self-test for testing allocator - relates to #342

CHANGELOG file | annotate | diff | comparison | revisions
tests/Makefile file | annotate | diff | comparison | revisions
tests/ucxtest.c file | annotate | diff | comparison | revisions
tests/util_allocator.c file | annotate | diff | comparison | revisions
tests/util_allocator.cpp file | annotate | diff | comparison | revisions
tests/util_allocator.h file | annotate | diff | comparison | revisions
     1.1 --- a/CHANGELOG	Wed Dec 27 14:54:04 2023 +0100
     1.2 +++ b/CHANGELOG	Wed Dec 27 16:04:38 2023 +0100
     1.3 @@ -4,8 +4,10 @@
     1.4   * adds cxListFindRemove()
     1.5   * adds cxBufferReset()
     1.6   * adds cx_cmp_ptr()
     1.7 + * adds improved version of UCX 2 Test framework (now a self-contained header)
     1.8   * fixes wrong link from UCX 2 documentation to UCX 3 documentation
     1.9 - * removes CMake, except for tests at the moment, in favor of uwproj
    1.10 + * removes CMake
    1.11 + * removes GTest dependency
    1.12  
    1.13  Version 3.0 - 2023-07-09
    1.14  ------------------------
     2.1 --- a/tests/Makefile	Wed Dec 27 14:54:04 2023 +0100
     2.2 +++ b/tests/Makefile	Wed Dec 27 16:04:38 2023 +0100
     2.3 @@ -27,7 +27,7 @@
     2.4  
     2.5  TEST_DIR=$(build_dir)/tests
     2.6  
     2.7 -SRC = test_utils.c test_hash_key.c ucxtest.c
     2.8 +SRC = util_allocator.c test_utils.c test_hash_key.c ucxtest.c
     2.9  
    2.10  OBJ_EXT=.o
    2.11  OBJ=$(SRC:%.c=$(TEST_DIR)/%$(OBJ_EXT))
    2.12 @@ -69,3 +69,8 @@
    2.13  	@echo "Compiling $<"
    2.14  	$(CC) -o $@ $(CFLAGS) -c $<
    2.15  
    2.16 +$(TEST_DIR)/util_allocator$(OBJ_EXT): util_allocator.c util_allocator.h \
    2.17 + ../src/cx/allocator.h ../src/cx/common.h ../src/cx/test.h
    2.18 +	@echo "Compiling $<"
    2.19 +	$(CC) -o $@ $(CFLAGS) -c $<
    2.20 +
     3.1 --- a/tests/ucxtest.c	Wed Dec 27 14:54:04 2023 +0100
     3.2 +++ b/tests/ucxtest.c	Wed Dec 27 16:04:38 2023 +0100
     3.3 @@ -28,32 +28,27 @@
     3.4  
     3.5  #include "cx/test.h"
     3.6  
     3.7 +CxTestSuite *cx_test_suite_testing_allocator(void);
     3.8  CxTestSuite *cx_test_suite_utils(void);
     3.9  CxTestSuite *cx_test_suite_hash_key(void);
    3.10  
    3.11  #define run_tests(suite) cx_test_run_stdout(suite); success += (suite)->success; failure += (suite)->failure
    3.12 +#define execute_test_suites(...) unsigned success = 0, failure = 0; CxTestSuite* test_suites[] = {__VA_ARGS__}; \
    3.13 +    for (size_t i = 0; i < sizeof(test_suites)/sizeof(void*) ; i++) {run_tests(test_suites[i]);} (void)0
    3.14 +#define free_test_suites for (size_t i = 0 ; i < sizeof(test_suites)/sizeof(void*) ; i++) {cx_test_suite_free(test_suites[i]);} (void)0
    3.15  
    3.16  int main(void) {
    3.17      printf("UCX Tests\n---------\n");
    3.18  
    3.19 -    unsigned success = 0, failure = 0;
    3.20 -
    3.21 -    // create test suites
    3.22 -    CxTestSuite
    3.23 -    *utils = cx_test_suite_utils(),
    3.24 -    *hash_key = cx_test_suite_hash_key();
    3.25 -
    3.26 -    // run tests
    3.27 -    run_tests(utils);
    3.28 -    run_tests(hash_key);
    3.29 -
    3.30 -    // print overall result
    3.31 +    execute_test_suites(
    3.32 +            cx_test_suite_testing_allocator(),
    3.33 +            cx_test_suite_utils(),
    3.34 +            cx_test_suite_hash_key()
    3.35 +    );
    3.36      printf("=== OVERALL RESULT ===\n");
    3.37      printf("  Total:   %u\n  Success: %u\n  Failure: %u\n",
    3.38             success + failure, success, failure);
    3.39 -
    3.40 -    cx_test_suite_free(utils);
    3.41 -    cx_test_suite_free(hash_key);
    3.42 +    free_test_suites;
    3.43  
    3.44      return failure > 0 ? 1 : 0;
    3.45  }
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tests/util_allocator.c	Wed Dec 27 16:04:38 2023 +0100
     4.3 @@ -0,0 +1,253 @@
     4.4 +/*
     4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     4.6 + *
     4.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     4.8 + *
     4.9 + * Redistribution and use in source and binary forms, with or without
    4.10 + * modification, are permitted provided that the following conditions are met:
    4.11 + *
    4.12 + *   1. Redistributions of source code must retain the above copyright
    4.13 + *      notice, this list of conditions and the following disclaimer.
    4.14 + *
    4.15 + *   2. Redistributions in binary form must reproduce the above copyright
    4.16 + *      notice, this list of conditions and the following disclaimer in the
    4.17 + *      documentation and/or other materials provided with the distribution.
    4.18 + *
    4.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    4.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    4.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    4.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    4.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    4.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    4.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    4.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    4.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    4.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    4.29 + * POSSIBILITY OF SUCH DAMAGE.
    4.30 + */
    4.31 +
    4.32 +#include "util_allocator.h"
    4.33 +#include "cx/test.h"
    4.34 +
    4.35 +static void cx_testing_allocator_track(CxTestingAllocator *alloc, void *ptr) {
    4.36 +    for (size_t i = 0; i < alloc->tracked_count; i++) {
    4.37 +        if (alloc->tracked[i] == ptr) return; // is already tracked
    4.38 +    }
    4.39 +
    4.40 +    if (alloc->tracked_count == alloc->tracked_capacity) {
    4.41 +        size_t newcapa = alloc->tracked_capacity + 64;
    4.42 +        void *newarr = realloc(alloc->tracked, newcapa * sizeof(void *));
    4.43 +        if (newarr == NULL) abort();
    4.44 +        alloc->tracked = newarr;
    4.45 +        alloc->tracked_capacity = newcapa;
    4.46 +    }
    4.47 +
    4.48 +    alloc->tracked[alloc->tracked_count] = ptr;
    4.49 +    alloc->tracked_count++;
    4.50 +}
    4.51 +
    4.52 +static bool cx_testing_allocator_untrack(CxTestingAllocator *alloc, void *ptr) {
    4.53 +    for (size_t i = 0; i < alloc->tracked_count; i++) {
    4.54 +        if (alloc->tracked[i] == ptr) {
    4.55 +            size_t last = alloc->tracked_count - 1;
    4.56 +            if (i < last) {
    4.57 +                alloc->tracked[i] = alloc->tracked[last];
    4.58 +            }
    4.59 +            alloc->tracked_count--;
    4.60 +            return true;
    4.61 +        }
    4.62 +    }
    4.63 +    return false;
    4.64 +}
    4.65 +
    4.66 +static void *cx_malloc_testing(void *d, size_t n) {
    4.67 +    CxTestingAllocator *data = d;
    4.68 +    void *ptr = malloc(n);
    4.69 +    data->alloc_total++;
    4.70 +    if (ptr == NULL) {
    4.71 +        data->alloc_failed++;
    4.72 +    } else {
    4.73 +        cx_testing_allocator_track(data, ptr);
    4.74 +    }
    4.75 +    return ptr;
    4.76 +}
    4.77 +
    4.78 +static void *cx_realloc_testing(void *d, void *mem, size_t n) {
    4.79 +    CxTestingAllocator *data = d;
    4.80 +    void *ptr = realloc(mem, n);
    4.81 +    if (ptr == mem) {
    4.82 +        return ptr;
    4.83 +    } else {
    4.84 +        data->alloc_total++;
    4.85 +        if (ptr == NULL) {
    4.86 +            data->alloc_failed++;
    4.87 +        } else {
    4.88 +            data->free_total++;
    4.89 +            if (!cx_testing_allocator_untrack(data, mem)) {
    4.90 +                data->free_failed++;
    4.91 +            }
    4.92 +            cx_testing_allocator_track(data, ptr);
    4.93 +        }
    4.94 +        return ptr;
    4.95 +    }
    4.96 +}
    4.97 +
    4.98 +static void *cx_calloc_testing(void *d, size_t nelem, size_t n) {
    4.99 +    CxTestingAllocator *data = d;
   4.100 +    void *ptr = calloc(nelem, n);
   4.101 +    data->alloc_total++;
   4.102 +    if (ptr == NULL) {
   4.103 +        data->alloc_failed++;
   4.104 +    } else {
   4.105 +        cx_testing_allocator_track(data, ptr);
   4.106 +    }
   4.107 +    return ptr;
   4.108 +}
   4.109 +
   4.110 +static void cx_free_testing(void *d, void *mem) {
   4.111 +    CxTestingAllocator *data = d;
   4.112 +    data->free_total++;
   4.113 +    if (cx_testing_allocator_untrack(data, mem)) {
   4.114 +        free(mem);
   4.115 +    } else {
   4.116 +        data->free_failed++;
   4.117 +        // do not even attempt to free mem, because it is likely to segfault
   4.118 +    }
   4.119 +}
   4.120 +
   4.121 +cx_allocator_class cx_testing_allocator_class = {
   4.122 +        cx_malloc_testing,
   4.123 +        cx_realloc_testing,
   4.124 +        cx_calloc_testing,
   4.125 +        cx_free_testing
   4.126 +};
   4.127 +
   4.128 +
   4.129 +void cx_testing_allocator_init(CxTestingAllocator *alloc) {
   4.130 +    alloc->base.cl = &cx_testing_allocator_class;
   4.131 +    alloc->base.data = alloc;
   4.132 +    alloc->alloc_failed = 0;
   4.133 +    alloc->alloc_total = 0;
   4.134 +    alloc->free_failed = 0;
   4.135 +    alloc->free_total = 0;
   4.136 +    size_t initial_capa = 16;
   4.137 +    alloc->tracked_capacity = initial_capa;
   4.138 +    alloc->tracked_count = 0;
   4.139 +    alloc->tracked = calloc(sizeof(void *), initial_capa);
   4.140 +}
   4.141 +
   4.142 +void cx_testing_allocator_destroy(CxTestingAllocator *alloc) {
   4.143 +    free(alloc->tracked);
   4.144 +}
   4.145 +
   4.146 +bool cx_testing_allocator_used(CxTestingAllocator const *alloc) {
   4.147 +    return alloc->alloc_total > 0;
   4.148 +}
   4.149 +
   4.150 +bool cx_testing_allocator_verify(CxTestingAllocator const *alloc) {
   4.151 +    return alloc->tracked_count == 0 && alloc->alloc_failed == 0 && alloc->free_failed == 0
   4.152 +           && alloc->alloc_total == alloc->free_total;
   4.153 +}
   4.154 +
   4.155 +// SELF-TEST
   4.156 +
   4.157 +CX_TEST(test_util_allocator_expect_free) {
   4.158 +    CxTestingAllocator talloc;
   4.159 +    cx_testing_allocator_init(&talloc);
   4.160 +    CxAllocator *alloc = &talloc.base;
   4.161 +    CX_TEST_DO {
   4.162 +        CX_TEST_ASSERTM(cx_testing_allocator_verify(&talloc),
   4.163 +                        "Fresh testing allocator fails to verify.");
   4.164 +        CX_TEST_ASSERTM(!cx_testing_allocator_used(&talloc),
   4.165 +                        "Fresh testing allocator already used.");
   4.166 +        void *ptr = cxMalloc(alloc, 16);
   4.167 +        CX_TEST_ASSERTM(!cx_testing_allocator_verify(&talloc),
   4.168 +                        "Testing allocator verifies with unfreed memory.");
   4.169 +        CX_TEST_ASSERT(cx_testing_allocator_used(&talloc));
   4.170 +        CX_TEST_ASSERT(ptr != NULL);
   4.171 +
   4.172 +        cxFree(alloc, ptr);
   4.173 +        CX_TEST_ASSERTM(cx_testing_allocator_verify(&talloc),
   4.174 +                        "Testing allocator fails to verify after everything freed.");
   4.175 +    }
   4.176 +    cx_testing_allocator_destroy(&talloc);
   4.177 +}
   4.178 +
   4.179 +CX_TEST(test_util_allocator_detect_double_free) {
   4.180 +    CxTestingAllocator talloc;
   4.181 +    cx_testing_allocator_init(&talloc);
   4.182 +    CxAllocator *alloc = &talloc.base;
   4.183 +    CX_TEST_DO {
   4.184 +        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   4.185 +        void *ptr = cxMalloc(alloc, 16);
   4.186 +        CX_TEST_ASSERT(ptr != NULL);
   4.187 +        cxFree(alloc, ptr);
   4.188 +        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   4.189 +        cxFree(alloc, ptr);
   4.190 +        CX_TEST_ASSERTM(!cx_testing_allocator_verify(&talloc),
   4.191 +                        "Testing allocator does not detect double-free.");
   4.192 +    }
   4.193 +    cx_testing_allocator_destroy(&talloc);
   4.194 +}
   4.195 +
   4.196 +CX_TEST(test_util_allocator_free_untracked) {
   4.197 +    CxTestingAllocator talloc;
   4.198 +    cx_testing_allocator_init(&talloc);
   4.199 +    CxAllocator *alloc = &talloc.base;
   4.200 +    void *ptr = malloc(16);
   4.201 +    CX_TEST_DO {
   4.202 +        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   4.203 +        cxFree(alloc, ptr);
   4.204 +        CX_TEST_ASSERTM(!cx_testing_allocator_verify(&talloc),
   4.205 +                        "Testing allocator does not detect free of untracked memory.");
   4.206 +    }
   4.207 +    free(ptr);
   4.208 +    cx_testing_allocator_destroy(&talloc);
   4.209 +}
   4.210 +
   4.211 +CX_TEST(test_util_allocator_full_lifecycle_with_realloc) {
   4.212 +    CxTestingAllocator talloc;
   4.213 +    cx_testing_allocator_init(&talloc);
   4.214 +    CxAllocator *alloc = &talloc.base;
   4.215 +    CX_TEST_DO {
   4.216 +        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   4.217 +        void *ptr = cxMalloc(alloc, 16);
   4.218 +        CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
   4.219 +        CX_TEST_ASSERT(ptr != NULL);
   4.220 +        CX_TEST_ASSERT(talloc.tracked_count == 1);
   4.221 +        ptr = cxRealloc(alloc, ptr, 256);
   4.222 +        CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
   4.223 +        CX_TEST_ASSERT(ptr != NULL);
   4.224 +        CX_TEST_ASSERT(talloc.tracked_count == 1);
   4.225 +        cxFree(alloc, ptr);
   4.226 +        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   4.227 +    }
   4.228 +    cx_testing_allocator_destroy(&talloc);
   4.229 +}
   4.230 +
   4.231 +CX_TEST(test_util_allocator_calloc_initializes) {
   4.232 +    CxTestingAllocator talloc;
   4.233 +    cx_testing_allocator_init(&talloc);
   4.234 +    CxAllocator *alloc = &talloc.base;
   4.235 +    CX_TEST_DO {
   4.236 +        const char zeros[16] = {0};
   4.237 +        void *ptr = cxCalloc(alloc, 16, 1);
   4.238 +        CX_TEST_ASSERT(memcmp(ptr, zeros, 16) == 0);
   4.239 +        cxFree(alloc, ptr);
   4.240 +        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   4.241 +    }
   4.242 +    cx_testing_allocator_destroy(&talloc);
   4.243 +}
   4.244 +
   4.245 +CxTestSuite *cx_test_suite_testing_allocator(void) {
   4.246 +    CxTestSuite *suite = cx_test_suite_new("testing allocator self-test");
   4.247 +
   4.248 +    cx_test_register(suite, test_util_allocator_expect_free);
   4.249 +    cx_test_register(suite, test_util_allocator_detect_double_free);
   4.250 +    cx_test_register(suite, test_util_allocator_free_untracked);
   4.251 +    cx_test_register(suite, test_util_allocator_full_lifecycle_with_realloc);
   4.252 +    cx_test_register(suite, test_util_allocator_calloc_initializes);
   4.253 +
   4.254 +    return suite;
   4.255 +}
   4.256 +
     5.1 --- a/tests/util_allocator.cpp	Wed Dec 27 14:54:04 2023 +0100
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,167 +0,0 @@
     5.4 -/*
     5.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     5.6 - *
     5.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     5.8 - *
     5.9 - * Redistribution and use in source and binary forms, with or without
    5.10 - * modification, are permitted provided that the following conditions are met:
    5.11 - *
    5.12 - *   1. Redistributions of source code must retain the above copyright
    5.13 - *      notice, this list of conditions and the following disclaimer.
    5.14 - *
    5.15 - *   2. Redistributions in binary form must reproduce the above copyright
    5.16 - *      notice, this list of conditions and the following disclaimer in the
    5.17 - *      documentation and/or other materials provided with the distribution.
    5.18 - *
    5.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    5.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    5.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    5.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    5.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    5.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    5.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    5.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    5.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    5.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    5.29 - * POSSIBILITY OF SUCH DAMAGE.
    5.30 - */
    5.31 -
    5.32 -#include "util_allocator.h"
    5.33 -
    5.34 -void *cx_malloc_testing(void *d, size_t n) {
    5.35 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
    5.36 -    void *ptr = malloc(n);
    5.37 -    data->alloc_total++;
    5.38 -    if (ptr == nullptr) {
    5.39 -        data->alloc_failed++;
    5.40 -    } else {
    5.41 -        data->tracked.insert(ptr);
    5.42 -    }
    5.43 -    return ptr;
    5.44 -}
    5.45 -
    5.46 -void *cx_realloc_testing(void *d, void *mem, size_t n) {
    5.47 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
    5.48 -    void *ptr = realloc(mem, n);
    5.49 -    if (ptr == mem) {
    5.50 -        return ptr;
    5.51 -    } else {
    5.52 -        data->alloc_total++;
    5.53 -        if (ptr == nullptr) {
    5.54 -            data->alloc_failed++;
    5.55 -        } else {
    5.56 -            data->free_total++;
    5.57 -            if (data->tracked.erase(mem) == 0) {
    5.58 -                data->free_failed++;
    5.59 -            }
    5.60 -            data->tracked.insert(ptr);
    5.61 -        }
    5.62 -        return ptr;
    5.63 -    }
    5.64 -}
    5.65 -
    5.66 -void *cx_calloc_testing(void *d, size_t nelem, size_t n) {
    5.67 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
    5.68 -    void *ptr = calloc(nelem, n);
    5.69 -    data->alloc_total++;
    5.70 -    if (ptr == nullptr) {
    5.71 -        data->alloc_failed++;
    5.72 -    } else {
    5.73 -        data->tracked.insert(ptr);
    5.74 -    }
    5.75 -    return ptr;
    5.76 -}
    5.77 -
    5.78 -void cx_free_testing(void *d, void *mem) {
    5.79 -    auto data = reinterpret_cast<CxTestingAllocator *>(d);
    5.80 -    data->free_total++;
    5.81 -    if (data->tracked.erase(mem) == 0) {
    5.82 -        data->free_failed++;
    5.83 -        // do not even attempt to free mem, because it is likely to segfault
    5.84 -    } else {
    5.85 -        free(mem);
    5.86 -    }
    5.87 -}
    5.88 -
    5.89 -cx_allocator_class cx_testing_allocator_class = {
    5.90 -        cx_malloc_testing,
    5.91 -        cx_realloc_testing,
    5.92 -        cx_calloc_testing,
    5.93 -        cx_free_testing
    5.94 -};
    5.95 -
    5.96 -CxTestingAllocator::CxTestingAllocator() : CxAllocator() {
    5.97 -    cl = &cx_testing_allocator_class;
    5.98 -    data = this;
    5.99 -}
   5.100 -
   5.101 -bool CxTestingAllocator::used() const {
   5.102 -    return alloc_total > 0;
   5.103 -}
   5.104 -
   5.105 -bool CxTestingAllocator::verify() const {
   5.106 -    return tracked.empty() && alloc_failed == 0 && free_failed == 0 && alloc_total == free_total;
   5.107 -}
   5.108 -
   5.109 -// SELF-TEST
   5.110 -
   5.111 -#include <gtest/gtest.h>
   5.112 -
   5.113 -TEST(TestingAllocator, ExpectFree) {
   5.114 -    CxTestingAllocator allocator;
   5.115 -
   5.116 -    ASSERT_TRUE(allocator.verify());
   5.117 -    EXPECT_FALSE(allocator.used());
   5.118 -    auto ptr = cxMalloc(&allocator, 16);
   5.119 -    EXPECT_TRUE(allocator.used());
   5.120 -    ASSERT_NE(ptr, nullptr);
   5.121 -    EXPECT_FALSE(allocator.verify());
   5.122 -
   5.123 -    cxFree(&allocator, ptr);
   5.124 -    EXPECT_TRUE(allocator.verify());
   5.125 -}
   5.126 -
   5.127 -TEST(TestingAllocator, DetectDoubleFree) {
   5.128 -    CxTestingAllocator allocator;
   5.129 -
   5.130 -    ASSERT_TRUE(allocator.verify());
   5.131 -    auto ptr = cxMalloc(&allocator, 16);
   5.132 -    ASSERT_NE(ptr, nullptr);
   5.133 -
   5.134 -    cxFree(&allocator, ptr);
   5.135 -    EXPECT_TRUE(allocator.verify());
   5.136 -    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
   5.137 -    EXPECT_FALSE(allocator.verify());
   5.138 -}
   5.139 -
   5.140 -TEST(TestingAllocator, FreeUntracked) {
   5.141 -    CxTestingAllocator allocator;
   5.142 -
   5.143 -    auto ptr = malloc(16);
   5.144 -    ASSERT_TRUE(allocator.verify());
   5.145 -    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
   5.146 -    EXPECT_FALSE(allocator.verify());
   5.147 -    ASSERT_NO_FATAL_FAILURE(free(ptr));
   5.148 -}
   5.149 -
   5.150 -TEST(TestingAllocator, FullLifecycleWithRealloc) {
   5.151 -    CxTestingAllocator allocator;
   5.152 -    ASSERT_TRUE(allocator.verify());
   5.153 -    auto ptr = cxMalloc(&allocator, 16);
   5.154 -    ASSERT_NE(ptr, nullptr);
   5.155 -    EXPECT_EQ(allocator.tracked.size(), 1);
   5.156 -    ptr = cxRealloc(&allocator, ptr, 256);
   5.157 -    ASSERT_NE(ptr, nullptr);
   5.158 -    EXPECT_EQ(allocator.tracked.size(), 1);
   5.159 -    cxFree(&allocator, ptr);
   5.160 -    EXPECT_TRUE(allocator.verify());
   5.161 -}
   5.162 -
   5.163 -TEST(TestingAllocator, CallocInitializes) {
   5.164 -    CxTestingAllocator allocator;
   5.165 -    const char zeros[16] = {0};
   5.166 -    auto ptr = cxCalloc(&allocator, 16, 1);
   5.167 -    EXPECT_EQ(memcmp(ptr, zeros, 16), 0);
   5.168 -    cxFree(&allocator, ptr);
   5.169 -    EXPECT_TRUE(allocator.verify());
   5.170 -}
     6.1 --- a/tests/util_allocator.h	Wed Dec 27 14:54:04 2023 +0100
     6.2 +++ b/tests/util_allocator.h	Wed Dec 27 16:04:38 2023 +0100
     6.3 @@ -26,56 +26,77 @@
     6.4   * POSSIBILITY OF SUCH DAMAGE.
     6.5   */
     6.6  
     6.7 -#ifndef UCX_UTIL_ALLOCATOR_H
     6.8 -#define UCX_UTIL_ALLOCATOR_H
     6.9 +#ifndef UCX_TEST_UTIL_ALLOCATOR_H
    6.10 +#define UCX_TEST_UTIL_ALLOCATOR_H
    6.11  
    6.12  #include "cx/allocator.h"
    6.13  
    6.14 -#include <set>
    6.15 +#ifdef __cplusplus
    6.16 +#extern "C" {
    6.17 +#endif
    6.18  
    6.19 -struct CxTestingAllocator : public CxAllocator {
    6.20 +typedef struct CxTestingAllocator {
    6.21 +    CxAllocator base;
    6.22      /**
    6.23       * Total number of all allocations (malloc, calloc, realloc).
    6.24       * A realloc() does only count when the memory has to be moved.
    6.25       */
    6.26 -    unsigned alloc_total = 0;
    6.27 +    unsigned alloc_total;
    6.28      /**
    6.29       * Number of failed allocations (malloc, calloc, realloc).
    6.30       */
    6.31 -    unsigned alloc_failed = 0;
    6.32 +    unsigned alloc_failed;
    6.33      /**
    6.34       * Total number of freed pointers.
    6.35       * A reallocation also counts as a free when the memory has to be moved.
    6.36       */
    6.37 -    unsigned free_total = 0;
    6.38 +    unsigned free_total;
    6.39      /**
    6.40       * Number of failed free invocations.
    6.41       * A free() is considered failed, if it has not been performed on tracked memory.
    6.42       */
    6.43 -    unsigned free_failed = 0;
    6.44 +    unsigned free_failed;
    6.45 +    /**
    6.46 +     * The number of currently tracked memory blocks.
    6.47 +     */
    6.48 +    size_t tracked_count;
    6.49 +    /**
    6.50 +     * The capaciyty of the \c tracked array.
    6.51 +     */
    6.52 +    size_t tracked_capacity;
    6.53      /**
    6.54       * The set of tracked memory blocks.
    6.55       */
    6.56 -    std::set<void *> tracked;
    6.57 +    void **tracked;
    6.58 +} CxTestingAllocator;
    6.59  
    6.60 -    /**
    6.61 -     * Constructs a new testing allocator.
    6.62 -     */
    6.63 -    CxTestingAllocator();
    6.64  
    6.65 -    /**
    6.66 -     * Verifies that this allocator has been used.
    6.67 -     *
    6.68 -     * @return true if any allocation was attempted using this allocator
    6.69 -     */
    6.70 -    [[nodiscard]] bool used() const;
    6.71 +/**
    6.72 + * Initializes a new testing allocator.
    6.73 + */
    6.74 +void cx_testing_allocator_init(CxTestingAllocator *alloc);
    6.75  
    6.76 -    /**
    6.77 -     * Verifies that all allocated memory blocks are freed and no free occurred twice.
    6.78 -     *
    6.79 -     * @return true iff all tracked allocations / deallocations were valid
    6.80 -     */
    6.81 -    [[nodiscard]] bool verify() const;
    6.82 -};
    6.83 +/**
    6.84 + * Destroys a testing allocator.
    6.85 + */
    6.86 +void cx_testing_allocator_destroy(CxTestingAllocator *alloc);
    6.87  
    6.88 -#endif // UCX_UTIL_ALLOCATOR_H
    6.89 +/**
    6.90 + * Verifies that this allocator has been used.
    6.91 + *
    6.92 + * @return true if any allocation was attempted using this allocator
    6.93 + */
    6.94 +bool cx_testing_allocator_used(CxTestingAllocator const *alloc);
    6.95 +
    6.96 +/**
    6.97 + * Verifies that all allocated memory blocks are freed and no free occurred twice.
    6.98 + *
    6.99 + * @return true iff all tracked allocations / deallocations were valid
   6.100 + */
   6.101 +bool cx_testing_allocator_verify(CxTestingAllocator const *alloc);
   6.102 +
   6.103 +#ifdef __cplusplus
   6.104 +} // extern "C"
   6.105 +#endif
   6.106 +
   6.107 +#endif // UCX_TEST_UTIL_ALLOCATOR_H

mercurial