From d8b960be46007f9c09356e526d3c2dcff4b186a5 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 23 Oct 2022 13:41:27 -0400 Subject: Add filesystem API --- test/.clang-tidy | 1 + test/headers/test_headers.c | 1 + test/test_filesystem.c | 712 ++++++++++++++++++++++++++++++++++++++++++++ test/test_status.c | 4 +- 4 files changed, 716 insertions(+), 2 deletions(-) create mode 100644 test/test_filesystem.c (limited to 'test') diff --git a/test/.clang-tidy b/test/.clang-tidy index 5722b69..16da00c 100644 --- a/test/.clang-tidy +++ b/test/.clang-tidy @@ -3,6 +3,7 @@ Checks: > -*-magic-numbers, + -android-cloexec-fopen, -bugprone-easily-swappable-parameters, -cert-err33-c, -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, diff --git a/test/headers/test_headers.c b/test/headers/test_headers.c index 9e5bddd..d62dc2e 100644 --- a/test/headers/test_headers.c +++ b/test/headers/test_headers.c @@ -7,6 +7,7 @@ #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/function_types.h" // IWYU pragma: keep #include "zix/hash.h" // IWYU pragma: keep #include "zix/path.h" // IWYU pragma: keep diff --git a/test/test_filesystem.c b/test/test_filesystem.c new file mode 100644 index 0000000..b0ec2a4 --- /dev/null +++ b/test/test_filesystem.c @@ -0,0 +1,712 @@ +// Copyright 2020-2022 David Robillard +// 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" + +#ifndef _WIN32 +# include +#endif + +#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L +# include +# include +# include +#endif + +#include +#include +#include +#include +#include + +static void +test_temp_directory_path(void) +{ + char* tmpdir = zix_temp_directory_path(NULL); + + assert(zix_file_type(tmpdir) == ZIX_FILE_TYPE_DIRECTORY); + + free(tmpdir); +} + +static void +test_current_path(void) +{ + char* cwd = zix_current_path(NULL); + + assert(zix_file_type(cwd) == ZIX_FILE_TYPE_DIRECTORY); + + free(cwd); +} + +static char* +create_temp_dir(const char* const name_pattern) +{ + char* const temp = zix_temp_directory_path(NULL); + char* const path_pattern = zix_path_join(NULL, temp, name_pattern); + char* const result = zix_create_temporary_directory(NULL, path_pattern); + free(path_pattern); + zix_free(NULL, temp); + return result; +} + +static void +test_canonical_path(void) +{ + assert(!zix_canonical_path(NULL, NULL)); + + char* const temp_dir = create_temp_dir("zixXXXXXX"); + assert(temp_dir); + + char* const file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); + assert(file_path); + + { + FILE* const f = fopen(file_path, "w"); + fprintf(f, "test\n"); + fclose(f); + } + +#ifndef _WIN32 + // Test symlink resolution + + char* const link_path = zix_path_join(NULL, temp_dir, "zix_test_link"); + + assert(!zix_create_symlink(file_path, link_path)); + + char* const real_file_path = zix_canonical_path(NULL, file_path); + char* const real_link_path = zix_canonical_path(NULL, link_path); + + assert(real_file_path); + assert(real_link_path); + assert(!strcmp(real_file_path, real_link_path)); + + assert(!zix_remove(link_path)); + free(real_link_path); + free(real_file_path); + free(link_path); +#endif + + // Test dot segment resolution + + char* const parent_dir_1 = zix_path_join(NULL, temp_dir, ".."); + assert(parent_dir_1); + + const ZixStringView parent_view = zix_path_parent_path(temp_dir); + char* const parent_dir_2 = zix_string_view_copy(NULL, parent_view); + assert(parent_dir_2); + assert(parent_dir_2[0]); + + char* const real_parent_dir_1 = zix_canonical_path(NULL, parent_dir_1); + char* const real_parent_dir_2 = zix_canonical_path(NULL, parent_dir_2); + + assert(real_parent_dir_1); + assert(real_parent_dir_2); + assert(!strcmp(real_parent_dir_1, real_parent_dir_2)); + + // Test missing files + + assert(!zix_canonical_path(NULL, "/presumuably/absent")); + assert(!zix_canonical_path(NULL, "/presumuably/absent/")); + assert(!zix_canonical_path(NULL, "presumuably_absent")); + + // Clean everything up + + assert(!zix_remove(file_path)); + assert(!zix_remove(temp_dir)); + + free(real_parent_dir_2); + free(real_parent_dir_1); + free(parent_dir_2); + free(parent_dir_1); + free(file_path); + free(temp_dir); +} + +static void +test_file_type(void) +{ + char* const temp_dir = create_temp_dir("zixXXXXXX"); + assert(temp_dir); + + char* const file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); + assert(file_path); + assert(zix_file_type(file_path) == ZIX_FILE_TYPE_NONE); + + // Regular file + FILE* f = fopen(file_path, "w"); + fprintf(f, "test\n"); + fclose(f); + assert(zix_file_type(file_path) == ZIX_FILE_TYPE_REGULAR); + assert(!zix_remove(file_path)); + +#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L + + // FIFO + if (!mkfifo(file_path, 0600)) { + assert(zix_file_type(file_path) == ZIX_FILE_TYPE_FIFO); + assert(!zix_remove(file_path)); + } + + // Socket + const int sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock >= 0) { + const socklen_t addr_len = sizeof(struct sockaddr_un); + struct sockaddr_un* const addr = (struct sockaddr_un*)calloc(1, addr_len); + + 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); + close(sock); + free(addr); + } + +#endif + + assert(!zix_remove(temp_dir)); + free(file_path); + free(temp_dir); +} + +static void +test_path_exists(void) +{ + char* const temp_dir = create_temp_dir("zixXXXXXX"); + char* const file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); + assert(temp_dir); + assert(file_path); + + assert(zix_file_type(file_path) == ZIX_FILE_TYPE_NONE); + + FILE* f = fopen(file_path, "w"); + fprintf(f, "test\n"); + fclose(f); + + assert(zix_file_type(file_path) == ZIX_FILE_TYPE_REGULAR); + + assert(!zix_remove(file_path)); + assert(!zix_remove(temp_dir)); + + free(file_path); + free(temp_dir); +} + +static void +test_is_directory(void) +{ + char* const temp_dir = create_temp_dir("zixXXXXXX"); + char* const file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); + assert(temp_dir); + assert(file_path); + + assert(zix_file_type(temp_dir) == ZIX_FILE_TYPE_DIRECTORY); + assert(zix_file_type(file_path) == ZIX_FILE_TYPE_NONE); + + FILE* f = fopen(file_path, "w"); + fprintf(f, "test\n"); + fclose(f); + + assert(zix_file_type(file_path) == ZIX_FILE_TYPE_REGULAR); + + assert(!zix_remove(file_path)); + assert(!zix_remove(temp_dir)); + + free(file_path); + free(temp_dir); +} + +static int +write_to_path(const char* const path, const char* const contents) +{ + FILE* const f = fopen(path, "w"); + if (!f) { + return -1; + } + + const size_t len = strlen(contents); + fwrite(contents, 1, len, f); + + const int ret = fflush(f) ? errno : ferror(f) ? EBADF : 0; + + return fclose(f) ? errno : ret; +} + +static void +test_copy_file(const char* const data_file_path) +{ + ZixStatus st = ZIX_STATUS_SUCCESS; + char* const temp_dir = create_temp_dir("zixXXXXXX"); + char* const tmp_file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); + char* const copy_path = zix_path_join(NULL, temp_dir, "zix_test_copy"); + assert(temp_dir); + assert(tmp_file_path); + assert(copy_path); + + write_to_path(tmp_file_path, "test\n"); + + assert((st = zix_copy_file(NULL, tmp_file_path, "/does/not/exist", 0U))); + assert(zix_copy_file(NULL, "/does/not/exist", copy_path, 0U)); + assert(zix_file_type(copy_path) == ZIX_FILE_TYPE_NONE); + + // Fail to copy from/to a directory + assert(zix_copy_file(NULL, temp_dir, copy_path, 0U)); + assert(zix_copy_file(NULL, tmp_file_path, temp_dir, 0U)); + + if (data_file_path) { + // Fail to copy a file to itself + assert((st = zix_copy_file(NULL, data_file_path, data_file_path, 0U)) == + ZIX_STATUS_EXISTS); + + // Successful copy between filesystems + assert(!(st = zix_copy_file(NULL, data_file_path, copy_path, 0U))); + assert(zix_file_equals(NULL, data_file_path, copy_path)); + + // Trying the same again fails because the copy path already exists + assert(zix_copy_file(NULL, data_file_path, copy_path, 0U) == + ZIX_STATUS_EXISTS); + + // Unless overwriting is requested + assert(!zix_copy_file( + NULL, data_file_path, copy_path, ZIX_COPY_OPTION_OVERWRITE_EXISTING)); + + assert(!zix_remove(copy_path)); + } + + // Successful copy within a filesystem + assert(zix_file_type(copy_path) == ZIX_FILE_TYPE_NONE); + assert(!(st = zix_copy_file(NULL, tmp_file_path, copy_path, 0U))); + assert(zix_file_equals(NULL, tmp_file_path, copy_path)); + assert(!zix_remove(copy_path)); + + if (zix_file_type("/dev/random") == ZIX_FILE_TYPE_CHARACTER) { + // Fail to copy infinite file to a file + assert((st = zix_copy_file(NULL, "/dev/random", copy_path, 0U)) == + ZIX_STATUS_BAD_ARG); + + // Fail to copy infinite file to itself + assert((st = zix_copy_file(NULL, "/dev/random", "/dev/random", 0U)) == + ZIX_STATUS_BAD_ARG); + + // Fail to copy infinite file to another + assert((st = zix_copy_file(NULL, "/dev/random", "/dev/urandom", 0U)) == + ZIX_STATUS_BAD_ARG); + } + + if (zix_file_type("/dev/full") == ZIX_FILE_TYPE_CHARACTER) { + if (data_file_path) { + assert((st = zix_copy_file(NULL, + data_file_path, + "/dev/full", + ZIX_COPY_OPTION_OVERWRITE_EXISTING)) == + ZIX_STATUS_NO_SPACE); + } + + // Copy short file (error after flushing) + assert(( + st = zix_copy_file( + NULL, tmp_file_path, "/dev/full", ZIX_COPY_OPTION_OVERWRITE_EXISTING))); + + // Copy long file (error during writing) + FILE* const f = fopen(tmp_file_path, "w"); + for (size_t i = 0; i < 4096; ++i) { + fprintf(f, "test\n"); + } + fclose(f); + assert(( + st = zix_copy_file( + NULL, tmp_file_path, "/dev/full", ZIX_COPY_OPTION_OVERWRITE_EXISTING))); + } + + assert(!(st = zix_remove(tmp_file_path))); + assert(!(st = zix_remove(temp_dir))); + + free(copy_path); + free(tmp_file_path); + free(temp_dir); +} + +static void +test_flock(void) +{ + char* const temp_dir = create_temp_dir("zixXXXXXX"); + char* const file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); + assert(temp_dir); + assert(file_path); + + FILE* const f1 = fopen(file_path, "w"); + FILE* const f2 = fopen(file_path, "w"); + + ZixStatus st = zix_file_lock(f1, ZIX_FILE_LOCK_TRY); + assert(!st || st == ZIX_STATUS_NOT_SUPPORTED); + + if (!st) { + assert(zix_file_lock(f2, ZIX_FILE_LOCK_TRY) == ZIX_STATUS_UNAVAILABLE); + assert(!zix_file_unlock(f1, ZIX_FILE_LOCK_TRY)); + + // assert(zix_file_unlock(f1, ZIX_FILE_LOCK_TRY)); + // assert(zix_file_unlock(f1, ZIX_FILE_LOCK_BLOCK)); + } + + // assert(zix_file_unlock(stdout, ZIX_FILE_LOCK_TRY)); + // assert(zix_file_unlock(stdout, ZIX_FILE_LOCK_BLOCK)); + + fclose(f2); + fclose(f1); + assert(!zix_remove(file_path)); + assert(!zix_remove(temp_dir)); + free(file_path); + free(temp_dir); +} + +typedef struct { + size_t n_names; + char** names; +} FileList; + +static void +visit(const char* const path, const char* const name, void* const data) +{ + (void)path; + + const size_t name_len = strlen(name); + FileList* const file_list = (FileList*)data; + + char** const new_names = + (char**)realloc(file_list->names, sizeof(char*) * ++file_list->n_names); + + if (new_names) { + char* const name_copy = (char*)calloc(name_len + 1, 1); + memcpy(name_copy, name, name_len + 1); + + file_list->names = new_names; + file_list->names[file_list->n_names - 1] = name_copy; + } +} + +static void +test_dir_for_each(void) +{ + char* const temp_dir = create_temp_dir("zixXXXXXX"); + char* const path1 = zix_path_join(NULL, temp_dir, "zix_test_1"); + char* const path2 = zix_path_join(NULL, temp_dir, "zix_test_2"); + assert(temp_dir); + assert(path1); + assert(path2); + + FILE* const f1 = fopen(path1, "w"); + FILE* const f2 = fopen(path2, "w"); + fprintf(f1, "test\n"); + fprintf(f2, "test\n"); + fclose(f2); + fclose(f1); + + FileList file_list = {0, NULL}; + zix_dir_for_each(temp_dir, &file_list, visit); + + assert(file_list.names); + assert((!strcmp(file_list.names[0], "zix_test_1") && + !strcmp(file_list.names[1], "zix_test_2")) || + (!strcmp(file_list.names[0], "zix_test_2") && + !strcmp(file_list.names[1], "zix_test_1"))); + + assert(!zix_remove(path2)); + assert(!zix_remove(path1)); + assert(!zix_remove(temp_dir)); + + free(file_list.names[0]); + free(file_list.names[1]); + free(file_list.names); + free(path2); + free(path1); + free(temp_dir); +} + +static void +test_create_temporary_directory(void) +{ + assert(!zix_create_temporary_directory(NULL, "")); + + char* const path1 = create_temp_dir("zixXXXXXX"); + + assert(path1); + assert(zix_file_type(path1) == ZIX_FILE_TYPE_DIRECTORY); + + char* const path2 = create_temp_dir("zixXXXXXX"); + + assert(path2); + assert(strcmp(path1, path2)); + assert(zix_file_type(path1) == ZIX_FILE_TYPE_DIRECTORY); + assert(zix_file_type(path2) == ZIX_FILE_TYPE_DIRECTORY); + + assert(!zix_remove(path2)); + assert(!zix_remove(path1)); + free(path2); + free(path1); +} + +static void +test_create_directory_like(void) +{ + char* const temp_dir = create_temp_dir("zixXXXXXX"); + assert(temp_dir); + assert(zix_file_type(temp_dir) == ZIX_FILE_TYPE_DIRECTORY); + + char* const sub_dir = zix_path_join(NULL, temp_dir, "sub"); + assert(zix_create_directory_like(sub_dir, sub_dir) == ZIX_STATUS_NOT_FOUND); + assert(!zix_create_directory_like(sub_dir, temp_dir)); + assert(zix_file_type(sub_dir) == ZIX_FILE_TYPE_DIRECTORY); + assert(!zix_remove(sub_dir)); + zix_free(NULL, sub_dir); + + assert(!zix_remove(temp_dir)); + free(temp_dir); +} + +static void +test_create_directories(void) +{ + char* const temp_dir = create_temp_dir("zixXXXXXX"); + + assert(temp_dir); + assert(zix_file_type(temp_dir) == ZIX_FILE_TYPE_DIRECTORY); + assert(zix_create_directories(NULL, "") == ZIX_STATUS_BAD_ARG); + + char* const child_dir = zix_path_join(NULL, temp_dir, "child"); + char* const grandchild_dir = zix_path_join(NULL, child_dir, "grandchild"); + + assert(!zix_create_directories(NULL, grandchild_dir)); + assert(zix_file_type(grandchild_dir) == ZIX_FILE_TYPE_DIRECTORY); + assert(zix_file_type(child_dir) == ZIX_FILE_TYPE_DIRECTORY); + + char* const file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); + FILE* const f = fopen(file_path, "w"); + + fprintf(f, "test\n"); + fclose(f); + + assert(zix_create_directories(NULL, file_path) == ZIX_STATUS_EXISTS); + + assert(!zix_remove(file_path)); + assert(!zix_remove(grandchild_dir)); + assert(!zix_remove(child_dir)); + assert(!zix_remove(temp_dir)); + free(file_path); + free(child_dir); + free(grandchild_dir); + free(temp_dir); +} + +static void +test_file_equals(void) +{ + char* const temp_dir = create_temp_dir("zixXXXXXX"); + char* const path1 = zix_path_join(NULL, temp_dir, "zix1"); + char* const path2 = zix_path_join(NULL, temp_dir, "zix2"); + assert(temp_dir); + + // Equal: test, test + assert(!write_to_path(path1, "test")); + assert(!write_to_path(path2, "test")); + assert(zix_file_equals(NULL, path1, path2)); + + // Missing files + assert(!zix_file_equals(NULL, path1, "/does/not/exist")); + assert(!zix_file_equals(NULL, "/does/not/exist", path2)); + + // Longer RHS: test, testdiff + assert(!write_to_path(path2, "diff")); + assert(!zix_file_equals(NULL, path1, path2)); + + // Longer LHS: testdifflong, testdiff + assert(!write_to_path(path1, "difflong")); + assert(!zix_file_equals(NULL, path1, path2)); + + // Equal sizes but different content: testdifflong, testdifflang + assert(!write_to_path(path2, "difflang")); + assert(!zix_file_equals(NULL, path1, path2)); + + assert(zix_file_equals(NULL, path1, path1)); + assert(zix_file_equals(NULL, path2, path2)); + + assert(!zix_remove(path2)); + assert(!zix_remove(path1)); + assert(!zix_remove(temp_dir)); + + free(path2); + free(path1); + free(temp_dir); +} + +static void +test_file_size(void) +{ + static const char* const contents = "file size test"; + + char* const temp_dir = create_temp_dir("zixXXXXXX"); + char* const path = zix_path_join(NULL, temp_dir, "zix_test"); + + assert(temp_dir); + assert(!write_to_path(path, contents)); + + const ZixFileOffset size = zix_file_size(path); + assert(size > 0); + assert((size_t)size == strlen(contents)); + + assert(!zix_remove(path)); + assert(!zix_remove(temp_dir)); + + free(path); + free(temp_dir); +} + +static void +test_create_symlink(void) +{ + static const char* const contents = "zixtest"; + + char* const temp_dir = create_temp_dir("zixXXXXXX"); + assert(temp_dir); + + // Write contents to original file + char* const file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); + { + FILE* const f = fopen(file_path, "w"); + fprintf(f, "%s", contents); + fclose(f); + } + + // Ensure original file exists and is a regular file + assert(zix_symlink_type(file_path) == ZIX_FILE_TYPE_REGULAR); + + // Create symlink to original file + char* const link_path = zix_path_join(NULL, temp_dir, "zix_test_link"); + const ZixStatus st = zix_create_symlink(file_path, link_path); + + // Check that the symlink seems equivalent to the original file + assert(!st || st == ZIX_STATUS_NOT_SUPPORTED || st == ZIX_STATUS_BAD_PERMS); + if (!st) { + assert(zix_symlink_type(link_path) == ZIX_FILE_TYPE_SYMLINK); + assert(zix_file_type(link_path) == ZIX_FILE_TYPE_REGULAR); + assert(zix_file_equals(NULL, file_path, link_path)); + assert(!zix_remove(link_path)); + } else { + assert(zix_symlink_type(link_path) == ZIX_FILE_TYPE_NONE); + } + + assert(!zix_remove(file_path)); + assert(!zix_remove(temp_dir)); + + free(link_path); + free(file_path); + free(temp_dir); +} + +static void +test_create_directory_symlink(void) +{ + char* const temp_dir = create_temp_dir("zixXXXXXX"); + assert(temp_dir); + + char* const link_path = zix_path_join(NULL, temp_dir, "zix_test_link"); + const ZixStatus st = zix_create_directory_symlink(temp_dir, link_path); + + if (st != ZIX_STATUS_NOT_SUPPORTED && st != ZIX_STATUS_BAD_PERMS) { + assert(!st); + assert(zix_file_type(link_path) == ZIX_FILE_TYPE_DIRECTORY); + +#ifdef _WIN32 + assert(zix_symlink_type(link_path) == ZIX_FILE_TYPE_DIRECTORY); +#else + assert(zix_symlink_type(link_path) == ZIX_FILE_TYPE_SYMLINK); +#endif + + assert(!zix_remove(link_path)); + } + + assert(!zix_remove(temp_dir)); + free(link_path); + free(temp_dir); +} + +static void +test_create_hard_link(void) +{ + static const char* const contents = "zixtest"; + + char* const temp_dir = create_temp_dir("zixXXXXXX"); + assert(temp_dir); + + // Write contents to original file + char* const file_path = zix_path_join(NULL, temp_dir, "zix_test_file"); + { + FILE* const f = fopen(file_path, "w"); + fprintf(f, "%s", contents); + fclose(f); + } + + // Ensure original file exists and is a regular file + assert(zix_symlink_type(file_path) == ZIX_FILE_TYPE_REGULAR); + + // Create symlink to original file + char* const link_path = zix_path_join(NULL, temp_dir, "zix_test_link"); + const ZixStatus st = zix_create_hard_link(file_path, link_path); + + // Check that the link is equivalent to the original file + assert(!st || st == ZIX_STATUS_NOT_SUPPORTED || st == ZIX_STATUS_MAX_LINKS); + if (!st) { + assert(zix_file_type(link_path) == ZIX_FILE_TYPE_REGULAR); + assert(zix_file_equals(NULL, file_path, link_path)); + assert(!zix_remove(link_path)); + } else { + assert(zix_symlink_type(link_path) == ZIX_FILE_TYPE_NONE); + } + + assert(!zix_remove(file_path)); + assert(!zix_remove(temp_dir)); + + free(link_path); + free(file_path); + free(temp_dir); +} + +int +main(const int argc, char** const argv) +{ +#ifdef __EMSCRIPTEN__ + const char* const data_file_path = NULL; +#else + const char* const data_file_path = argc > 1 ? argv[1] : "build.ninja"; +#endif + + test_temp_directory_path(); + test_current_path(); + test_canonical_path(); + test_file_type(); + test_path_exists(); + test_is_directory(); + test_copy_file(data_file_path); + test_flock(); + test_dir_for_each(); + test_create_temporary_directory(); + test_create_directory_like(); + test_create_directories(); + test_file_equals(); + test_file_size(); + test_create_symlink(); + test_create_directory_symlink(); + test_create_hard_link(); + + return 0; +} diff --git a/test/test_status.c b/test/test_status.c index ca47d6e..6857928 100644 --- a/test/test_status.c +++ b/test/test_status.c @@ -1,4 +1,4 @@ -// Copyright 2021 David Robillard +// Copyright 2021-2022 David Robillard // SPDX-License-Identifier: ISC #undef NDEBUG @@ -15,7 +15,7 @@ test_strerror(void) const char* msg = zix_strerror(ZIX_STATUS_SUCCESS); assert(!strcmp(msg, "Success")); - for (int i = ZIX_STATUS_ERROR; i <= ZIX_STATUS_UNAVAILABLE; ++i) { + for (int i = ZIX_STATUS_ERROR; i <= ZIX_STATUS_MAX_LINKS; ++i) { msg = zix_strerror((ZixStatus)i); assert(strcmp(msg, "Success")); } -- cgit v1.2.1