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 | 83 | ||||
-rw-r--r-- | test/test_allocator.c | 6 | ||||
-rw-r--r-- | test/test_btree.c | 36 | ||||
-rw-r--r-- | test/test_digest.c | 4 | ||||
-rw-r--r-- | test/test_environment.c | 143 | ||||
-rw-r--r-- | test/test_filesystem.c | 58 | ||||
-rw-r--r-- | test/test_hash.c | 18 | ||||
-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 | 119 | ||||
-rw-r--r-- | test/test_thread.c | 11 | ||||
-rw-r--r-- | test/test_tree.c | 16 |
22 files changed, 530 insertions, 170 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 15f449c..0db182c 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,38 +1,34 @@ -# Copyright 2020-2023 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 +############## +# Unit Tests # +############## + # 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 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 +elif cc.get_id() == 'gcc' + test_suppressions += ['-Wno-bad-function-cast'] + + if host_machine.system() == 'windows' test_suppressions += ['-Wno-format'] endif endif @@ -46,11 +42,13 @@ sequential_tests = { '': [], '_small': ['4'], }, - 'filesystem': {'': files('../README.md')}, 'digest': {'': []}, + 'environment': {'': []}, + 'filesystem': {'': files('../README.md')}, 'hash': {'': []}, 'path': {'': []}, 'status': {'': []}, + 'string_view': {'': []}, 'tree': { '': [], '_seed': ['8', '314159'], @@ -93,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, ) @@ -103,7 +102,7 @@ foreach test, cases : sequential_tests endforeach endforeach -# Test multi-threaded +# Test multi-threaded if thread_dep.found() foreach test, cases : threaded_tests sources = common_test_sources + files('test_@0@.c'.format(test)) @@ -112,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, ) @@ -147,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' @@ -181,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', @@ -198,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' @@ -232,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( @@ -244,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, ), @@ -261,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 7e7e77a..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> 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 4a1ad4f..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,16 +167,19 @@ 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); - addr->sun_family = AF_UNIX; - strncpy(addr->sun_path, file_path, sizeof(addr->sun_path) - 1); + if (strlen(file_path) < sizeof(addr->sun_path)) { + addr->sun_family = AF_UNIX; + strncpy(addr->sun_path, file_path, sizeof(addr->sun_path) - 1); - const int fd = bind(sock, (struct sockaddr*)addr, addr_len); - if (fd >= 0) { - assert(zix_file_type(file_path) == ZIX_FILE_TYPE_SOCKET); - assert(!zix_remove(file_path)); - close(fd); - } + const int fd = bind(sock, (struct sockaddr*)addr, addr_len); + if (fd >= 0) { + assert(zix_file_type(file_path) == ZIX_FILE_TYPE_SOCKET); + assert(!zix_remove(file_path)); + close(fd); + } + } // otherwise, TMPDIR is oddly long, skip test close(sock); free(addr); @@ -241,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; @@ -257,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")); @@ -391,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; @@ -691,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 b1de72a..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> @@ -135,7 +135,7 @@ stress_with(ZixAllocator* const allocator, static const size_t string_length = 15; char* const buffer = (char*)calloc(1, n_elems * (string_length + 1)); - char** const strings = state.strings = (char**)calloc(sizeof(char*), n_elems); + char** const strings = state.strings = (char**)calloc(n_elems, sizeof(char*)); state.buffer = buffer; state.strings = strings; ENSURE(&state, buffer && state.strings, "Failed to allocate strings\n"); @@ -193,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 @@ -357,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 new file mode 100644 index 0000000..9aeb826 --- /dev/null +++ b/test/test_string_view.c @@ -0,0 +1,119 @@ +// Copyright 2021-2024 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#undef NDEBUG + +#include "failing_allocator.h" + +#include <zix/allocator.h> +#include <zix/string_view.h> + +#include <assert.h> +#include <string.h> + +static void +test_static_init(void) +{ + static const ZixStringView a = ZIX_STATIC_STRING("a"); + static const ZixStringView ab = ZIX_STATIC_STRING("ab"); + + assert(a.length == 1U); + assert(a.data); + assert(a.data[0] == 'a'); + assert(a.data[1] == '\0'); + + assert(ab.length == 2U); + assert(ab.data[0] == 'a'); + assert(ab.data[1] == 'b'); + assert(ab.data[2] == '\0'); +} + +static void +test_empty(void) +{ + const ZixStringView empty = zix_empty_string(); + + assert(!empty.length); + assert(empty.data); + assert(empty.data[0] == '\0'); +} + +static void +test_string(void) +{ + const ZixStringView nodata = zix_string(NULL); + const ZixStringView empty = zix_string(""); + + assert(!nodata.length); + assert(nodata.data); + assert(nodata.data[0] == '\0'); + + assert(!empty.length); + assert(empty.data); + assert(empty.data[0] == '\0'); +} + +static void +test_equals(void) +{ + static const char* const prefix_str = "prefix"; + + const ZixStringView prefix = zix_string(prefix_str); + const ZixStringView pre = zix_substring(prefix_str, 3U); + const ZixStringView fix = zix_substring(prefix_str + 3U, 3U); + const ZixStringView suffix1 = zix_substring("suffix_1", 6U); + const ZixStringView suffix2 = zix_substring("suffix_2", 6U); + + assert(prefix.length == 6U); + assert(pre.length == 3U); + assert(fix.length == 3U); + assert(suffix1.length == 6U); + assert(suffix2.length == 6U); + + assert(zix_string_view_equals(prefix, zix_string("prefix"))); + assert(zix_string_view_equals(pre, zix_string("pre"))); + assert(zix_string_view_equals(fix, zix_string("fix"))); + assert(zix_string_view_equals(suffix1, zix_string("suffix"))); + assert(zix_string_view_equals(suffix2, zix_string("suffix"))); + + assert(zix_string_view_equals(prefix, prefix)); + assert(zix_string_view_equals(suffix1, suffix2)); + + assert(!zix_string_view_equals(prefix, pre)); + assert(!zix_string_view_equals(pre, prefix)); + assert(!zix_string_view_equals(pre, fix)); + assert(!zix_string_view_equals(fix, prefix)); + assert(!zix_string_view_equals(suffix1, prefix)); + assert(!zix_string_view_equals(prefix, suffix1)); +} + +static void +test_copy(void) +{ + static const ZixStringView orig = ZIX_STATIC_STRING("string"); + + ZixFailingAllocator allocator = zix_failing_allocator(); + + // Copying a string takes exactly one allocation + zix_failing_allocator_reset(&allocator, 1U); + + char* const copy = zix_string_view_copy(&allocator.base, orig); + assert(copy); + assert(!strcmp(copy, "string")); + zix_free(&allocator.base, copy); + + // Check that allocation failure is handled gracefully + zix_failing_allocator_reset(&allocator, 0U); + assert(!zix_string_view_copy(&allocator.base, orig)); +} + +int +main(void) +{ + test_static_init(); + test_empty(); + test_string(); + test_equals(); + test_copy(); + return 0; +} diff --git a/test/test_thread.c b/test/test_thread.c index 8cfc9f4..ede0f31 100644 --- a/test/test_thread.c +++ b/test/test_thread.c @@ -3,7 +3,8 @@ #undef NDEBUG -#include "zix/thread.h" +#include <zix/status.h> +#include <zix/thread.h> #include <assert.h> #include <string.h> @@ -32,8 +33,12 @@ main(int argc, char** argv) SharedData data = {argc + (int)strlen(argv[0]), 0}; - assert(!zix_thread_create(&thread, 128, thread_func, &data)); - assert(!zix_thread_join(thread)); + ZixStatus st = zix_thread_create(&thread, 128, thread_func, &data); + assert(!st); + + st = zix_thread_join(thread); + assert(!st); + assert(data.output == data.input * 7); return 0; diff --git a/test/test_tree.c b/test/test_tree.c index 5f093d3..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> @@ -21,7 +21,7 @@ #include <stdlib.h> #include <time.h> -static uintptr_t seed = 1; +static size_t seed = 1; static int int_cmp(const void* a, const void* b, const void* ZIX_UNUSED(user_data)) @@ -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)); } } @@ -237,7 +237,7 @@ main(int argc, char** argv) if (argc > 2) { seed = strtoul(argv[2], NULL, 10); } else { - seed = (uintptr_t)time(NULL); + seed = (size_t)time(NULL); } } |