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
--- a/CHANGELOG	Wed Dec 27 14:54:04 2023 +0100
+++ b/CHANGELOG	Wed Dec 27 16:04:38 2023 +0100
@@ -4,8 +4,10 @@
  * adds cxListFindRemove()
  * adds cxBufferReset()
  * adds cx_cmp_ptr()
+ * adds improved version of UCX 2 Test framework (now a self-contained header)
  * fixes wrong link from UCX 2 documentation to UCX 3 documentation
- * removes CMake, except for tests at the moment, in favor of uwproj
+ * removes CMake
+ * removes GTest dependency
 
 Version 3.0 - 2023-07-09
 ------------------------
--- a/tests/Makefile	Wed Dec 27 14:54:04 2023 +0100
+++ b/tests/Makefile	Wed Dec 27 16:04:38 2023 +0100
@@ -27,7 +27,7 @@
 
 TEST_DIR=$(build_dir)/tests
 
-SRC = test_utils.c test_hash_key.c ucxtest.c
+SRC = util_allocator.c test_utils.c test_hash_key.c ucxtest.c
 
 OBJ_EXT=.o
 OBJ=$(SRC:%.c=$(TEST_DIR)/%$(OBJ_EXT))
@@ -69,3 +69,8 @@
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
+$(TEST_DIR)/util_allocator$(OBJ_EXT): util_allocator.c util_allocator.h \
+ ../src/cx/allocator.h ../src/cx/common.h ../src/cx/test.h
+	@echo "Compiling $<"
+	$(CC) -o $@ $(CFLAGS) -c $<
+
--- a/tests/ucxtest.c	Wed Dec 27 14:54:04 2023 +0100
+++ b/tests/ucxtest.c	Wed Dec 27 16:04:38 2023 +0100
@@ -28,32 +28,27 @@
 
 #include "cx/test.h"
 
+CxTestSuite *cx_test_suite_testing_allocator(void);
 CxTestSuite *cx_test_suite_utils(void);
 CxTestSuite *cx_test_suite_hash_key(void);
 
 #define run_tests(suite) cx_test_run_stdout(suite); success += (suite)->success; failure += (suite)->failure
