summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/.clang-tidy6
-rw-r--r--test/cpp/.clang-tidy8
-rw-r--r--test/cpp/test_headers_cpp.cpp31
-rw-r--r--test/cpp/test_path_std.cpp14
-rw-r--r--test/failing_allocator.c30
-rw-r--r--test/failing_allocator.h15
-rw-r--r--test/headers/test_headers.c31
-rw-r--r--test/lint/meson.build42
-rw-r--r--test/meson.build83
-rw-r--r--test/test_allocator.c6
-rw-r--r--test/test_btree.c36
-rw-r--r--test/test_digest.c4
-rw-r--r--test/test_environment.c143
-rw-r--r--test/test_filesystem.c58
-rw-r--r--test/test_hash.c18
-rw-r--r--test/test_path.c4
-rw-r--r--test/test_ring.c15
-rw-r--r--test/test_sem.c8
-rw-r--r--test/test_status.c2
-rw-r--r--test/test_string_view.c119
-rw-r--r--test/test_thread.c11
-rw-r--r--test/test_tree.c16
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);
}
}