diff options
-rw-r--r-- | test/cpp/test_path_std.cpp | 7 | ||||
-rw-r--r-- | test/ensure.h | 21 | ||||
-rw-r--r-- | test/meson.build | 132 | ||||
-rw-r--r-- | test/test_allocator.c | 21 | ||||
-rw-r--r-- | test/test_btree.c | 427 | ||||
-rw-r--r-- | test/test_data.h | 9 | ||||
-rw-r--r-- | test/test_filesystem.c | 25 | ||||
-rw-r--r-- | test/test_hash.c | 177 | ||||
-rw-r--r-- | test/test_ring.c | 6 | ||||
-rw-r--r-- | test/test_tree.c | 159 |
10 files changed, 460 insertions, 524 deletions
diff --git a/test/cpp/test_path_std.cpp b/test/cpp/test_path_std.cpp index db38cfa..cabf3da 100644 --- a/test/cpp/test_path_std.cpp +++ b/test/cpp/test_path_std.cpp @@ -501,11 +501,6 @@ run() int main() { - try { - run(); - } catch (...) { - return 1; - } - + run(); return 0; } diff --git a/test/ensure.h b/test/ensure.h new file mode 100644 index 0000000..b906a1d --- /dev/null +++ b/test/ensure.h @@ -0,0 +1,21 @@ +// Copyright 2023 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#ifndef ZIX_TEST_ENSURE_H +#define ZIX_TEST_ENSURE_H + +#define ENSURE(ctx, condition, fmt) \ + do { \ + if (!(condition)) { \ + return test_fail(ctx, fmt); \ + } \ + } while (0) + +#define ENSUREV(ctx, condition, fmt, ...) \ + do { \ + if (!(condition)) { \ + return test_fail(ctx, fmt, __VA_ARGS__); \ + } \ + } while (0) + +#endif // ZIX_TEST_ENSURE_H diff --git a/test/meson.build b/test/meson.build index 72d723b..bd752a3 100644 --- a/test/meson.build +++ b/test/meson.build @@ -38,75 +38,101 @@ endif common_test_sources = files('failing_allocator.c') # Single-threaded tests that should run everywhere -sequential_tests = [ - 'allocator', - 'btree', - 'digest', - 'hash', - 'path', - 'status', - 'tree', -] +sequential_tests = { + 'allocator': {'': []}, + 'btree': { + '': [], + '_small': ['4'], + }, + 'filesystem': {'': files('../README.md')}, + 'digest': {'': []}, + 'hash': {'': []}, + 'path': {'': []}, + 'status': {'': []}, + 'tree': { + '': [], + '_seed': ['8', '314159'], + '_small': ['4'], + }, +} # Multi-threaded tests that require thread support -threaded_tests = [ - 'ring', - 'sem', - 'thread', -] +threaded_tests = { + 'ring': { + '': [], + 'small': ['4', '1024'], + }, + 'sem': { + '': [], + 'one': ['1'], + }, + 'thread': {'': []}, +} -foreach test : sequential_tests +# Bad command-line argument (meta-)tests +bad_tests = { + 'btree': { + '_extra': ['4', '1337'], + }, + 'ring': { + '_extra': ['4', '1024', '1337'], + }, + 'sem': { + '_extra': ['4', '1337'], + }, +} + +# Test single-threaded +test_executables = {} +foreach test, cases : sequential_tests sources = common_test_sources + files('test_@0@.c'.format(test)) + exe = executable( + 'test_@0@'.format(test), + sources, + c_args: c_suppressions + program_c_args + test_suppressions, + dependencies: [zix_dep], + include_directories: include_dirs, + link_args: program_link_args, + ) - test( - test, - executable( + test_executables += { test: exe } + foreach suffix, args : cases + test(test + suffix, exe, args: args, suite: 'unit', timeout: 120) + endforeach +endforeach + +# Test multi-threaded +if thread_dep.found() + foreach test, cases : threaded_tests + sources = common_test_sources + files('test_@0@.c'.format(test)) + exe = executable( 'test_@0@'.format(test), sources, c_args: c_suppressions + program_c_args + test_suppressions, - dependencies: [zix_dep], + dependencies: [zix_dep, thread_dep], include_directories: include_dirs, link_args: program_link_args, - ), - suite: 'unit', - timeout: 120, - ) -endforeach - -test( - 'filesystem', - executable( - 'test_filesystem', - files('test_filesystem.c'), - c_args: c_suppressions + program_c_args, - dependencies: [zix_dep], - include_directories: include_dirs, - link_args: program_link_args, - ), - args: files('../README.md'), - suite: 'unit', - timeout: 120, -) + ) -if thread_dep.found() - foreach test : threaded_tests - sources = common_test_sources + files('test_@0@.c'.format(test)) + test_executables += { test: exe } + foreach suffix, args : cases + test(test + suffix, exe, args: args, suite: 'unit', timeout: 120) + endforeach + endforeach +endif +# Test bad cases +foreach test, cases : bad_tests + foreach suffix, args : cases test( - test, - executable( - 'test_@0@'.format(test), - sources, - c_args: c_suppressions + program_c_args + test_suppressions, - dependencies: [zix_dep, thread_dep], - include_directories: include_dirs, - link_args: program_link_args, - ), + test + suffix, + test_executables[test], + args: args, + should_fail: true, suite: 'unit', - timeout: 120, ) endforeach -endif +endforeach # Test that headers have no warnings (ignoring the usual suppressions) if cc.get_id() != 'emscripten' diff --git a/test/test_allocator.c b/test/test_allocator.c index 3474533..9ecbfa0 100644 --- a/test/test_allocator.c +++ b/test/test_allocator.c @@ -1,12 +1,15 @@ -// Copyright 2014-2021 David Robillard <d@drobilla.net> +// Copyright 2014-2023 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #undef NDEBUG +#include "failing_allocator.h" + #include "zix/allocator.h" #include "zix/bump_allocator.h" #include <assert.h> +#include <stddef.h> #include <stdint.h> static void @@ -108,17 +111,33 @@ test_bump_allocator(void) assert((uintptr_t)aligned % 128 == 0U); assert(!zix_aligned_alloc(&allocator.base, 8, 896)); + assert(zix_aligned_alloc(&allocator.base, 8, 8)); zix_aligned_free(&allocator.base, aligned); zix_free(&allocator.base, reclaimed); // Correct, but a noop zix_free(&allocator.base, malloced); // Correct, but a noop } +static void +test_failing_allocator(void) +{ + ZixFailingAllocator allocator = zix_failing_allocator(); + allocator.n_remaining = 0; + + assert(!zix_malloc(&allocator.base, 16U)); + assert(!zix_calloc(&allocator.base, 16U, 1U)); + assert(!zix_realloc(&allocator.base, NULL, 32U)); + zix_free(&allocator.base, NULL); + assert(!zix_aligned_alloc(&allocator.base, 8U, 16U)); + zix_aligned_free(&allocator.base, NULL); +} + int main(void) { test_allocator(); test_bump_allocator(); + test_failing_allocator(); return 0; } diff --git a/test/test_btree.c b/test/test_btree.c index 7392ff8..e918799 100644 --- a/test/test_btree.c +++ b/test/test_btree.c @@ -1,10 +1,11 @@ -// Copyright 2011-2021 David Robillard <d@drobilla.net> +// Copyright 2011-2023 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #undef NDEBUG #include "zix/btree.h" +#include "ensure.h" #include "failing_allocator.h" #include "test_args.h" #include "test_data.h" @@ -16,12 +17,9 @@ #include <assert.h> #include <inttypes.h> #include <stdarg.h> -#include <stdbool.h> #include <stdio.h> #include <stdlib.h> -static bool expect_failure = false; - ZIX_PURE_FUNC static int int_cmp(const void* a, const void* b, const void* ZIX_UNUSED(user_data)) @@ -69,23 +67,13 @@ wildcard_cmp(const void* a, const void* b, const void* user_data) const uintptr_t ia = (uintptr_t)a; const uintptr_t ib = (uintptr_t)b; - if (ia == 0) { - if (ib >= wildcard_cut(test_num, n_elems)) { - return 0; // Wildcard match - } - - return 1; // Wildcard a > b - } - - if (ib == 0) { - if (ia >= wildcard_cut(test_num, n_elems)) { - return 0; // Wildcard match - } - - return -1; // Wildcard b > a - } - - return int_cmp(a, b, user_data); + return (ia == 0) + ? ((ib >= wildcard_cut(test_num, n_elems)) ? 0 // Wildcard match + : 1) // Wildcard a > b + : (ib == 0) + ? ((ia >= wildcard_cut(test_num, n_elems)) ? 0 // Wildcard match + : -1) // Wildcard b > a + : int_cmp(a, b, user_data); } ZIX_LOG_FUNC(2, 3) @@ -93,9 +81,6 @@ static int test_fail(ZixBTree* t, const char* fmt, ...) { zix_btree_free(t, NULL, NULL); - if (expect_failure) { - return EXIT_SUCCESS; - } va_list args; // NOLINT(cppcoreguidelines-init-variables) va_start(args, fmt); @@ -106,24 +91,18 @@ test_fail(ZixBTree* t, const char* fmt, ...) } static const size_t n_clear_insertions = 1024U; +static size_t n_destroy_calls = 0U; static void destroy(void* const ptr, const void* const user_data) { (void)user_data; + ++n_destroy_calls; assert(ptr); assert((uintptr_t)ptr <= n_clear_insertions); } static void -no_destroy(void* const ptr, const void* const user_data) -{ - (void)ptr; - (void)user_data; - assert(!ptr); -} - -static void test_clear(void) { ZixBTree* t = zix_btree_new(NULL, int_cmp, NULL); @@ -132,10 +111,17 @@ test_clear(void) assert(!zix_btree_insert(t, (void*)(r + 1U))); } + // Clear and check that destroy is called once for each element + assert(n_destroy_calls == 0U); + zix_btree_clear(t, destroy, &n_destroy_calls); + assert(zix_btree_size(t) == 0U); + assert(n_destroy_calls == n_clear_insertions); + + // Clear the now-empty tree and check that destroy isn't called again zix_btree_clear(t, destroy, NULL); - assert(zix_btree_size(t) == 0); + assert(n_destroy_calls == n_clear_insertions); - zix_btree_free(t, no_destroy, NULL); + zix_btree_free(t, destroy, NULL); } static void @@ -257,103 +243,91 @@ stress(ZixAllocator* const allocator, const unsigned test_num, const size_t n_elems) { - if (n_elems == 0) { - return 0; - } + assert(n_elems > 0U); uintptr_t r = 0; ZixBTree* t = zix_btree_new(allocator, int_cmp, NULL); ZixStatus st = ZIX_STATUS_SUCCESS; - if (!t) { - return test_fail(t, "Failed to allocate tree\n"); - } + ENSURE(t, t, "Failed to allocate tree\n"); // Ensure begin iterator is end on empty tree ZixBTreeIter ti = zix_btree_begin(t); ZixBTreeIter end = zix_btree_end(t); - if (!zix_btree_iter_is_end(ti)) { - return test_fail(t, "Begin iterator on empty tree is not end\n"); - } + ENSURE( + t, zix_btree_iter_is_end(ti), "Begin iterator on empty tree is not end\n"); - if (!zix_btree_iter_equals(ti, end)) { - return test_fail(t, "Begin and end of empty tree are not equal\n"); - } + ENSURE(t, + zix_btree_iter_equals(ti, end), + "Begin and end of empty tree are not equal\n"); // Insert n_elems elements for (size_t i = 0; i < n_elems; ++i) { - r = ith_elem(test_num, n_elems, i); - if (!zix_btree_find(t, (void*)r, &ti)) { - return test_fail(t, "%" PRIuPTR " already in tree\n", (uintptr_t)r); - } - - if ((st = zix_btree_insert(t, (void*)r))) { - return test_fail( - t, "Insert %" PRIuPTR " failed (%s)\n", (uintptr_t)r, zix_strerror(st)); - } + r = ith_elem(test_num, n_elems, i); + st = zix_btree_insert(t, (void*)r); + ENSUREV(t, !st, "Insert %" PRIuPTR " failed (%s)\n", r, zix_strerror(st)); } // Ensure tree size is correct - if (zix_btree_size(t) != n_elems) { - return test_fail(t, - "Tree size %" PRIuPTR " != %" PRIuPTR "\n", - zix_btree_size(t), - n_elems); - } + ENSUREV(t, + zix_btree_size(t) == n_elems, + "Tree size %" PRIuPTR " != %" PRIuPTR "\n", + zix_btree_size(t), + n_elems); // Ensure begin no longer equals end ti = zix_btree_begin(t); end = zix_btree_end(t); - if (zix_btree_iter_equals(ti, end)) { - return test_fail(t, "Begin and end of non-empty tree are equal\n"); - } + ENSURE(t, + !zix_btree_iter_equals(ti, end), + "Begin and end of non-empty tree are equal\n"); // Search for all elements for (size_t i = 0; i < n_elems; ++i) { r = ith_elem(test_num, n_elems, i); - if (zix_btree_find(t, (void*)r, &ti)) { - return test_fail( - t, "Find %" PRIuPTR " @ %" PRIuPTR " failed\n", (uintptr_t)r, i); - } + ENSUREV(t, + !zix_btree_find(t, (void*)r, &ti), + "Find %" PRIuPTR " @ %" PRIuPTR " failed\n", + r, + i); - if ((uintptr_t)zix_btree_get(ti) != r) { - return test_fail(t, - "Search data corrupt (%" PRIuPTR " != %" PRIuPTR ")\n", - (uintptr_t)zix_btree_get(ti), - r); - } + ENSUREV(t, + (uintptr_t)zix_btree_get(ti) == r, + "Search data corrupt (%" PRIuPTR " != %" PRIuPTR ")\n", + (uintptr_t)zix_btree_get(ti), + r); } // Find the lower bound of all elements and ensure it's exact for (size_t i = 0; i < n_elems; ++i) { r = ith_elem(test_num, n_elems, i); - if (zix_btree_lower_bound(t, int_cmp, NULL, (void*)r, &ti)) { - return test_fail( - t, "Lower bound %" PRIuPTR " @ %" PRIuPTR " failed\n", (uintptr_t)r, i); - } + ENSUREV(t, + !zix_btree_lower_bound(t, int_cmp, NULL, (void*)r, &ti), + "Lower bound %" PRIuPTR " @ %" PRIuPTR " failed\n", + r, + i); - if (zix_btree_iter_is_end(ti)) { - return test_fail(t, - "Lower bound %" PRIuPTR " @ %" PRIuPTR " hit end\n", - (uintptr_t)r, - i); - } + ENSUREV(t, + !zix_btree_iter_is_end(ti), + "Lower bound %" PRIuPTR " @ %" PRIuPTR " hit end\n", + r, + i); - if ((uintptr_t)zix_btree_get(ti) != r) { - return test_fail(t, - "Lower bound corrupt (%" PRIuPTR " != %" PRIuPTR "\n", - (uintptr_t)zix_btree_get(ti), - r); - } + ENSUREV(t, + (uintptr_t)zix_btree_get(ti) == r, + "Lower bound corrupt (%" PRIuPTR " != %" PRIuPTR "\n", + (uintptr_t)zix_btree_get(ti), + r); } // Search for elements that don't exist for (size_t i = 0; i < n_elems; ++i) { r = ith_elem(test_num, n_elems * 3, n_elems + i); - if (!zix_btree_find(t, (void*)r, &ti)) { - return test_fail(t, "Unexpectedly found %" PRIuPTR "\n", (uintptr_t)r); - } + ENSUREV(t, + zix_btree_find(t, (void*)r, &ti), + "Unexpectedly found %" PRIuPTR "\n", + r); } // Iterate over all elements @@ -362,143 +336,132 @@ stress(ZixAllocator* const allocator, for (ti = zix_btree_begin(t); !zix_btree_iter_is_end(ti); zix_btree_iter_increment(&ti), ++i) { const uintptr_t iter_data = (uintptr_t)zix_btree_get(ti); - if (iter_data < last) { - return test_fail(t, - "Iter @ %" PRIuPTR " corrupt (%" PRIuPTR " < %" PRIuPTR - ")\n", - i, - iter_data, - last); - } + ENSUREV(t, + iter_data >= last, + "Iter @ %" PRIuPTR " corrupt (%" PRIuPTR " < %" PRIuPTR ")\n", + i, + iter_data, + last); + last = iter_data; } - if (i != n_elems) { - return test_fail(t, - "Iteration stopped at %" PRIuPTR "/%" PRIuPTR - " elements\n", - i, - n_elems); - } + ENSUREV(t, + i == n_elems, + "Iteration stopped at %" PRIuPTR "/%" PRIuPTR " elements\n", + i, + n_elems); // Insert n_elems elements again, ensuring duplicates fail for (i = 0; i < n_elems; ++i) { r = ith_elem(test_num, n_elems, i); - if (!zix_btree_insert(t, (void*)r)) { - return test_fail(t, "Duplicate insert succeeded\n"); - } + ENSURE(t, zix_btree_insert(t, (void*)r), "Duplicate insert succeeded\n"); } // Search for the middle element then iterate from there r = ith_elem(test_num, n_elems, n_elems / 2); - if (zix_btree_find(t, (void*)r, &ti)) { - return test_fail(t, "Find %" PRIuPTR " failed\n", (uintptr_t)r); - } + ENSUREV( + t, !zix_btree_find(t, (void*)r, &ti), "Find %" PRIuPTR " failed\n", r); last = (uintptr_t)zix_btree_get(ti); zix_btree_iter_increment(&ti); for (i = 1; !zix_btree_iter_is_end(ti); zix_btree_iter_increment(&ti), ++i) { - if ((uintptr_t)zix_btree_get(ti) == last) { - return test_fail( - t, "Duplicate element @ %" PRIuPTR " %" PRIuPTR "\n", i, last); - } + ENSUREV(t, + (uintptr_t)zix_btree_get(ti) != last, + "Duplicate element @ %" PRIuPTR " %" PRIuPTR "\n", + i, + last); last = (uintptr_t)zix_btree_get(ti); } - // Delete all elements + // Remove all elements ZixBTreeIter next = zix_btree_end_iter; for (size_t e = 0; e < n_elems; e++) { r = ith_elem(test_num, n_elems, e); uintptr_t removed = 0; - if (zix_btree_remove(t, (void*)r, (void**)&removed, &next)) { - return test_fail(t, "Error removing item %" PRIuPTR "\n", (uintptr_t)r); - } + ENSUREV(t, + !zix_btree_remove(t, (void*)r, (void**)&removed, &next), + "Error removing item %" PRIuPTR "\n", + r); - if (removed != r) { - return test_fail(t, - "Removed wrong item %" PRIuPTR " != %" PRIuPTR "\n", - removed, - (uintptr_t)r); - } + ENSUREV(t, + removed == r, + "Removed wrong item %" PRIuPTR " != %" PRIuPTR "\n", + removed, + r); if (test_num == 0) { const uintptr_t next_value = ith_elem(test_num, n_elems, e + 1); - if (!((zix_btree_iter_is_end(next) && e == n_elems - 1) || - (uintptr_t)zix_btree_get(next) == next_value)) { - return test_fail(t, - "Delete all next iterator %" PRIuPTR " != %" PRIuPTR - "\n", - (uintptr_t)zix_btree_get(next), - next_value); - } + ENSUREV(t, + (zix_btree_iter_is_end(next) && e == n_elems - 1) || + ((uintptr_t)zix_btree_get(next) == next_value), + "Remove-all next value %" PRIuPTR " != %" PRIuPTR "\n", + (uintptr_t)zix_btree_get(next), + next_value); } } // Ensure the tree is empty - if (zix_btree_size(t) != 0) { - return test_fail(t, "Tree size %" PRIuPTR " != 0\n", zix_btree_size(t)); - } + ENSUREV(t, + zix_btree_size(t) == 0U, + "Tree size %" PRIuPTR " != 0\n", + zix_btree_size(t)); // Insert n_elems elements again (to test non-empty destruction) for (size_t e = 0; e < n_elems; ++e) { r = ith_elem(test_num, n_elems, e); - if (zix_btree_insert(t, (void*)r)) { - return test_fail(t, "Post-deletion insert failed\n"); - } + ENSURE(t, !zix_btree_insert(t, (void*)r), "Post-deletion insert failed\n"); } - // Delete elements that don't exist + // Try to remove elements that don't exist for (size_t e = 0; e < n_elems; e++) { r = ith_elem(test_num, n_elems * 3, n_elems + e); uintptr_t removed = 0; - if (!zix_btree_remove(t, (void*)r, (void**)&removed, &next)) { - return test_fail( - t, "Non-existant deletion of %" PRIuPTR " succeeded\n", (uintptr_t)r); - } + ENSUREV(t, + zix_btree_remove(t, (void*)r, (void**)&removed, &next), + "Removal of non-existant %" PRIuPTR " succeeded\n", + r); } // Ensure tree size is still correct - if (zix_btree_size(t) != n_elems) { - return test_fail(t, - "Tree size %" PRIuPTR " != %" PRIuPTR "\n", - zix_btree_size(t), - n_elems); - } + ENSUREV(t, + zix_btree_size(t) == n_elems, + "Tree size %" PRIuPTR " != %" PRIuPTR "\n", + zix_btree_size(t), + n_elems); // Delete some elements towards the end for (size_t e = 0; e < n_elems / 4; e++) { r = ith_elem(test_num, n_elems, n_elems - (n_elems / 4) + e); uintptr_t removed = 0; - if (zix_btree_remove(t, (void*)r, (void**)&removed, &next)) { - return test_fail(t, "Deletion of %" PRIuPTR " failed\n", (uintptr_t)r); - } + ENSUREV(t, + !zix_btree_remove(t, (void*)r, (void**)&removed, &next), + "Deletion of %" PRIuPTR " failed\n", + r); - if (removed != r) { - return test_fail(t, - "Removed wrong item %" PRIuPTR " != %" PRIuPTR "\n", - removed, - (uintptr_t)r); - } + ENSUREV(t, + removed == r, + "Removed wrong item %" PRIuPTR " != %" PRIuPTR "\n", + removed, + r); if (test_num == 0) { const uintptr_t next_value = ith_elem(test_num, n_elems, e + 1); - if (!zix_btree_iter_is_end(next) && - (uintptr_t)zix_btree_get(next) == next_value) { - return test_fail(t, - "Next iterator %" PRIuPTR " != %" PRIuPTR "\n", - (uintptr_t)zix_btree_get(next), - next_value); - } + ENSUREV(t, + zix_btree_iter_is_end(next) || + (uintptr_t)zix_btree_get(next) != next_value, + "Next iterator %" PRIuPTR " == %" PRIuPTR "\n", + (uintptr_t)zix_btree_get(next), + next_value); } } // Check tree size - if (zix_btree_size(t) != n_elems - (n_elems / 4)) { - return test_fail(t, - "Tree size %" PRIuPTR " != %" PRIuPTR "\n", - zix_btree_size(t), - n_elems); - } + ENSUREV(t, + zix_btree_size(t) == n_elems - (n_elems / 4), + "Tree size %" PRIuPTR " != %" PRIuPTR "\n", + zix_btree_size(t), + n_elems); // Delete some elements in a random order for (size_t e = 0; e < zix_btree_size(t) / 2; e++) { @@ -506,9 +469,10 @@ stress(ZixAllocator* const allocator, uintptr_t removed = 0; ZixStatus rst = zix_btree_remove(t, (void*)r, (void**)&removed, &next); - if (rst != ZIX_STATUS_SUCCESS && rst != ZIX_STATUS_NOT_FOUND) { - return test_fail(t, "Error deleting %" PRIuPTR "\n", (uintptr_t)r); - } + ENSUREV(t, + rst == ZIX_STATUS_SUCCESS || rst == ZIX_STATUS_NOT_FOUND, + "Error deleting %" PRIuPTR "\n", + r); } // Delete all remaining elements via next iterator @@ -517,25 +481,22 @@ stress(ZixAllocator* const allocator, while (!zix_btree_iter_is_end(next)) { const uintptr_t value = (uintptr_t)zix_btree_get(next); uintptr_t removed = 0; - if (zix_btree_remove(t, zix_btree_get(next), (void**)&removed, &next)) { - return test_fail( - t, "Error removing next item %" PRIuPTR "\n", (uintptr_t)r); - } - - if (removed != value) { - return test_fail(t, - "Removed wrong next item %" PRIuPTR " != %" PRIuPTR "\n", - removed, - (uintptr_t)value); - } - - if (removed < last_value) { - return test_fail(t, - "Removed unordered next item %" PRIuPTR " < %" PRIuPTR - "\n", - removed, - (uintptr_t)value); - } + ENSUREV(t, + !zix_btree_remove(t, zix_btree_get(next), (void**)&removed, &next), + "Error removing next item %" PRIuPTR "\n", + r); + + ENSUREV(t, + removed == value, + "Removed wrong next item %" PRIuPTR " != %" PRIuPTR "\n", + removed, + (uintptr_t)value); + + ENSUREV(t, + removed >= last_value, + "Removed unordered next item %" PRIuPTR " < %" PRIuPTR "\n", + removed, + (uintptr_t)value); last_value = removed; } @@ -546,51 +507,47 @@ stress(ZixAllocator* const allocator, // Test lower_bound with wildcard comparator TestContext ctx = {test_num, n_elems}; - if (!(t = zix_btree_new(NULL, wildcard_cmp, &ctx))) { - return test_fail(t, "Failed to allocate tree\n"); - } + t = zix_btree_new(NULL, wildcard_cmp, &ctx); + ENSURE(t, t, "Failed to allocate tree\n"); // Insert n_elems elements for (i = 0; i < n_elems; ++i) { - r = ith_elem(test_num, n_elems, i); - if ((st = zix_btree_insert(t, (void*)r))) { - return test_fail( - t, "Insert %" PRIuPTR " failed (%s)\n", (uintptr_t)r, zix_strerror(st)); - } + r = ith_elem(test_num, n_elems, i); + st = zix_btree_insert(t, (void*)r); + ENSUREV(t, !st, "Insert %" PRIuPTR " failed (%s)\n", r, zix_strerror(st)); } // Find lower bound of wildcard const uintptr_t wildcard = 0; - if (zix_btree_lower_bound(t, wildcard_cmp, &ctx, (void*)wildcard, &ti)) { - return test_fail(t, "Lower bound failed\n"); - } + ENSURE(t, + !zix_btree_lower_bound(t, wildcard_cmp, &ctx, (void*)wildcard, &ti), + "Wildcard lower bound failed\n"); - if (zix_btree_iter_is_end(ti)) { - return test_fail(t, "Lower bound reached end\n"); - } + ENSURE(t, !zix_btree_iter_is_end(ti), "Lower bound reached end\n"); // Check value const uintptr_t iter_data = (uintptr_t)zix_btree_get(ti); const uintptr_t cut = wildcard_cut(test_num, n_elems); - if (iter_data != cut) { - return test_fail( - t, "Lower bound %" PRIuPTR " != %" PRIuPTR "\n", iter_data, cut); - } - - if (wildcard_cmp((void*)wildcard, (void*)iter_data, &ctx)) { - return test_fail( - t, "Wildcard lower bound %" PRIuPTR " != %" PRIuPTR "\n", iter_data, cut); - } + ENSUREV(t, + iter_data == cut, + "Lower bound %" PRIuPTR " != %" PRIuPTR "\n", + iter_data, + cut); + + ENSUREV(t, + !wildcard_cmp((void*)wildcard, (void*)iter_data, &ctx), + "Wildcard lower bound %" PRIuPTR " != %" PRIuPTR "\n", + iter_data, + cut); // Find lower bound of value past end const uintptr_t max = (uintptr_t)-1; - if (zix_btree_lower_bound(t, wildcard_cmp, &ctx, (void*)max, &ti)) { - return test_fail(t, "Lower bound failed\n"); - } + ENSURE(t, + !zix_btree_lower_bound(t, wildcard_cmp, &ctx, (void*)max, &ti), + "End lower bound failed\n"); - if (!zix_btree_iter_is_end(ti)) { - return test_fail(t, "Lower bound of maximum value is not end\n"); - } + ENSURE( + t, zix_btree_iter_is_end(ti), "Lower bound of maximum value is not end\n"); zix_btree_free(t, NULL, NULL); @@ -628,19 +585,19 @@ main(int argc, char** argv) test_remove_cases(); test_failed_alloc(); - const unsigned n_tests = 2U; - const size_t n_elems = - (argc > 1) ? zix_test_size_arg(argv[1], 4U, 1U << 20U) : (1U << 16U); + const unsigned n_tests = 3U; + const char* size_arg = (argc > 1) ? argv[1] : "65536"; + const size_t n_elems = zix_test_size_arg(size_arg, 4U, 1U << 20U); printf("Running %u tests with %zu elements", n_tests, n_elems); - for (unsigned i = 0; i < n_tests; ++i) { + + int st = 0; + for (unsigned i = 0; !st && i < n_tests; ++i) { printf("."); fflush(stdout); - if (stress(NULL, i, n_elems)) { - return EXIT_FAILURE; - } + st = stress(NULL, i, n_elems); } - printf("\n"); - return EXIT_SUCCESS; + printf("\n"); + return st; } diff --git a/test/test_data.h b/test/test_data.h index 603a6c2..bc61cfd 100644 --- a/test/test_data.h +++ b/test/test_data.h @@ -1,4 +1,4 @@ -// Copyright 2011-2021 David Robillard <d@drobilla.net> +// Copyright 2011-2023 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #ifndef ZIX_TEST_DATA_H @@ -46,12 +46,11 @@ unique_rand(size_t i) // Largest prime < 2^32 which satisfies (2^32 = 3 mod 4) static const size_t prime = 4294967291U; - if (i >= prime) { - return i; // Values >= prime are mapped to themselves - } const size_t residue = (size_t)(((uint64_t)i * i) % prime); - return (i <= prime / 2) ? residue : prime - residue; + return (i >= prime) ? i // Values >= prime are mapped to themselves + : (i <= prime / 2) ? residue + : prime - residue; } #endif // ZIX_TEST_DATA_H diff --git a/test/test_filesystem.c b/test/test_filesystem.c index 5006676..cc68249 100644 --- a/test/test_filesystem.c +++ b/test/test_filesystem.c @@ -1,4 +1,4 @@ -// Copyright 2020-2022 David Robillard <d@drobilla.net> +// Copyright 2020-2023 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #undef NDEBUG @@ -235,17 +235,16 @@ test_is_directory(void) static int write_to_path(const char* const path, const char* const contents) { - FILE* const f = fopen(path, "w"); - if (!f) { - return -1; - } - - const size_t len = strlen(contents); - fwrite(contents, 1, len, f); + int ret = -1; + FILE* const f = fopen(path, "w"); + if (f) { + const size_t len = strlen(contents); + fwrite(contents, 1, len, f); - const int ret = fflush(f) ? errno : ferror(f) ? EBADF : 0; + ret = fflush(f) ? errno : ferror(f) ? EBADF : fclose(f) ? errno : 0; + } - return fclose(f) ? errno : ret; + return ret; } static void @@ -600,13 +599,12 @@ test_create_symlink(void) // Check that the symlink seems equivalent to the original file assert(!st || st == ZIX_STATUS_NOT_SUPPORTED || st == ZIX_STATUS_BAD_PERMS); + assert(!st || zix_symlink_type(link_path) == ZIX_FILE_TYPE_NONE); if (!st) { assert(zix_symlink_type(link_path) == ZIX_FILE_TYPE_SYMLINK); assert(zix_file_type(link_path) == ZIX_FILE_TYPE_REGULAR); assert(zix_file_equals(NULL, file_path, link_path)); assert(!zix_remove(link_path)); - } else { - assert(zix_symlink_type(link_path) == ZIX_FILE_TYPE_NONE); } assert(!zix_remove(file_path)); @@ -670,12 +668,11 @@ test_create_hard_link(void) // Check that the link is equivalent to the original file assert(!st || st == ZIX_STATUS_NOT_SUPPORTED || st == ZIX_STATUS_MAX_LINKS); + assert(!st || zix_symlink_type(link_path) == ZIX_FILE_TYPE_NONE); if (!st) { assert(zix_file_type(link_path) == ZIX_FILE_TYPE_REGULAR); assert(zix_file_equals(NULL, file_path, link_path)); assert(!zix_remove(link_path)); - } else { - assert(zix_symlink_type(link_path) == ZIX_FILE_TYPE_NONE); } assert(!zix_remove(file_path)); diff --git a/test/test_hash.c b/test/test_hash.c index c3aaaba..b1de72a 100644 --- a/test/test_hash.c +++ b/test/test_hash.c @@ -1,4 +1,4 @@ -// Copyright 2011-2021 David Robillard <d@drobilla.net> +// Copyright 2011-2023 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #undef NDEBUG @@ -6,6 +6,7 @@ #define ZIX_HASH_KEY_TYPE const char #define ZIX_HASH_RECORD_TYPE const char +#include "ensure.h" #include "failing_allocator.h" #include "test_data.h" @@ -24,29 +25,26 @@ #include <stdlib.h> #include <string.h> -static bool expect_failure = false; +typedef struct { + ZixHash* hash; + char* buffer; + char** strings; +} TestState; -ZIX_LOG_FUNC(4, 5) +ZIX_LOG_FUNC(2, 3) static int -test_fail(ZixHash* const hash, - char* const buffer, - char** const strings, - const char* fmt, - ...) +test_fail(TestState* const state, const char* fmt, ...) { - if (!expect_failure) { - va_list args; // NOLINT(cppcoreguidelines-init-variables) - va_start(args, fmt); - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, args); - va_end(args); - } - - zix_hash_free(hash); - free(buffer); - free(strings); - - return expect_failure ? 0 : 1; + va_list args; // NOLINT(cppcoreguidelines-init-variables) + va_start(args, fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, args); + va_end(args); + + zix_hash_free(state->hash); + free(state->buffer); + free(state->strings); + return EXIT_FAILURE; } ZIX_PURE_FUNC static const char* @@ -130,18 +128,17 @@ stress_with(ZixAllocator* const allocator, const ZixHashFunc hash_func, const size_t n_elems) { - ZixHash* hash = zix_hash_new(allocator, identity, hash_func, string_equal); - if (!hash) { - return test_fail(hash, NULL, NULL, "Failed to allocate hash\n"); - } + ZixHash* hash = zix_hash_new(allocator, identity, hash_func, string_equal); + TestState state = {hash, NULL, NULL}; + ENSURE(&state, hash, "Failed to allocate hash\n"); static const size_t string_length = 15; char* const buffer = (char*)calloc(1, n_elems * (string_length + 1)); - char** const strings = (char**)calloc(sizeof(char*), n_elems); - if (!buffer || !strings) { - return test_fail(hash, buffer, strings, "Failed to allocate strings\n"); - } + char** const strings = state.strings = (char**)calloc(sizeof(char*), n_elems); + state.buffer = buffer; + state.strings = strings; + ENSURE(&state, buffer && state.strings, "Failed to allocate strings\n"); uint32_t seed = 1U; for (size_t i = 0U; i < n_elems; ++i) { @@ -158,46 +155,35 @@ stress_with(ZixAllocator* const allocator, // Insert each string for (size_t i = 0; i < n_elems; ++i) { ZixStatus st = zix_hash_insert(hash, strings[i]); - if (st) { - return test_fail( - hash, buffer, strings, "Failed to insert `%s'\n", strings[i]); - } + ENSUREV(&state, !st, "Failed to insert `%s'\n", strings[i]); } // Ensure hash size is correct - if (zix_hash_size(hash) != n_elems) { - return test_fail(hash, - buffer, - strings, - "Hash size %" PRIuPTR " != %" PRIuPTR "\n", - zix_hash_size(hash), - n_elems); - } + ENSUREV(&state, + zix_hash_size(hash) == n_elems, + "Hash size %" PRIuPTR " != %" PRIuPTR "\n", + zix_hash_size(hash), + n_elems); // Attempt to insert each string again for (size_t i = 0; i < n_elems; ++i) { ZixStatus st = zix_hash_insert(hash, strings[i]); - if (st != ZIX_STATUS_EXISTS) { - return test_fail(hash, - buffer, - strings, - "Double inserted `%s' (%s)\n", - strings[i], - zix_strerror(st)); - } + ENSUREV(&state, + st == ZIX_STATUS_EXISTS, + "Double inserted `%s' (%s)\n", + strings[i], + zix_strerror(st)); } // Search for each string for (size_t i = 0; i < n_elems; ++i) { const char* match = (const char*)zix_hash_find_record(hash, strings[i]); - if (!match) { - return test_fail( - hash, buffer, strings, "Failed to find `%s'\n", strings[i]); - } - if (match != strings[i]) { - return test_fail( - hash, buffer, strings, "Bad match for `%s': `%s'\n", strings[i], match); - } + ENSUREV(&state, match, "Failed to find `%s'\n", strings[i]); + ENSUREV(&state, + match == strings[i], + "Bad match for `%s': `%s'\n", + strings[i], + match); } static const char* const not_indexed_string = "__not__indexed__"; @@ -207,10 +193,7 @@ stress_with(ZixAllocator* const allocator, if (not_indexed) { memcpy(not_indexed, not_indexed_string, strlen(not_indexed_string) + 1); const char* match = (const char*)zix_hash_find_record(hash, not_indexed); - if (match) { - return test_fail( - hash, buffer, strings, "Unexpectedly found `%s'\n", not_indexed); - } + ENSUREV(&state, !match, "Unexpectedly found `%s'\n", not_indexed); free(not_indexed); } @@ -221,33 +204,26 @@ stress_with(ZixAllocator* const allocator, // Remove string const char* removed = NULL; ZixStatus st = zix_hash_remove(hash, strings[i], &removed); - if (st) { - return test_fail( - hash, buffer, strings, "Failed to remove `%s'\n", strings[i]); - } + ENSUREV(&state, !st, "Failed to remove `%s'\n", strings[i]); // Ensure the removed value is what we expected - if (removed != strings[i]) { - return test_fail(hash, - buffer, - strings, - "Removed `%s` instead of `%s`\n", - removed, - strings[i]); - } + ENSUREV(&state, + removed == strings[i], + "Removed `%s` instead of `%s`\n", + removed, + strings[i]); // Ensure size is updated - if (zix_hash_size(hash) != initial_size - 1) { - return test_fail( - hash, buffer, strings, "Removing node did not decrease hash size\n"); - } + ENSURE(&state, + zix_hash_size(hash) == initial_size - 1, + "Removing node did not decrease hash size\n"); // Ensure second removal fails st = zix_hash_remove(hash, strings[i], &removed); - if (st != ZIX_STATUS_NOT_FOUND) { - return test_fail( - hash, buffer, strings, "Unexpectedly removed `%s' twice\n", strings[i]); - } + ENSUREV(&state, + st == ZIX_STATUS_NOT_FOUND, + "Unexpectedly removed `%s' twice\n", + strings[i]); // Ensure value can no longer be found assert(zix_hash_find(hash, strings[i]) == zix_hash_end(hash)); @@ -255,20 +231,11 @@ stress_with(ZixAllocator* const allocator, // Check to ensure remaining strings are still present for (size_t j = i + 1; j < n_elems; ++j) { const char* match = (const char*)zix_hash_find_record(hash, strings[j]); - if (!match) { - return test_fail(hash, - buffer, - strings, - "Failed to find `%s' after remove\n", - strings[j]); - } - if (match != strings[j]) { - return test_fail(hash, - buffer, - strings, - "Bad match for `%s' after remove\n", - strings[j]); - } + ENSUREV(&state, match, "Failed to find `%s' after remove\n", strings[j]); + ENSUREV(&state, + match == strings[j], + "Bad match for `%s' after remove\n", + strings[j]); } } @@ -278,10 +245,7 @@ stress_with(ZixAllocator* const allocator, assert(!zix_hash_record_at(hash, plan)); ZixStatus st = zix_hash_insert_at(hash, plan, strings[i]); - if (st) { - return test_fail( - hash, buffer, strings, "Failed to insert `%s'\n", strings[i]); - } + ENSUREV(&state, !st, "Failed to insert `%s'\n", strings[i]); } // Check key == value (and test zix_hash_foreach) @@ -290,15 +254,12 @@ stress_with(ZixAllocator* const allocator, i = zix_hash_next(hash, i)) { const char* const string = (const char*)zix_hash_get(hash, i); assert(string); - if (strlen(string) < 3) { - return test_fail(hash, buffer, strings, "Corrupt value `%s'\n", string); - } + ENSUREV(&state, strlen(string) >= 3, "Corrupt value `%s'\n", string); ++n_checked; } - if (n_checked != n_elems) { - return test_fail(hash, buffer, strings, "Check failed\n"); - } + + ENSURE(&state, n_checked == n_elems, "Check failed\n"); free(strings); free(buffer); @@ -413,9 +374,5 @@ main(void) static const size_t n_elems = 1024U; - if (stress(NULL, n_elems)) { - return 1; - } - - return 0; + return stress(NULL, n_elems); } diff --git a/test/test_ring.c b/test/test_ring.c index fc45ac6..46abe05 100644 --- a/test/test_ring.c +++ b/test/test_ring.c @@ -1,4 +1,4 @@ -// Copyright 2011-2021 David Robillard <d@drobilla.net> +// Copyright 2011-2023 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #undef NDEBUG @@ -182,8 +182,8 @@ test_failed_alloc(void) int main(int argc, char** argv) { - if (argc > 1 && argv[1][0] == '-') { - printf("Usage: %s SIZE N_WRITES\n", argv[0]); + if (argc > 3) { + printf("Usage: %s SIZE [N_WRITES]\n", argv[0]); return 1; } diff --git a/test/test_tree.c b/test/test_tree.c index b51bb29..5f093d3 100644 --- a/test/test_tree.c +++ b/test/test_tree.c @@ -1,8 +1,9 @@ -// Copyright 2011-2020 David Robillard <d@drobilla.net> +// Copyright 2011-2023 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #undef NDEBUG +#include "ensure.h" #include "failing_allocator.h" #include "test_args.h" #include "test_data.h" @@ -45,17 +46,18 @@ ith_elem(unsigned test_num, size_t n_elems, size_t i) } } -ZIX_LOG_FUNC(1, 2) +ZIX_LOG_FUNC(2, 3) static int -test_fail(const char* const fmt, ...) +test_fail(ZixTree* t, const char* fmt, ...) { + zix_tree_free(t); + va_list args; // NOLINT(cppcoreguidelines-init-variables) va_start(args, fmt); - fprintf(stderr, "error: "); vfprintf(stderr, fmt, args); - va_end(args); + return EXIT_FAILURE; } @@ -79,25 +81,17 @@ test_duplicate_insert(void) } static int -check_value(const uintptr_t actual, const uintptr_t expected) +check_tree_size(const size_t actual, const size_t expected) { return (expected == actual) ? 0 - : test_fail("Data corrupt (%" PRIuPTR " != %" PRIuPTR ")\n", + : test_fail(NULL, // FIXME + "Tree size %" PRIuPTR " != %" PRIuPTR "\n", actual, expected); } static int -check_tree_size(const size_t actual, const size_t expected) -{ - return (expected == actual) - ? 0 - : test_fail( - "Tree size %" PRIuPTR " != %" PRIuPTR "\n", actual, expected); -} - -static int insert_elements(ZixTree* const t, const unsigned test_num, const size_t n_elems) { ZixTreeIter* ti = NULL; @@ -105,14 +99,12 @@ insert_elements(ZixTree* const t, const unsigned test_num, const size_t n_elems) for (size_t i = 0; i < n_elems; ++i) { const uintptr_t r = ith_elem(test_num, n_elems, i); - ZixStatus status = zix_tree_insert(t, (void*)r, &ti); - if (status) { - return test_fail("Insert failed\n"); - } + const ZixStatus st = zix_tree_insert(t, (void*)r, &ti); + ENSURE(NULL, !st, "Insert failed\n"); - if (check_value((uintptr_t)zix_tree_get(ti), r)) { - return EXIT_FAILURE; - } + const uintptr_t value = (uintptr_t)zix_tree_get(ti); + ENSUREV( + NULL, value == r, "Insert %" PRIuPTR " != %" PRIuPTR "\n", value, r); } return 0; @@ -125,32 +117,31 @@ stress(ZixAllocator* allocator, unsigned test_num, size_t n_elems) ZixTreeIter* ti = NULL; ZixTree* t = zix_tree_new(allocator, true, int_cmp, NULL, NULL, NULL); - assert(t); - assert(!zix_tree_begin(t)); - assert(!zix_tree_end(t)); - assert(!zix_tree_rbegin(t)); - assert(!zix_tree_rend(t)); + ENSURE(t, t, "Failed to allocate tree\n"); + ENSURE(t, !zix_tree_begin(t), "Empty tree has begin iterator\n"); + ENSURE(t, !zix_tree_end(t), "Empty tree has end iterator\n"); + ENSURE(t, !zix_tree_rbegin(t), "Empty tree has reverse begin iterator\n"); + ENSURE(t, !zix_tree_rend(t), "Empty tree has reverse end iterator\n"); // Insert n_elems elements - if (insert_elements(t, test_num, n_elems)) { - return EXIT_FAILURE; - } + ENSURE(t, + !insert_elements(t, test_num, n_elems), + "Failed to insert initial elements\n"); // Ensure tree size is correct - if (check_tree_size(zix_tree_size(t), n_elems)) { - return EXIT_FAILURE; - } + ENSUREV(t, + zix_tree_size(t) == n_elems, + "Tree size %" PRIuPTR " != %" PRIuPTR "\n", + zix_tree_size(t), + n_elems); // Search for all elements for (size_t i = 0; i < n_elems; ++i) { r = ith_elem(test_num, n_elems, i); - if (zix_tree_find(t, (void*)r, &ti)) { - return test_fail("Find failed\n"); - } + ENSURE(t, !zix_tree_find(t, (void*)r, &ti), "Find failed\n"); - if (check_value((uintptr_t)zix_tree_get(ti), r)) { - return EXIT_FAILURE; - } + const uintptr_t value = (uintptr_t)zix_tree_get(ti); + ENSUREV(t, value == r, "Value %" PRIuPTR " != %" PRIuPTR "\n", value, r); } // Iterate over all elements @@ -159,16 +150,18 @@ stress(ZixAllocator* allocator, unsigned test_num, size_t n_elems) for (ZixTreeIter* iter = zix_tree_begin(t); !zix_tree_iter_is_end(iter); iter = zix_tree_iter_next(iter), ++i) { const uintptr_t iter_data = (uintptr_t)zix_tree_get(iter); - if (iter_data < last) { - return test_fail( - "Iter corrupt (%" PRIuPTR " < %" PRIuPTR ")\n", iter_data, last); - } + ENSUREV(t, + iter_data >= last, + "Iter corrupt (%" PRIuPTR " < %" PRIuPTR ")\n", + iter_data, + last); last = iter_data; } - if (i != n_elems) { - return test_fail( - "Iteration stopped at %" PRIuPTR "/%" PRIuPTR " elements\n", i, n_elems); - } + ENSUREV(t, + i == n_elems, + "Iteration stopped at %" PRIuPTR "/%" PRIuPTR " elements\n", + i, + n_elems); // Iterate over all elements backwards i = 0; @@ -176,10 +169,11 @@ stress(ZixAllocator* allocator, unsigned test_num, size_t n_elems) for (ZixTreeIter* iter = zix_tree_rbegin(t); !zix_tree_iter_is_rend(iter); iter = zix_tree_iter_prev(iter), ++i) { const uintptr_t iter_data = (uintptr_t)zix_tree_get(iter); - if (iter_data > last) { - return test_fail( - "Iter corrupt (%" PRIuPTR " < %" PRIuPTR ")\n", iter_data, last); - } + ENSUREV(t, + iter_data <= last, + "Iter corrupt (%" PRIuPTR " < %" PRIuPTR ")\n", + iter_data, + last); last = iter_data; } @@ -188,23 +182,17 @@ stress(ZixAllocator* allocator, unsigned test_num, size_t n_elems) r = ith_elem(test_num, n_elems, e); ZixTreeIter* item = NULL; - if (zix_tree_find(t, (void*)r, &item) != ZIX_STATUS_SUCCESS) { - return test_fail("Failed to find item to remove\n"); - } - if (zix_tree_remove(t, item)) { - return test_fail("Error removing item\n"); - } + ENSURE(t, + zix_tree_find(t, (void*)r, &item) == ZIX_STATUS_SUCCESS, + "Failed to find item to remove\n"); + ENSURE(t, !zix_tree_remove(t, item), "Error removing item\n"); } // Ensure the tree is empty - if (check_tree_size(zix_tree_size(t), 0)) { - return EXIT_FAILURE; - } + ENSURE(t, zix_tree_size(t) == 0U, "Tree isn't empty\n"); // Insert n_elems elements again (to test non-empty destruction) - if (insert_elements(t, test_num, n_elems)) { - return EXIT_FAILURE; - } + ENSURE(t, !insert_elements(t, test_num, n_elems), "Reinsertion failed\n"); // Ensure tree size is correct const int ret = check_tree_size(zix_tree_size(t), n_elems); @@ -217,34 +205,17 @@ stress(ZixAllocator* allocator, unsigned test_num, size_t n_elems) static void test_failed_alloc(void) { - static const size_t n_insertions = 4096; - ZixFailingAllocator allocator = zix_failing_allocator(); - // Successfully test insertions to count the number of allocations - ZixTree* t = zix_tree_new(&allocator.base, false, int_cmp, NULL, NULL, NULL); - for (size_t i = 0U; i < n_insertions; ++i) { - assert(!zix_tree_insert(t, (void*)i, NULL)); - } - - // Test that tree allocation failure is handled gracefully - allocator.n_remaining = 0; - zix_tree_free(t); - assert(!zix_tree_new(&allocator.base, false, int_cmp, NULL, NULL, NULL)); - - // Allocate a new tree to try the same test again, but with allocation failure - allocator.n_remaining = 1; - t = zix_tree_new(&allocator.base, false, int_cmp, NULL, NULL, NULL); - assert(t); - - // Test that each insertion allocation failing is handled gracefully - for (size_t i = 0U; i < n_insertions; ++i) { - allocator.n_remaining = 0; + // Successfully stress test the tree to count the number of allocations + assert(!stress(&allocator.base, 0, 16)); - assert(zix_tree_insert(t, (void*)i, NULL) == ZIX_STATUS_NO_MEM); + // Test that each allocation failing is handled gracefully + const size_t n_new_allocs = allocator.n_allocations; + for (size_t i = 0U; i < n_new_allocs; ++i) { + allocator.n_remaining = i; + assert(stress(&allocator.base, 0, 16)); } - - zix_tree_free(t); } int @@ -270,20 +241,14 @@ main(int argc, char** argv) } } - if (!n_elems) { - fprintf(stderr, "USAGE: %s [N_ELEMS]\n", argv[0]); - return 1; - } - printf( "Running %u tests with %zu elements (seed %zu)", n_tests, n_elems, seed); - for (unsigned i = 0; i < n_tests; ++i) { + int st = 0; + for (unsigned i = 0; !st && i < n_tests; ++i) { printf("."); fflush(stdout); - if (stress(NULL, i, n_elems)) { - return test_fail("Failure with random seed %zu\n", seed); - } + st = stress(NULL, i, n_elems); } printf("\n"); |