+#define execute_test_suites(...) unsigned success = 0, failure = 0; CxTestSuite* test_suites[] = {__VA_ARGS__}; \
+    for (size_t i = 0; i < sizeof(test_suites)/sizeof(void*) ; i++) {run_tests(test_suites[i]);} (void)0
+#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
 
 int main(void) {
     printf("UCX Tests\n---------\n");
 
-    unsigned success = 0, failure = 0;
-
-    // create test suites
-    CxTestSuite
-    *utils = cx_test_suite_utils(),
-    *hash_key = cx_test_suite_hash_key();
-
-    // run tests
-    run_tests(utils);
-    run_tests(hash_key);
-
-    // print overall result
+    execute_test_suites(
+            cx_test_suite_testing_allocator(),
+            cx_test_suite_utils(),
+            cx_test_suite_hash_key()
+    );
     printf("=== OVERALL RESULT ===\n");
     printf("  Total:   %u\n  Success: %u\n  Failure: %u\n",
            success + failure, success, failure);
-
-    cx_test_suite_free(utils);
-    cx_test_suite_free(hash_key);
+    free_test_suites;
 
     return failure > 0 ? 1 : 0;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/util_allocator.c	Wed Dec 27 16:04:38 2023 +0100
@@ -0,0 +1,253 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "util_allocator.h"
+#include "cx/test.h"
+
+static void cx_testing_allocator_track(CxTestingAllocator *alloc, void *ptr) {
+    for (size_t i = 0; i < alloc->tracked_count; i++) {
+        if (alloc->tracked[i] == ptr) return; // is already tracked
+    }
+
+    if (alloc->tracked_count == alloc->tracked_capacity) {
+        size_t newcapa = alloc->tracked_capacity + 64;
+        void *newarr = realloc(alloc->tracked, newcapa * sizeof(void *));
+        if (newarr == NULL) abort();
+        alloc->tracked = newarr;
+        alloc->tracked_capacity = newcapa;
+    }
+
+    alloc->tracked[alloc->tracked_count] = ptr;
+    alloc->tracked_count++;
+}
+
+static bool cx_testing_allocator_untrack(CxTestingAllocator *alloc, void *ptr) {
+    for (size_t i = 0; i < alloc->tracked_count; i++) {
+        if (alloc->tracked[i] == ptr) {
+            size_t last = alloc->tracked_count - 1;
+            if (i < last) {
+                alloc->tracked[i] = alloc->tracked[last];
+            }
+            alloc->tracked_count--;
+            return true;
+        }
+    }
+    return false;
+}
+
+static void *cx_malloc_testing(void *d, size_t n) {
+    CxTestingAllocator *data = d;
+    void *ptr = malloc(n);
+    data->alloc_total++;
+    if (ptr == NULL) {
+        data->alloc_failed++;
+    } else {
+        cx_testing_allocator_track(data, ptr);
+    }
+    return ptr;
+}
+
+static void *cx_realloc_testing(void *d, void *mem, size_t n) {
+    CxTestingAllocator *data = d;
+    void *ptr = realloc(mem, n);
+    if (ptr == mem) {
+        return ptr;
+    } else {
+        data->alloc_total++;
+        if (ptr == NULL) {
+            data->alloc_failed++;
+        } else {
+            data->free_total++;
+            if (!cx_testing_allocator_untrack(data, mem)) {
+                data->free_failed++;
+            }
+            cx_testing_allocator_track(data, ptr);
+        }
+        return ptr;
+    }
+}
+
+static void *cx_calloc_testing(void *d, size_t nelem, size_t n) {
+    CxTestingAllocator *data = d;
+    void *ptr = calloc(nelem, n);
+    data->alloc_total++;
+    if (ptr == NULL) {
+        data->alloc_failed++;
+    } else {
+        cx_testing_allocator_track(data, ptr);
+    }
+    return ptr;
+}
+
+static void cx_free_testing(void *d, void *mem) {
+    CxTestingAllocator *data = d;
+    data->free_total++;
+    if (cx_testing_allocator_untrack(data, mem)) {
+        free(mem);
+    } else {
+        data->free_failed++;
+        // do not even attempt to free mem, because it is likely to segfault
+    }
+}
+
+cx_allocator_class cx_testing_allocator_class = {
+        cx_malloc_testing,
+        cx_realloc_testing,
+        cx_calloc_testing,
+        cx_free_testing
+};
+
+
+void cx_testing_allocator_init(CxTestingAllocator *alloc) {
+    alloc->base.cl = &cx_testing_allocator_class;
+    alloc->base.data = alloc;
+    alloc->alloc_failed = 0;
+    alloc->alloc_total = 0;
+    alloc->free_failed = 0;
+    alloc->free_total = 0;
+    size_t initial_capa = 16;
+    alloc->tracked_capacity = initial_capa;
+    alloc->tracked_count = 0;
+    alloc->tracked = calloc(sizeof(void *), initial_capa);
+}
+
+void cx_testing_allocator_destroy(CxTestingAllocator *alloc) {
+    free(alloc->tracked);
+}
+
+bool cx_testing_allocator_used(CxTestingAllocator const *alloc) {
+    return alloc->alloc_total > 0;
+}
+
+bool cx_testing_allocator_verify(CxTestingAllocator const *alloc) {
+    return alloc->tracked_count == 0 && alloc->alloc_failed == 0 && alloc->free_failed == 0
+           && alloc->alloc_total == alloc->free_total;
+}
+
+// SELF-TEST
+
+CX_TEST(test_util_allocator_expect_free) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    CxAllocator *alloc = &talloc.base;
+    CX_TEST_DO {
+        CX_TEST_ASSERTM(cx_testing_allocator_verify(&talloc),
+                        "Fresh testing allocator fails to verify.");
+        CX_TEST_ASSERTM(!cx_testing_allocator_used(&talloc),
+                        "Fresh testing allocator already used.");
+        void *ptr = cxMalloc(alloc, 16);
+        CX_TEST_ASSERTM(!cx_testing_allocator_verify(&talloc),
+                        "Testing allocator verifies with unfreed memory.");
+        CX_TEST_ASSERT(cx_testing_allocator_used(&talloc));
+        CX_TEST_ASSERT(ptr != NULL);
+
+        cxFree(alloc, ptr);
+        CX_TEST_ASSERTM(cx_testing_allocator_verify(&talloc),
+                        "Testing allocator fails to verify after everything freed.");
+    }
+    cx_testing_allocator_destroy(&talloc);
+}
+
+CX_TEST(test_util_allocator_detect_double_free) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    CxAllocator *alloc = &talloc.base;
+    CX_TEST_DO {
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+        void *ptr = cxMalloc(alloc, 16);
+        CX_TEST_ASSERT(ptr != NULL);
+        cxFree(alloc, ptr);
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+        cxFree(alloc, ptr);
+        CX_TEST_ASSERTM(!cx_testing_allocator_verify(&talloc),
+                        "Testing allocator does not detect double-free.");
+    }
+    cx_testing_allocator_destroy(&talloc);
+}
+
+CX_TEST(test_util_allocator_free_untracked) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    CxAllocator *alloc = &talloc.base;
+    void *ptr = malloc(16);
+    CX_TEST_DO {
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+        cxFree(alloc, ptr);
+        CX_TEST_ASSERTM(!cx_testing_allocator_verify(&talloc),
+                        "Testing allocator does not detect free of untracked memory.");
+    }
+    free(ptr);
+    cx_testing_allocator_destroy(&talloc);
+}
+
+CX_TEST(test_util_allocator_full_lifecycle_with_realloc) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    CxAllocator *alloc = &talloc.base;
+    CX_TEST_DO {
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+        void *ptr = cxMalloc(alloc, 16);
+        CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
+        CX_TEST_ASSERT(ptr != NULL);
+        CX_TEST_ASSERT(talloc.tracked_count == 1);
+        ptr = cxRealloc(alloc, ptr, 256);
+        CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
+        CX_TEST_ASSERT(ptr != NULL);
+        CX_TEST_ASSERT(talloc.tracked_count == 1);
+        cxFree(alloc, ptr);
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+    }
+    cx_testing_allocator_destroy(&talloc);
+}
+
+CX_TEST(test_util_allocator_calloc_initializes) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    CxAllocator *alloc = &talloc.base;
+    CX_TEST_DO {
+        const char zeros[16] = {0};
+        void *ptr = cxCalloc(alloc, 16, 1);
+        CX_TEST_ASSERT(memcmp(ptr, zeros, 16) == 0);
+        cxFree(alloc, ptr);
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+    }
+    cx_testing_allocator_destroy(&talloc);
+}
+
+CxTestSuite *cx_test_suite_testing_allocator(void) {
+    CxTestSuite *suite = cx_test_suite_new("testing allocator self-test");
+
+    cx_test_register(suite, test_util_allocator_expect_free);
+    cx_test_register(suite, test_util_allocator_detect_double_free);
+    cx_test_register(suite, test_util_allocator_free_untracked);
+    cx_test_register(suite, test_util_allocator_full_lifecycle_with_realloc);
+    cx_test_register(suite, test_util_allocator_calloc_initializes);
+
+    return suite;
+}
+
--- a/tests/util_allocator.cpp	Wed Dec 27 14:54:04 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *   1. Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "util_allocator.h"
-
-void *cx_malloc_testing(void *d, size_t n) {
-    auto data = reinterpret_cast<CxTestingAllocator *>(d);
-    void *ptr = malloc(n);
-    data->alloc_total++;
-    if (ptr == nullptr) {
-        data->alloc_failed++;
-    } else {
-        data->tracked.insert(ptr);
-    }
-    return ptr;
-}
-
-void *cx_realloc_testing(void *d, void *mem, size_t n) {
-    auto data = reinterpret_cast<CxTestingAllocator *>(d);
-    void *ptr = realloc(mem, n);
-    if (ptr == mem) {
-        return ptr;
-    } else {
-        data->alloc_total++;
-        if (ptr == nullptr) {
-            data->alloc_failed++;
-        } else {
-            data->free_total++;
-            if (data->tracked.erase(mem) == 0) {
-                data->free_failed++;
-            }
-            data->tracked.insert(ptr);
-        }
-        return ptr;
-    }
-}
-
-void *cx_calloc_testing(void *d, size_t nelem, size_t n) {
-    auto data = reinterpret_cast<CxTestingAllocator *>(d);
-    void *ptr = calloc(nelem, n);
-    data->alloc_total++;
-    if (ptr == nullptr) {
-        data->alloc_failed++;
-    } else {
-        data->tracked.insert(ptr);
-    }
-    return ptr;
-}
-
-void cx_free_testing(void *d, void *mem) {
-    auto data = reinterpret_cast<CxTestingAllocator *>(d);
-    data->free_total++;
-    if (data->tracked.erase(mem) == 0) {
-        data->free_failed++;
-        // do not even attempt to free mem, because it is likely to segfault
-    } else {
-        free(mem);
-    }
-}
-
-cx_allocator_class cx_testing_allocator_class = {
-        cx_malloc_testing,
-        cx_realloc_testing,
-        cx_calloc_testing,
-        cx_free_testing
-};
-
-CxTestingAllocator::CxTestingAllocator() : CxAllocator() {
-    cl = &cx_testing_allocator_class;
-    data = this;
-}
-
-bool CxTestingAllocator::used() const {
-    return alloc_total > 0;
-}
-
-bool CxTestingAllocator::verify() const {
-    return tracked.empty() && alloc_failed == 0 && free_failed == 0 && alloc_total == free_total;
-}
-
-// SELF-TEST
-
-#include <gtest/gtest.h>
-
-TEST(TestingAllocator, ExpectFree) {
-    CxTestingAllocator allocator;
-
-    ASSERT_TRUE(allocator.verify());
-    EXPECT_FALSE(allocator.used());
-    auto ptr = cxMalloc(&allocator, 16);
-    EXPECT_TRUE(allocator.used());
-    ASSERT_NE(ptr, nullptr);
-    EXPECT_FALSE(allocator.verify());
-
-    cxFree(&allocator, ptr);
-    EXPECT_TRUE(allocator.verify());
-}
-
-TEST(TestingAllocator, DetectDoubleFree) {
-    CxTestingAllocator allocator;
-
-    ASSERT_TRUE(allocator.verify());
-    auto ptr = cxMalloc(&allocator, 16);
-    ASSERT_NE(ptr, nullptr);
-
-    cxFree(&allocator, ptr);
-    EXPECT_TRUE(allocator.verify());
-    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
-    EXPECT_FALSE(allocator.verify());
-}
-
-TEST(TestingAllocator, FreeUntracked) {
-    CxTestingAllocator allocator;
-
-    auto ptr = malloc(16);
-    ASSERT_TRUE(allocator.verify());
-    ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
-    EXPECT_FALSE(allocator.verify());
-    ASSERT_NO_FATAL_FAILURE(free(ptr));
-}
-
-TEST(TestingAllocator, FullLifecycleWithRealloc) {
-    CxTestingAllocator allocator;
-    ASSERT_TRUE(allocator.verify());
-    auto ptr = cxMalloc(&allocator, 16);
-    ASSERT_NE(ptr, nullptr);
-    EXPECT_EQ(allocator.tracked.size(), 1);
-    ptr = cxRealloc(&allocator, ptr, 256);
-    ASSERT_NE(ptr, nullptr);
-    EXPECT_EQ(allocator.tracked.size(), 1);
-    cxFree(&allocator, ptr);
-    EXPECT_TRUE(allocator.verify());
-}
-
-TEST(TestingAllocator, CallocInitializes) {
-    CxTestingAllocator allocator;
-    const char zeros[16] = {0};
-    auto ptr = cxCalloc(&allocator, 16, 1);
-    EXPECT_EQ(memcmp(ptr, zeros, 16), 0);
-    cxFree(&allocator, ptr);
-    EXPECT_TRUE(allocator.verify());
-}
--- a/tests/util_allocator.h	Wed Dec 27 14:54:04 2023 +0100
+++ b/tests/util_allocator.h	Wed Dec 27 16:04:38 2023 +0100
@@ -26,56 +26,77 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef UCX_UTIL_ALLOCATOR_H
-#define UCX_UTIL_ALLOCATOR_H
+#ifndef UCX_TEST_UTIL_ALLOCATOR_H
+#define UCX_TEST_UTIL_ALLOCATOR_H
 
 #include "cx/allocator.h"
 
