diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/.clang-tidy | 6 | ||||
-rw-r--r-- | test/cpp/.clang-tidy | 8 | ||||
-rw-r--r-- | test/cpp/test_headers_cpp.cpp | 31 | ||||
-rw-r--r-- | test/cpp/test_path_std.cpp | 14 | ||||
-rw-r--r-- | test/failing_allocator.c | 30 | ||||
-rw-r--r-- | test/failing_allocator.h | 15 | ||||
-rw-r--r-- | test/headers/test_headers.c | 31 | ||||
-rw-r--r-- | test/lint/meson.build | 42 | ||||
-rw-r--r-- | test/meson.build | 112 | ||||
-rw-r--r-- | test/test_allocator.c | 6 | ||||
-rw-r--r-- | test/test_btree.c | 36 | ||||
-rw-r--r-- | test/test_digest.c | 7 | ||||
-rw-r--r-- | test/test_environment.c | 143 | ||||
-rw-r--r-- | test/test_filesystem.c | 44 | ||||
-rw-r--r-- | test/test_hash.c | 43 | ||||
-rw-r--r-- | test/test_path.c | 4 | ||||
-rw-r--r-- | test/test_ring.c | 15 | ||||
-rw-r--r-- | test/test_sem.c | 8 | ||||
-rw-r--r-- | test/test_status.c | 2 | ||||
-rw-r--r-- | test/test_string_view.c | 7 | ||||
-rw-r--r-- | test/test_thread.c | 4 | ||||
-rw-r--r-- | test/test_tree.c | 12 |
22 files changed, 404 insertions, 216 deletions
diff --git a/test/.clang-tidy b/test/.clang-tidy index 2d684a6..401b1b0 100644 --- a/test/.clang-tidy +++ b/test/.clang-tidy @@ -1,16 +1,18 @@ -# Copyright 2020-2022 David Robillard <d@drobilla.net> +# Copyright 2020-2024 David Robillard <d@drobilla.net> # SPDX-License-Identifier: 0BSD OR ISC Checks: > + -*-macro-to-enum, -*-magic-numbers, -android-cloexec-fopen, -bugprone-easily-swappable-parameters, + -bugprone-multi-level-implicit-pointer-conversion, -cert-err33-c, -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, + -concurrency-mt-unsafe, -cppcoreguidelines-avoid-non-const-global-variables, -google-readability-casting, -llvm-header-guard, - -modernize-macro-to-enum, -performance-no-int-to-ptr, -readability-function-cognitive-complexity, InheritParentConfig: true diff --git a/test/cpp/.clang-tidy b/test/cpp/.clang-tidy index 9a3cd8c..1cbcc07 100644 --- a/test/cpp/.clang-tidy +++ b/test/cpp/.clang-tidy @@ -1,13 +1,19 @@ -# Copyright 2020-2022 David Robillard <d@drobilla.net> +# Copyright 2020-2025 David Robillard <d@drobilla.net> # SPDX-License-Identifier: 0BSD OR ISC Checks: > -*-avoid-c-arrays, -*-no-malloc, + -*-use-nullptr, -android-cloexec-fopen, + -bugprone-exception-escape, + -cppcoreguidelines-macro-usage, -cppcoreguidelines-owning-memory, -fuchsia-default-arguments-calls, -modernize-raw-string-literal, + -modernize-redundant-void-arg, -modernize-use-trailing-return-type, + -modernize-use-using, + -performance-enum-size, -readability-implicit-bool-conversion, InheritParentConfig: true diff --git a/test/cpp/test_headers_cpp.cpp b/test/cpp/test_headers_cpp.cpp index f8038c1..fe367ad 100644 --- a/test/cpp/test_headers_cpp.cpp +++ b/test/cpp/test_headers_cpp.cpp @@ -5,21 +5,22 @@ # define WIN32_LEAN_AND_MEAN #endif -#include "zix/allocator.h" // IWYU pragma: keep -#include "zix/attributes.h" // IWYU pragma: keep -#include "zix/btree.h" // IWYU pragma: keep -#include "zix/bump_allocator.h" // IWYU pragma: keep -#include "zix/digest.h" // IWYU pragma: keep -#include "zix/filesystem.h" // IWYU pragma: keep -#include "zix/hash.h" // IWYU pragma: keep -#include "zix/path.h" // IWYU pragma: keep -#include "zix/ring.h" // IWYU pragma: keep -#include "zix/sem.h" // IWYU pragma: keep -#include "zix/status.h" // IWYU pragma: keep -#include "zix/string_view.h" // IWYU pragma: keep -#include "zix/thread.h" // IWYU pragma: keep -#include "zix/tree.h" // IWYU pragma: keep -#include "zix/zix.h" // IWYU pragma: keep +#include <zix/allocator.h> // IWYU pragma: keep +#include <zix/attributes.h> // IWYU pragma: keep +#include <zix/btree.h> // IWYU pragma: keep +#include <zix/bump_allocator.h> // IWYU pragma: keep +#include <zix/digest.h> // IWYU pragma: keep +#include <zix/environment.h> // IWYU pragma: keep +#include <zix/filesystem.h> // IWYU pragma: keep +#include <zix/hash.h> // IWYU pragma: keep +#include <zix/path.h> // IWYU pragma: keep +#include <zix/ring.h> // IWYU pragma: keep +#include <zix/sem.h> // IWYU pragma: keep +#include <zix/status.h> // IWYU pragma: keep +#include <zix/string_view.h> // IWYU pragma: keep +#include <zix/thread.h> // IWYU pragma: keep +#include <zix/tree.h> // IWYU pragma: keep +#include <zix/zix.h> // IWYU pragma: keep #if defined(__GNUC__) __attribute__((const)) diff --git a/test/cpp/test_path_std.cpp b/test/cpp/test_path_std.cpp index cabf3da..b0850a9 100644 --- a/test/cpp/test_path_std.cpp +++ b/test/cpp/test_path_std.cpp @@ -10,15 +10,16 @@ #undef NDEBUG -#include "zix/path.h" -#include "zix/string_view.h" +#include <zix/path.h> +#include <zix/string_view.h> #include <cassert> #include <cstdlib> #include <filesystem> -#include <sstream> #include <string> +// IWYU pragma: no_include <version> + namespace { struct BinaryCase { @@ -483,8 +484,11 @@ run() } for (const auto& relatives : lexical_relatives) { - const Path l = relatives.lhs ? Path{relatives.lhs} : Path{}; - const Path r = relatives.rhs ? Path{relatives.rhs} : Path{}; + assert(relatives.lhs); + assert(relatives.rhs); + + const Path l = Path{relatives.lhs}; + const Path r = Path{relatives.rhs}; assert(match( l.lexically_relative(r), diff --git a/test/failing_allocator.c b/test/failing_allocator.c index 684a8ec..6cffc7b 100644 --- a/test/failing_allocator.c +++ b/test/failing_allocator.c @@ -1,10 +1,10 @@ -// Copyright 2021 David Robillard <d@drobilla.net> +// Copyright 2021-2024 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #include "failing_allocator.h" -#include "zix/allocator.h" -#include "zix/attributes.h" +#include <zix/allocator.h> +#include <zix/attributes.h> #include <stdbool.h> #include <stddef.h> @@ -23,8 +23,7 @@ attempt(ZixFailingAllocator* const allocator) return true; } -ZIX_MALLOC_FUNC -static void* +ZIX_MALLOC_FUNC static void* zix_failing_malloc(ZixAllocator* const allocator, const size_t size) { ZixFailingAllocator* const state = (ZixFailingAllocator*)allocator; @@ -33,8 +32,7 @@ zix_failing_malloc(ZixAllocator* const allocator, const size_t size) return attempt(state) ? base->malloc(base, size) : NULL; } -ZIX_MALLOC_FUNC -static void* +ZIX_MALLOC_FUNC static void* zix_failing_calloc(ZixAllocator* const allocator, const size_t nmemb, const size_t size) @@ -66,8 +64,7 @@ zix_failing_free(ZixAllocator* const allocator, void* const ptr) base->free(base, ptr); } -ZIX_MALLOC_FUNC -static void* +ZIX_MALLOC_FUNC static void* zix_failing_aligned_alloc(ZixAllocator* const allocator, const size_t alignment, const size_t size) @@ -88,8 +85,7 @@ zix_failing_aligned_free(ZixAllocator* const allocator, void* const ptr) base->aligned_free(base, ptr); } -ZIX_CONST_FUNC -ZixFailingAllocator +ZIX_CONST_FUNC ZixFailingAllocator zix_failing_allocator(void) { ZixFailingAllocator failing_allocator = { @@ -107,3 +103,15 @@ zix_failing_allocator(void) return failing_allocator; } + +size_t +zix_failing_allocator_reset(ZixFailingAllocator* const allocator, + const size_t n_allowed) +{ + const size_t n_allocations = allocator->n_allocations; + + allocator->n_allocations = 0U; + allocator->n_remaining = n_allowed; + + return n_allocations; +} diff --git a/test/failing_allocator.h b/test/failing_allocator.h index 982874d..215f2b6 100644 --- a/test/failing_allocator.h +++ b/test/failing_allocator.h @@ -1,10 +1,10 @@ -// Copyright 2021 David Robillard <d@drobilla.net> +// Copyright 2021-2024 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC -#ifndef ZIX_FAILING_ALLOCATOR_H -#define ZIX_FAILING_ALLOCATOR_H +#ifndef ZIX_TEST_FAILING_ALLOCATOR_H +#define ZIX_TEST_FAILING_ALLOCATOR_H -#include "zix/allocator.h" +#include <zix/allocator.h> #include <stddef.h> @@ -15,7 +15,12 @@ typedef struct { size_t n_remaining; ///< Number of remaining successful allocations } ZixFailingAllocator; +/// Return an allocator configured by default to succeed ZixFailingAllocator zix_failing_allocator(void); -#endif // ZIX_FAILING_ALLOCATOR_H +/// Reset an allocator to fail after some number of "allowed" allocations +size_t +zix_failing_allocator_reset(ZixFailingAllocator* allocator, size_t n_allowed); + +#endif // ZIX_TEST_FAILING_ALLOCATOR_H diff --git a/test/headers/test_headers.c b/test/headers/test_headers.c index a610600..f10d05f 100644 --- a/test/headers/test_headers.c +++ b/test/headers/test_headers.c @@ -1,21 +1,22 @@ // Copyright 2022 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC -#include "zix/allocator.h" // IWYU pragma: keep -#include "zix/attributes.h" // IWYU pragma: keep -#include "zix/btree.h" // IWYU pragma: keep -#include "zix/bump_allocator.h" // IWYU pragma: keep -#include "zix/digest.h" // IWYU pragma: keep -#include "zix/filesystem.h" // IWYU pragma: keep -#include "zix/hash.h" // IWYU pragma: keep -#include "zix/path.h" // IWYU pragma: keep -#include "zix/ring.h" // IWYU pragma: keep -#include "zix/sem.h" // IWYU pragma: keep -#include "zix/status.h" // IWYU pragma: keep -#include "zix/string_view.h" // IWYU pragma: keep -#include "zix/thread.h" // IWYU pragma: keep -#include "zix/tree.h" // IWYU pragma: keep -#include "zix/zix.h" // IWYU pragma: keep +#include <zix/allocator.h> // IWYU pragma: keep +#include <zix/attributes.h> // IWYU pragma: keep +#include <zix/btree.h> // IWYU pragma: keep +#include <zix/bump_allocator.h> // IWYU pragma: keep +#include <zix/digest.h> // IWYU pragma: keep +#include <zix/environment.h> // IWYU pragma: keep +#include <zix/filesystem.h> // IWYU pragma: keep +#include <zix/hash.h> // IWYU pragma: keep +#include <zix/path.h> // IWYU pragma: keep +#include <zix/ring.h> // IWYU pragma: keep +#include <zix/sem.h> // IWYU pragma: keep +#include <zix/status.h> // IWYU pragma: keep +#include <zix/string_view.h> // IWYU pragma: keep +#include <zix/thread.h> // IWYU pragma: keep +#include <zix/tree.h> // IWYU pragma: keep +#include <zix/zix.h> // IWYU pragma: keep #if defined(__GNUC__) __attribute__((const)) diff --git a/test/lint/meson.build b/test/lint/meson.build new file mode 100644 index 0000000..13966cf --- /dev/null +++ b/test/lint/meson.build @@ -0,0 +1,42 @@ +# Copyright 2024 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +if not meson.is_subproject() + # Check release metadata + autoship = find_program('autoship', required: get_option('tests')) + if autoship.found() + test('autoship', autoship, args: ['test', zix_src_root], suite: 'data') + endif + + # Check code with cppcheck + cppcheck = find_program('cppcheck', required: false) + if cppcheck.found() + compdb_path = join_paths(zix_build_root, 'compile_commands.json') + cppcheck_args = [ + '--cppcheck-build-dir=' + meson.current_build_dir(), + '--enable=warning,style,performance,portability', + '--error-exitcode=1', + '--project=' + compdb_path, + '--suppress=constParameterCallback', + '--suppress=constParameterPointer', + '--suppress=normalCheckLevelMaxBranches', + '--suppress=unreadVariable', + '-q', + ] + test('cppcheck', cppcheck, args: cppcheck_args, suite: 'code') + endif +endif + +# Check licensing metadata +reuse = find_program('reuse', required: get_option('tests')) +if reuse.found() + reuse_args = ['--root', zix_src_root, 'lint'] + test('REUSE', reuse, args: reuse_args, suite: 'data') +endif + +# Check code formatting +clang_format = find_program('clang-format', required: false) +if clang_format.found() + clang_format_args = ['--Werror', '--dry-run'] + c_headers + sources + test('format', clang_format, args: clang_format_args, suite: 'code') +endif diff --git a/test/meson.build b/test/meson.build index 96fe455..0db182c 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,72 +1,34 @@ -# Copyright 2020-2024 David Robillard <d@drobilla.net> +# Copyright 2020-2025 David Robillard <d@drobilla.net> # SPDX-License-Identifier: 0BSD OR ISC -if not meson.is_subproject() and get_option('lint') - # Check release metadata - autoship = find_program('autoship', required: get_option('tests')) - if autoship.found() - test( - 'autoship', - autoship, - args: ['test', zix_src_root], - suite: 'data', - ) - endif +######## +# Lint # +######## - # Check licensing metadata - reuse = find_program('reuse', required: get_option('tests')) - if reuse.found() - test( - 'REUSE', - reuse, - args: ['--root', zix_src_root, 'lint'], - suite: 'data', - ) - endif +if get_option('lint') + subdir('lint') +endif - # Check code formatting - clang_format = find_program('clang-format', required: false) - if clang_format.found() - test( - 'format', - clang_format, - args: ['--Werror', '--dry-run'] + c_headers + sources, - suite: 'code', - ) - endif +############## +# Unit Tests # +############## - # Check code with cppcheck - if not meson.is_subproject() - cppcheck = find_program('cppcheck', required: false) - if cppcheck.found() - compdb_path = join_paths(zix_build_root, 'compile_commands.json') - test( - 'cppcheck', - cppcheck, - args: [ - '--check-level=exhaustive', - '--enable=warning,style,performance,portability', - '--error-exitcode=1', - '--project=' + compdb_path, - '--suppress=constParameterCallback', - '--suppress=constParameterPointer', - '--suppress=unreadVariable', - '-q', - ], - suite: 'code', - ) +# Set warning suppression flags specific to tests +test_suppressions = [] +if cc.get_id() in ['clang', 'emscripten'] + if warning_level == 'everything' + test_suppressions += ['-Wno-bad-function-cast'] + + if host_machine.system() == 'windows' + if cc.get_id() in ['clang', 'emscripten'] + test_suppressions += ['-Wno-format-nonliteral'] + endif endif endif -endif +elif cc.get_id() == 'gcc' + test_suppressions += ['-Wno-bad-function-cast'] -# Set warning suppression flags specific to tests -test_suppressions = [] -if host_machine.system() == 'windows' - if cc.get_id() in ['clang', 'emscripten'] - test_suppressions += [ - '-Wno-format-nonliteral', - ] - elif cc.get_id() == 'gcc' + if host_machine.system() == 'windows' test_suppressions += ['-Wno-format'] endif endif @@ -80,8 +42,9 @@ sequential_tests = { '': [], '_small': ['4'], }, - 'filesystem': {'': files('../README.md')}, 'digest': {'': []}, + 'environment': {'': []}, + 'filesystem': {'': files('../README.md')}, 'hash': {'': []}, 'path': {'': []}, 'status': {'': []}, @@ -128,6 +91,7 @@ foreach test, cases : sequential_tests sources, c_args: c_suppressions + program_c_args + test_suppressions, dependencies: [zix_dep], + implicit_include_directories: false, include_directories: include_dirs, link_args: program_link_args, ) @@ -147,6 +111,7 @@ if thread_dep.found() sources, c_args: c_suppressions + program_c_args + test_suppressions, dependencies: [zix_dep, thread_dep], + implicit_include_directories: false, include_directories: include_dirs, link_args: program_link_args, ) @@ -182,15 +147,11 @@ if cc.get_id() != 'emscripten' ] if not meson.is_cross_build() - header_suppressions += [ - '-Wno-poison-system-directories', - ] + header_suppressions += ['-Wno-poison-system-directories'] endif if host_machine.system() == 'windows' - header_suppressions += [ - '-Wno-nonportable-system-include-path', - ] + header_suppressions += ['-Wno-nonportable-system-include-path'] endif elif cc.get_id() == 'gcc' @@ -216,6 +177,7 @@ if cc.get_id() != 'emscripten' files('headers/test_headers.c'), c_args: header_suppressions + program_c_args, dependencies: zix_dep, + implicit_include_directories: false, include_directories: include_dirs, ), suite: 'build', @@ -233,19 +195,16 @@ if add_languages(['cpp'], native: false, required: get_option('tests_cpp')) '-Wno-c++98-compat-pedantic', '-Wno-nullability-extension', '-Wno-padded', + '-Wno-unsafe-buffer-usage-in-libc-call', '-Wno-zero-as-null-pointer-constant', ] if not meson.is_cross_build() - cpp_test_args += [ - '-Wno-poison-system-directories', - ] + cpp_test_args += ['-Wno-poison-system-directories'] endif if host_machine.system() == 'windows' - cpp_test_args += [ - '-Wno-nonportable-system-include-path', - ] + cpp_test_args += ['-Wno-nonportable-system-include-path'] endif elif cpp.get_id() == 'gcc' @@ -267,11 +226,14 @@ if add_languages(['cpp'], native: false, required: get_option('tests_cpp')) '/wd4711', # function selected for automatic inline expansion '/wd4820', # padding added after construct '/wd5039', # throwing function passed to C (winbase.h) + '/wd5045', # will insert Spectre mitigation for memory load '/wd5262', # implicit fall-through '/wd5264', # const variable is not used ] endif + cpp_test_args = cpp.get_supported_arguments(cpp_test_args) + test( 'headers_cpp', executable( @@ -279,6 +241,7 @@ if add_languages(['cpp'], native: false, required: get_option('tests_cpp')) files('cpp/test_headers_cpp.cpp'), cpp_args: cpp_test_args + program_c_args, dependencies: [zix_dep], + implicit_include_directories: false, include_directories: include_dirs, link_args: program_link_args, ), @@ -296,6 +259,7 @@ int main(void) { return 0; }''' files('cpp/test_path_std.cpp'), cpp_args: cpp_test_args + program_c_args, dependencies: [zix_dep], + implicit_include_directories: false, include_directories: include_dirs, link_args: program_link_args, ), diff --git a/test/test_allocator.c b/test/test_allocator.c index 9ecbfa0..e9be7ea 100644 --- a/test/test_allocator.c +++ b/test/test_allocator.c @@ -5,8 +5,8 @@ #include "failing_allocator.h" -#include "zix/allocator.h" -#include "zix/bump_allocator.h" +#include <zix/allocator.h> +#include <zix/bump_allocator.h> #include <assert.h> #include <stddef.h> @@ -122,7 +122,7 @@ static void test_failing_allocator(void) { ZixFailingAllocator allocator = zix_failing_allocator(); - allocator.n_remaining = 0; + zix_failing_allocator_reset(&allocator, 0); assert(!zix_malloc(&allocator.base, 16U)); assert(!zix_calloc(&allocator.base, 16U, 1U)); diff --git a/test/test_btree.c b/test/test_btree.c index e918799..a87e26e 100644 --- a/test/test_btree.c +++ b/test/test_btree.c @@ -3,16 +3,15 @@ #undef NDEBUG -#include "zix/btree.h" - #include "ensure.h" #include "failing_allocator.h" #include "test_args.h" #include "test_data.h" -#include "zix/allocator.h" -#include "zix/attributes.h" -#include "zix/status.h" +#include <zix/allocator.h> +#include <zix/attributes.h> +#include <zix/btree.h> +#include <zix/status.h> #include <assert.h> #include <inttypes.h> @@ -20,8 +19,7 @@ #include <stdio.h> #include <stdlib.h> -ZIX_PURE_FUNC -static int +ZIX_PURE_FUNC static int int_cmp(const void* a, const void* b, const void* ZIX_UNUSED(user_data)) { const uintptr_t ia = (uintptr_t)a; @@ -103,6 +101,23 @@ destroy(void* const ptr, const void* const user_data) } static void +test_empty(void) +{ + ZixBTree* const t = zix_btree_new(NULL, int_cmp, NULL); + assert(t); + + // Check that reading functions work properly with an empty (rootless) tree + const int e = 42; + ZixBTreeIter ti = zix_btree_end(t); + zix_btree_clear(t, NULL, NULL); + assert(!zix_btree_size(t)); + assert(zix_btree_find(t, &e, &ti) == ZIX_STATUS_NOT_FOUND); + assert(!zix_btree_lower_bound(t, int_cmp, NULL, &e, &ti)); + + zix_btree_free(t, destroy, NULL); +} + +static void test_clear(void) { ZixBTree* t = zix_btree_new(NULL, int_cmp, NULL); @@ -419,7 +434,7 @@ stress(ZixAllocator* const allocator, uintptr_t removed = 0; ENSUREV(t, zix_btree_remove(t, (void*)r, (void**)&removed, &next), - "Removal of non-existant %" PRIuPTR " succeeded\n", + "Removal of non-existent %" PRIuPTR " succeeded\n", r); } @@ -563,9 +578,9 @@ test_failed_alloc(void) assert(!stress(&allocator.base, 0, 4096)); // Test that each allocation failing is handled gracefully - const size_t n_new_allocs = allocator.n_allocations; + const size_t n_new_allocs = zix_failing_allocator_reset(&allocator, 0); for (size_t i = 0U; i < n_new_allocs; ++i) { - allocator.n_remaining = i; + zix_failing_allocator_reset(&allocator, i); assert(stress(&allocator.base, 0, 4096)); } } @@ -578,6 +593,7 @@ main(int argc, char** argv) return EXIT_FAILURE; } + test_empty(); test_clear(); test_free(); test_iter_comparison(); diff --git a/test/test_digest.c b/test/test_digest.c index 7228f86..65a0e41 100644 --- a/test/test_digest.c +++ b/test/test_digest.c @@ -3,8 +3,8 @@ #undef NDEBUG -#include "zix/attributes.h" -#include "zix/digest.h" +#include <zix/attributes.h> +#include <zix/digest.h> #include <assert.h> #include <stddef.h> @@ -116,8 +116,7 @@ test_digest_aligned(void) } } -ZIX_PURE_FUNC -int +ZIX_PURE_FUNC int main(void) { test_digest32(); diff --git a/test/test_environment.c b/test/test_environment.c new file mode 100644 index 0000000..8756441 --- /dev/null +++ b/test/test_environment.c @@ -0,0 +1,143 @@ +// Copyright 2012-2024 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#undef NDEBUG + +#include "failing_allocator.h" + +#include <zix/allocator.h> +#include <zix/environment.h> +#include <zix/path.h> + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#ifdef _WIN32 + +# define HOME_NAME "USERPROFILE" +# define HOME_VAR "%USERPROFILE%" + +#else + +# define HOME_NAME "HOME" +# define HOME_VAR "$HOME" + +static char* +concat(ZixAllocator* const allocator, + const char* const prefix, + const char* const suffix) +{ + const size_t prefix_len = strlen(prefix); + const size_t suffix_len = strlen(suffix); + const size_t result_len = prefix_len + suffix_len; + + char* const result = (char*)zix_calloc(allocator, 1U, result_len + 1U); + assert(result); + memcpy(result, prefix, prefix_len + 1U); + memcpy(result + prefix_len, suffix, suffix_len + 1U); + return result; +} + +#endif + +static void +check_expansion(const char* const path, const char* const expected) +{ + char* const expanded = zix_expand_environment_strings(NULL, path); + assert(expanded); + assert(!strcmp(expanded, expected)); + zix_free(NULL, expanded); +} + +static void +test_expansion(void) +{ + // Check non-expansion of hopefully unset variables + check_expansion("$ZIX_UNSET0", "$ZIX_UNSET0"); + check_expansion("$ZIX_unset0", "$ZIX_unset0"); + check_expansion("%ZIX_UNSET0%", "%ZIX_UNSET0%"); + check_expansion("%ZIX_unset0%", "%ZIX_unset0%"); + + // Check non-expansion of invalid variable names + check_expansion("$%INVALID", "$%INVALID"); + check_expansion("$<INVALID>", "$<INVALID>"); + check_expansion("$[INVALID]", "$[INVALID]"); + check_expansion("$invalid", "$invalid"); + check_expansion("${INVALID}", "${INVALID}"); + + const char* const home = getenv(HOME_NAME); + if (home) { + char* const var_foo = zix_path_join(NULL, HOME_VAR, "foo"); + char* const home_foo = zix_path_join(NULL, home, "foo"); + + check_expansion(var_foo, home_foo); + +#ifndef _WIN32 + char* const tilde_foo = zix_path_join(NULL, "~", "foo"); + char* const home_and_other = concat(NULL, home, ":/other"); + char* const other_and_home = concat(NULL, "/other:", home); + check_expansion("~other", "~other"); + check_expansion("~", home); + check_expansion("~/foo", home_foo); + check_expansion("~:/other", home_and_other); + check_expansion("/other:~", other_and_home); + check_expansion("$HO", "$HO"); + check_expansion("$HOMEZIX", "$HOMEZIX"); + zix_free(NULL, other_and_home); + zix_free(NULL, home_and_other); + zix_free(NULL, tilde_foo); +#endif + + zix_free(NULL, home_foo); + zix_free(NULL, var_foo); + } +} + +static void +test_failed_alloc(void) +{ + ZixFailingAllocator allocator = zix_failing_allocator(); + + zix_failing_allocator_reset(&allocator, 0U); + assert(!zix_expand_environment_strings(&allocator.base, "/one:~")); + assert(!zix_expand_environment_strings(&allocator.base, "/only")); + assert(!zix_expand_environment_strings(&allocator.base, "~")); + +#ifndef _WIN32 + zix_failing_allocator_reset(&allocator, 1U); + assert(!zix_expand_environment_strings(&allocator.base, "/one:~")); + assert(!zix_expand_environment_strings(&allocator.base, "/one:$HOME/two")); + + zix_failing_allocator_reset(&allocator, 2U); + assert(!zix_expand_environment_strings(&allocator.base, "/one:$HOME/two")); + + zix_failing_allocator_reset(&allocator, 1U); + assert(!zix_expand_environment_strings(&allocator.base, "/one:$UNSET/two")); +#endif +} + +#ifndef _WIN32 + +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +extern char** environ; + +static void +test_null_environ(void) +{ + environ = NULL; + check_expansion(HOME_VAR, HOME_VAR); +} + +#endif + +int +main(void) +{ + test_expansion(); + test_failed_alloc(); +#ifndef _WIN32 + test_null_environ(); +#endif + return 0; +} diff --git a/test/test_filesystem.c b/test/test_filesystem.c index 87a3d15..40fc9a2 100644 --- a/test/test_filesystem.c +++ b/test/test_filesystem.c @@ -1,13 +1,13 @@ -// Copyright 2020-2023 David Robillard <d@drobilla.net> +// Copyright 2020-2024 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #undef NDEBUG -#include "zix/allocator.h" -#include "zix/filesystem.h" -#include "zix/path.h" -#include "zix/status.h" -#include "zix/string_view.h" +#include <zix/allocator.h> +#include <zix/filesystem.h> +#include <zix/path.h> +#include <zix/status.h> +#include <zix/string_view.h> #ifndef _WIN32 # include <unistd.h> @@ -64,6 +64,10 @@ test_canonical_path(void) char* const temp_dir = create_temp_dir("zixXXXXXX"); assert(temp_dir); + char* const sub_dir = zix_path_join(NULL, temp_dir, "sub"); + assert(!zix_create_directory(sub_dir)); + assert(zix_file_type(temp_dir) == ZIX_FILE_TYPE_DIRECTORY); + char* const file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); assert(file_path); @@ -96,10 +100,10 @@ test_canonical_path(void) // Test dot segment resolution - char* const parent_dir_1 = zix_path_join(NULL, temp_dir, ".."); + char* const parent_dir_1 = zix_path_join(NULL, sub_dir, ".."); assert(parent_dir_1); - const ZixStringView parent_view = zix_path_parent_path(temp_dir); + const ZixStringView parent_view = zix_path_parent_path(sub_dir); char* const parent_dir_2 = zix_string_view_copy(NULL, parent_view); assert(parent_dir_2); assert(parent_dir_2[0]); @@ -120,6 +124,7 @@ test_canonical_path(void) // Clean everything up assert(!zix_remove(file_path)); + assert(!zix_remove(sub_dir)); assert(!zix_remove(temp_dir)); free(real_parent_dir_2); @@ -127,6 +132,7 @@ test_canonical_path(void) free(parent_dir_2); free(parent_dir_1); free(file_path); + free(sub_dir); free(temp_dir); } @@ -161,6 +167,7 @@ test_file_type(void) if (sock >= 0) { const socklen_t addr_len = sizeof(struct sockaddr_un); struct sockaddr_un* const addr = (struct sockaddr_un*)calloc(1, addr_len); + assert(addr); if (strlen(file_path) < sizeof(addr->sun_path)) { addr->sun_family = AF_UNIX; @@ -172,9 +179,7 @@ test_file_type(void) assert(!zix_remove(file_path)); close(fd); } - } else { - fprintf(stderr, "warning: Skipped socket test with oddly long TMPDIR\n"); - } + } // otherwise, TMPDIR is oddly long, skip test close(sock); free(addr); @@ -245,7 +250,8 @@ write_to_path(const char* const path, const char* const contents) const size_t len = strlen(contents); fwrite(contents, 1, len, f); - ret = fflush(f) ? errno : ferror(f) ? EBADF : fclose(f) ? errno : 0; + ret = fflush(f) ? errno : ferror(f) ? EBADF : 0; + ret = (fclose(f) && !ret) ? errno : ret; } return ret; @@ -261,9 +267,7 @@ test_copy_file(const char* data_file_path) assert(tmp_file_path); assert(copy_path); - if (!data_file_path) { - data_file_path = tmp_file_path; - } + data_file_path = data_file_path ? data_file_path : tmp_file_path; assert(!write_to_path(tmp_file_path, "test\n")); @@ -395,6 +399,7 @@ visit(const char* const path, const char* const name, void* const data) if (new_names) { char* const name_copy = (char*)calloc(name_len + 1, 1); + assert(name_copy); memcpy(name_copy, name, name_len + 1); file_list->names = new_names; @@ -695,10 +700,11 @@ int main(const int argc, char** const argv) { // Try to find some existing data file that's ideally not on a tmpfs - const char* data_file_path = (argc > 1) ? argv[1] : "build.ninja"; - if (zix_file_type(data_file_path) != ZIX_FILE_TYPE_REGULAR) { - data_file_path = NULL; - } + const char* const default_file_path = (argc > 1) ? argv[1] : "build.ninja"; + const char* const data_file_path = + (zix_file_type(default_file_path) == ZIX_FILE_TYPE_REGULAR) + ? default_file_path + : NULL; test_temp_directory_path(); test_current_path(); diff --git a/test/test_hash.c b/test/test_hash.c index 3d3ca95..2ff286c 100644 --- a/test/test_hash.c +++ b/test/test_hash.c @@ -10,11 +10,11 @@ #include "failing_allocator.h" #include "test_data.h" -#include "zix/allocator.h" -#include "zix/attributes.h" -#include "zix/digest.h" -#include "zix/hash.h" -#include "zix/status.h" +#include <zix/allocator.h> +#include <zix/attributes.h> +#include <zix/digest.h> +#include <zix/hash.h> +#include <zix/status.h> #include <assert.h> #include <inttypes.h> @@ -47,24 +47,21 @@ test_fail(TestState* const state, const char* fmt, ...) return EXIT_FAILURE; } -ZIX_PURE_FUNC -static const char* +ZIX_PURE_FUNC static const char* identity(const char* record) { return record; } /// Decent hash function using zix_digest (murmur2) -ZIX_PURE_FUNC -static size_t +ZIX_PURE_FUNC static size_t decent_string_hash(const char* const str) { return zix_digest(0U, str, strlen(str)); } /// Terrible hash function from K&R first edition -ZIX_PURE_FUNC -static size_t +ZIX_PURE_FUNC static size_t terrible_string_hash(const char* str) { size_t hash = 0U; @@ -77,8 +74,7 @@ terrible_string_hash(const char* str) return hash; } -ZIX_PURE_FUNC -static size_t +ZIX_PURE_FUNC static size_t string_hash_aligned(const char* const str) { size_t length = strlen(str); @@ -87,22 +83,19 @@ string_hash_aligned(const char* const str) return zix_digest_aligned(0U, str, length); } -ZIX_PURE_FUNC -static size_t +ZIX_PURE_FUNC static size_t string_hash32(const char* const str) { return (size_t)zix_digest32(0U, str, strlen(str)); } -ZIX_PURE_FUNC -static size_t +ZIX_PURE_FUNC static size_t string_hash64(const char* const str) { return (size_t)zix_digest64(0U, str, strlen(str)); } -ZIX_PURE_FUNC -static size_t +ZIX_PURE_FUNC static size_t string_hash32_aligned(const char* const str) { size_t length = strlen(str); @@ -113,8 +106,7 @@ string_hash32_aligned(const char* const str) #if UINTPTR_MAX >= UINT64_MAX -ZIX_PURE_FUNC -static size_t +ZIX_PURE_FUNC static size_t string_hash64_aligned(const char* const str) { size_t length = strlen(str); @@ -201,8 +193,8 @@ 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); - ENSUREV(&state, !match, "Unexpectedly found `%s'\n", not_indexed); free(not_indexed); + ENSUREV(&state, !match, "Unexpectedly found `%s'\n", not_indexed_string); } // Remove strings @@ -298,8 +290,7 @@ stress(ZixAllocator* const allocator, const size_t n_elems) } /// Identity hash function for numeric strings for explicitly hitting cases -ZIX_PURE_FUNC -static size_t +ZIX_PURE_FUNC static size_t identity_index_hash(const char* const str) { return strtoul(str, NULL, 10); @@ -366,9 +357,9 @@ test_failed_alloc(void) assert(!stress(&allocator.base, 16)); // Test that each allocation failing is handled gracefully - const size_t n_new_allocs = allocator.n_allocations; + const size_t n_new_allocs = zix_failing_allocator_reset(&allocator, 0); for (size_t i = 0U; i < n_new_allocs; ++i) { - allocator.n_remaining = i; + zix_failing_allocator_reset(&allocator, i); assert(stress(&allocator.base, 16)); } } diff --git a/test/test_path.c b/test/test_path.c index 5c98c32..3a8353d 100644 --- a/test/test_path.c +++ b/test/test_path.c @@ -3,8 +3,8 @@ #undef NDEBUG -#include "zix/path.h" -#include "zix/string_view.h" +#include <zix/path.h> +#include <zix/string_view.h> #include <assert.h> #include <stdbool.h> diff --git a/test/test_ring.c b/test/test_ring.c index b1845ce..06ac183 100644 --- a/test/test_ring.c +++ b/test/test_ring.c @@ -6,10 +6,10 @@ #include "failing_allocator.h" #include "test_args.h" -#include "zix/attributes.h" -#include "zix/ring.h" -#include "zix/status.h" -#include "zix/thread.h" +#include <zix/attributes.h> +#include <zix/ring.h> +#include <zix/status.h> +#include <zix/thread.h> #include <assert.h> #include <limits.h> @@ -34,8 +34,7 @@ gen_msg(int* const msg, int start) return start; } -ZIX_PURE_FUNC -static int +ZIX_PURE_FUNC static int cmp_msg(const int* const msg1, const int* const msg2) { for (unsigned i = 0U; i < MSG_SIZE; ++i) { @@ -170,9 +169,9 @@ test_failed_alloc(void) assert(ring); // Test that each allocation failing is handled gracefully - const size_t n_new_allocs = allocator.n_allocations; + const size_t n_new_allocs = zix_failing_allocator_reset(&allocator, 0); for (size_t i = 0U; i < n_new_allocs; ++i) { - allocator.n_remaining = i; + zix_failing_allocator_reset(&allocator, i); assert(!zix_ring_new(&allocator.base, 512)); } diff --git a/test/test_sem.c b/test/test_sem.c index 0118f50..ad2ea6d 100644 --- a/test/test_sem.c +++ b/test/test_sem.c @@ -3,10 +3,10 @@ #undef NDEBUG -#include "zix/attributes.h" -#include "zix/sem.h" -#include "zix/status.h" -#include "zix/thread.h" +#include <zix/attributes.h> +#include <zix/sem.h> +#include <zix/status.h> +#include <zix/thread.h> #include <assert.h> #include <stdio.h> diff --git a/test/test_status.c b/test/test_status.c index 6857928..b047fe8 100644 --- a/test/test_status.c +++ b/test/test_status.c @@ -3,7 +3,7 @@ #undef NDEBUG -#include "zix/status.h" +#include <zix/status.h> #include <assert.h> #include <stdio.h> diff --git a/test/test_string_view.c b/test/test_string_view.c index 52b824d..9aeb826 100644 --- a/test/test_string_view.c +++ b/test/test_string_view.c @@ -5,7 +5,8 @@ #include "failing_allocator.h" -#include "zix/string_view.h" +#include <zix/allocator.h> +#include <zix/string_view.h> #include <assert.h> #include <string.h> @@ -94,7 +95,7 @@ test_copy(void) ZixFailingAllocator allocator = zix_failing_allocator(); // Copying a string takes exactly one allocation - allocator.n_remaining = 1U; + zix_failing_allocator_reset(&allocator, 1U); char* const copy = zix_string_view_copy(&allocator.base, orig); assert(copy); @@ -102,7 +103,7 @@ test_copy(void) zix_free(&allocator.base, copy); // Check that allocation failure is handled gracefully - allocator.n_remaining = 0U; + zix_failing_allocator_reset(&allocator, 0U); assert(!zix_string_view_copy(&allocator.base, orig)); } diff --git a/test/test_thread.c b/test/test_thread.c index 09edde6..ede0f31 100644 --- a/test/test_thread.c +++ b/test/test_thread.c @@ -3,8 +3,8 @@ #undef NDEBUG -#include "zix/status.h" -#include "zix/thread.h" +#include <zix/status.h> +#include <zix/thread.h> #include <assert.h> #include <string.h> diff --git a/test/test_tree.c b/test/test_tree.c index fae6d85..61be9be 100644 --- a/test/test_tree.c +++ b/test/test_tree.c @@ -8,10 +8,10 @@ #include "test_args.h" #include "test_data.h" -#include "zix/allocator.h" -#include "zix/attributes.h" -#include "zix/status.h" -#include "zix/tree.h" +#include <zix/allocator.h> +#include <zix/attributes.h> +#include <zix/status.h> +#include <zix/tree.h> #include <assert.h> #include <inttypes.h> @@ -211,9 +211,9 @@ test_failed_alloc(void) assert(!stress(&allocator.base, 0, 16)); // Test that each allocation failing is handled gracefully - const size_t n_new_allocs = allocator.n_allocations; + const size_t n_new_allocs = zix_failing_allocator_reset(&allocator, 0); for (size_t i = 0U; i < n_new_allocs; ++i) { - allocator.n_remaining = i; + zix_failing_allocator_reset(&allocator, i); assert(stress(&allocator.base, 0, 16)); } } |