-#include <set>
+#ifdef __cplusplus
+#extern "C" {
+#endif
 
-struct CxTestingAllocator : public CxAllocator {
+typedef struct CxTestingAllocator {
+    CxAllocator base;
     /**
      * Total number of all allocations (malloc, calloc, realloc).
      * A realloc() does only count when the memory has to be moved.
      */
-    unsigned alloc_total = 0;
+    unsigned alloc_total;
     /**
      * Number of failed allocations (malloc, calloc, realloc).
      */
-    unsigned alloc_failed = 0;
+    unsigned alloc_failed;
     /**
      * Total number of freed pointers.
      * A reallocation also counts as a free when the memory has to be moved.
      */
-    unsigned free_total = 0;
+    unsigned free_total;
     /**
      * Number of failed free invocations.
      * A free() is considered failed, if it has not been performed on tracked memory.
      */
-    unsigned free_failed = 0;
+    unsigned free_failed;
+    /**
+     * The number of currently tracked memory blocks.
+     */
+    size_t tracked_count;
+    /**
+     * The capaciyty of the \c tracked array.
+     */
+    size_t tracked_capacity;
     /**
      * The set of tracked memory blocks.
      */
-    std::set<void *> tracked;
+    void **tracked;
+} CxTestingAllocator;
+
 
-    /**
-     * Constructs a new testing allocator.
-     */
-    CxTestingAllocator();
+/**
+ * Initializes a new testing allocator.
+ */
+void cx_testing_allocator_init(CxTestingAllocator *alloc);
+
+/**
+ * Destroys a testing allocator.
+ */
+void cx_testing_allocator_destroy(CxTestingAllocator *alloc);
 
-    /**
-     * Verifies that this allocator has been used.
-     *
-     * @return true if any allocation was attempted using this allocator
-     */
-    [[nodiscard]] bool used() const;
+/**
+ * Verifies that this allocator has been used.
+ *
+ * @return true if any allocation was attempted using this allocator
+ */
+bool cx_testing_allocator_used(CxTestingAllocator const *alloc);
 
-    /**
-     * Verifies that all allocated memory blocks are freed and no free occurred twice.
-     *
-     * @return true iff all tracked allocations / deallocations were valid
-     */
-    [[nodiscard]] bool verify() const;
-};
+/**
+ * Verifies that all allocated memory blocks are freed and no free occurred twice.
+ *
+ * @return true iff all tracked allocations / deallocations were valid
+ */
+bool cx_testing_allocator_verify(CxTestingAllocator const *alloc);
 
-#endif // UCX_UTIL_ALLOCATOR_H
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // UCX_TEST_UTIL_ALLOCATOR_H

mercurial