diff --git a/lib/libnv/tests/nv_array_tests.cc b/lib/libnv/tests/nv_array_tests.cc index 06d7525c3e1d..9acbaef67eba 100644 --- a/lib/libnv/tests/nv_array_tests.cc +++ b/lib/libnv/tests/nv_array_tests.cc @@ -1,1194 +1,1248 @@ /*- - * Copyright (c) 2015 Mariusz Zaborski - * All rights reserved. + * Copyright (c) 2015-2024 Mariusz Zaborski * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include +#include #include #include #include #include #include #include #include #include #include #define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF) ATF_TEST_CASE_WITHOUT_HEAD(nvlist_bool_array__basic); ATF_TEST_CASE_BODY(nvlist_bool_array__basic) { bool testbool[16]; const bool *const_result; bool *result; nvlist_t *nvl; size_t num_items; unsigned int i; const char *key; key = "nvl/bool"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); for (i = 0; i < 16; i++) testbool[i] = (i % 2 == 0); nvlist_add_bool_array(nvl, key, testbool, 16); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_bool_array(nvl, key)); ATF_REQUIRE(nvlist_exists_bool_array(nvl, "nvl/bool")); const_result = nvlist_get_bool_array(nvl, key, &num_items); ATF_REQUIRE_EQ(num_items, 16); ATF_REQUIRE(const_result != NULL); for (i = 0; i < num_items; i++) ATF_REQUIRE_EQ(const_result[i], testbool[i]); result = nvlist_take_bool_array(nvl, key, &num_items); ATF_REQUIRE_EQ(num_items, 16); ATF_REQUIRE(const_result != NULL); for (i = 0; i < num_items; i++) ATF_REQUIRE_EQ(result[i], testbool[i]); ATF_REQUIRE(!nvlist_exists_bool_array(nvl, key)); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); free(result); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array__basic); ATF_TEST_CASE_BODY(nvlist_string_array__basic) { const char * const *const_result; char **result; nvlist_t *nvl; size_t num_items; unsigned int i; const char *key; const char *string_arr[8] = { "a", "b", "kot", "foo", "tests", "nice test", "", "abcdef" }; key = "nvl/string"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); nvlist_add_string_array(nvl, key, string_arr, nitems(string_arr)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_string_array(nvl, key)); ATF_REQUIRE(nvlist_exists_string_array(nvl, "nvl/string")); const_result = nvlist_get_string_array(nvl, key, &num_items); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE(num_items == nitems(string_arr)); for (i = 0; i < num_items; i++) { if (string_arr[i] != NULL) { ATF_REQUIRE(strcmp(const_result[i], string_arr[i]) == 0); } else { ATF_REQUIRE(const_result[i] == string_arr[i]); } } result = nvlist_take_string_array(nvl, key, &num_items); ATF_REQUIRE(result != NULL); ATF_REQUIRE_EQ(num_items, nitems(string_arr)); for (i = 0; i < num_items; i++) { if (string_arr[i] != NULL) { ATF_REQUIRE_EQ(strcmp(result[i], string_arr[i]), 0); } else { ATF_REQUIRE_EQ(result[i], string_arr[i]); } } ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); for (i = 0; i < num_items; i++) free(result[i]); free(result); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_descriptor_array__basic); ATF_TEST_CASE_BODY(nvlist_descriptor_array__basic) { int fd[32], *result; const int *const_result; nvlist_t *nvl; size_t num_items; unsigned int i; const char *key; for (i = 0; i < nitems(fd); i++) { fd[i] = dup(STDERR_FILENO); ATF_REQUIRE(fd_is_valid(fd[i])); } key = "nvl/descriptor"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_descriptor_array(nvl, key)); nvlist_add_descriptor_array(nvl, key, fd, nitems(fd)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key)); ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, "nvl/descriptor")); const_result = nvlist_get_descriptor_array(nvl, key, &num_items); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE(num_items == nitems(fd)); for (i = 0; i < num_items; i++) { ATF_REQUIRE(fd_is_valid(const_result[i])); if (i > 0) ATF_REQUIRE(const_result[i] != const_result[i - 1]); } result = nvlist_take_descriptor_array(nvl, key, &num_items); ATF_REQUIRE(result != NULL); ATF_REQUIRE_EQ(num_items, nitems(fd)); for (i = 0; i < num_items; i++) { ATF_REQUIRE(fd_is_valid(result[i])); if (i > 0) ATF_REQUIRE(const_result[i] != const_result[i - 1]); } ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); for (i = 0; i < num_items; i++) { close(result[i]); close(fd[i]); } free(result); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_number_array__basic); ATF_TEST_CASE_BODY(nvlist_number_array__basic) { const uint64_t *const_result; uint64_t *result; nvlist_t *nvl; size_t num_items; unsigned int i; const char *key; const uint64_t number[8] = { 0, UINT_MAX, 7, 123, 90, 100000, 8, 1 }; key = "nvl/number"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); nvlist_add_number_array(nvl, key, number, nitems(number)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_number_array(nvl, key)); ATF_REQUIRE(nvlist_exists_number_array(nvl, "nvl/number")); const_result = nvlist_get_number_array(nvl, key, &num_items); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE(num_items == nitems(number)); for (i = 0; i < num_items; i++) ATF_REQUIRE_EQ(const_result[i], number[i]); result = nvlist_take_number_array(nvl, key, &num_items); ATF_REQUIRE(result != NULL); ATF_REQUIRE_EQ(num_items, nitems(number)); for (i = 0; i < num_items; i++) ATF_REQUIRE_EQ(result[i], number[i]); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); free(result); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__basic); ATF_TEST_CASE_BODY(nvlist_nvlist_array__basic) { nvlist_t *testnvl[8]; const nvlist_t * const *const_result; nvlist_t **result; nvlist_t *nvl; size_t num_items; unsigned int i; const char *somestr[8] = { "a", "b", "c", "d", "e", "f", "g", "h" }; const char *key; for (i = 0; i < 8; i++) { testnvl[i] = nvlist_create(0); ATF_REQUIRE(testnvl[i] != NULL); ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0); nvlist_add_string(testnvl[i], "nvl/string", somestr[i]); ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0); ATF_REQUIRE(nvlist_exists_string(testnvl[i], "nvl/string")); } key = "nvl/nvlist"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); nvlist_add_nvlist_array(nvl, key, (const nvlist_t * const *)testnvl, 8); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, key)); ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, "nvl/nvlist")); const_result = nvlist_get_nvlist_array(nvl, key, &num_items); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE(num_items == nitems(testnvl)); for (i = 0; i < num_items; i++) { ATF_REQUIRE_EQ(nvlist_error(const_result[i]), 0); if (i < num_items - 1) { ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == const_result[i + 1]); } else { ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == NULL); } ATF_REQUIRE(nvlist_get_parent(const_result[i], NULL) == nvl); ATF_REQUIRE(nvlist_in_array(const_result[i])); ATF_REQUIRE(nvlist_exists_string(const_result[i], "nvl/string")); ATF_REQUIRE(strcmp(nvlist_get_string(const_result[i], "nvl/string"), somestr[i]) == 0); } result = nvlist_take_nvlist_array(nvl, key, &num_items); ATF_REQUIRE(result != NULL); ATF_REQUIRE_EQ(num_items, 8); for (i = 0; i < num_items; i++) { ATF_REQUIRE_EQ(nvlist_error(result[i]), 0); ATF_REQUIRE(nvlist_get_array_next(result[i]) == NULL); ATF_REQUIRE(nvlist_get_parent(result[i], NULL) == NULL); ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == NULL); ATF_REQUIRE(!nvlist_in_array(const_result[i])); } ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); for (i = 0; i < 8; i++) { nvlist_destroy(result[i]); nvlist_destroy(testnvl[i]); } free(result); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone_array); ATF_TEST_CASE_BODY(nvlist_clone_array) { nvlist_t *testnvl[8]; nvlist_t *src, *dst; const nvlist_t *nvl; bool testbool[16]; int testfd[16]; size_t i, num_items; const char *string_arr[8] = { "a", "b", "kot", "foo", "tests", "nice test", "", "abcdef" }; const char *somestr[8] = { "a", "b", "c", "d", "e", "f", "g", "h" }; const uint64_t number[8] = { 0, UINT_MAX, 7, 123, 90, 100000, 8, 1 }; for (i = 0; i < nitems(testfd); i++) { testbool[i] = (i % 2 == 0); testfd[i] = dup(STDERR_FILENO); ATF_REQUIRE(fd_is_valid(testfd[i])); } for (i = 0; i < nitems(testnvl); i++) { testnvl[i] = nvlist_create(0); ATF_REQUIRE(nvlist_error(testnvl[i]) == 0); nvlist_add_string(testnvl[i], "nvl/nvl/teststr", somestr[i]); ATF_REQUIRE(nvlist_error(testnvl[i]) == 0); } src = nvlist_create(0); ATF_REQUIRE(nvlist_error(src) == 0); ATF_REQUIRE(!nvlist_exists_bool_array(src, "nvl/bool")); nvlist_add_bool_array(src, "nvl/bool", testbool, nitems(testbool)); ATF_REQUIRE_EQ(nvlist_error(src), 0); ATF_REQUIRE(nvlist_exists_bool_array(src, "nvl/bool")); ATF_REQUIRE(!nvlist_exists_string_array(src, "nvl/string")); nvlist_add_string_array(src, "nvl/string", string_arr, nitems(string_arr)); ATF_REQUIRE_EQ(nvlist_error(src), 0); ATF_REQUIRE(nvlist_exists_string_array(src, "nvl/string")); ATF_REQUIRE(!nvlist_exists_descriptor_array(src, "nvl/fd")); nvlist_add_descriptor_array(src, "nvl/fd", testfd, nitems(testfd)); ATF_REQUIRE_EQ(nvlist_error(src), 0); ATF_REQUIRE(nvlist_exists_descriptor_array(src, "nvl/fd")); ATF_REQUIRE(!nvlist_exists_number_array(src, "nvl/number")); nvlist_add_number_array(src, "nvl/number", number, nitems(number)); ATF_REQUIRE_EQ(nvlist_error(src), 0); ATF_REQUIRE(nvlist_exists_number_array(src, "nvl/number")); ATF_REQUIRE(!nvlist_exists_nvlist_array(src, "nvl/array")); nvlist_add_nvlist_array(src, "nvl/array", (const nvlist_t * const *)testnvl, nitems(testnvl)); ATF_REQUIRE_EQ(nvlist_error(src), 0); ATF_REQUIRE(nvlist_exists_nvlist_array(src, "nvl/array")); dst = nvlist_clone(src); ATF_REQUIRE(dst != NULL); ATF_REQUIRE(nvlist_exists_bool_array(dst, "nvl/bool")); (void) nvlist_get_bool_array(dst, "nvl/bool", &num_items); ATF_REQUIRE_EQ(num_items, nitems(testbool)); for (i = 0; i < num_items; i++) { ATF_REQUIRE( nvlist_get_bool_array(dst, "nvl/bool", &num_items)[i] == nvlist_get_bool_array(src, "nvl/bool", &num_items)[i]); } ATF_REQUIRE(nvlist_exists_string_array(dst, "nvl/string")); (void) nvlist_get_string_array(dst, "nvl/string", &num_items); ATF_REQUIRE_EQ(num_items, nitems(string_arr)); for (i = 0; i < num_items; i++) { if (nvlist_get_string_array(dst, "nvl/string", &num_items)[i] == NULL) { ATF_REQUIRE(nvlist_get_string_array(dst, "nvl/string", &num_items)[i] == nvlist_get_string_array(src, "nvl/string", &num_items)[i]); } else { ATF_REQUIRE(strcmp(nvlist_get_string_array(dst, "nvl/string", &num_items)[i], nvlist_get_string_array( src, "nvl/string", &num_items)[i]) == 0); } } ATF_REQUIRE(nvlist_exists_descriptor_array(dst, "nvl/fd")); (void) nvlist_get_descriptor_array(dst, "nvl/fd", &num_items); ATF_REQUIRE_EQ(num_items, nitems(testfd)); for (i = 0; i < num_items; i++) { ATF_REQUIRE(fd_is_valid( nvlist_get_descriptor_array(dst, "nvl/fd", &num_items)[i])); } ATF_REQUIRE(nvlist_exists_number_array(dst, "nvl/number")); (void) nvlist_get_number_array(dst, "nvl/number", &num_items); ATF_REQUIRE_EQ(num_items, nitems(number)); for (i = 0; i < num_items; i++) { ATF_REQUIRE( nvlist_get_number_array(dst, "nvl/number", &num_items)[i] == nvlist_get_number_array(src, "nvl/number", &num_items)[i]); } ATF_REQUIRE(nvlist_exists_nvlist_array(dst, "nvl/array")); (void) nvlist_get_nvlist_array(dst, "nvl/array", &num_items); ATF_REQUIRE_EQ(num_items, nitems(testnvl)); for (i = 0; i < num_items; i++) { nvl = nvlist_get_nvlist_array(dst, "nvl/array", &num_items)[i]; ATF_REQUIRE(nvlist_exists_string(nvl, "nvl/nvl/teststr")); ATF_REQUIRE(strcmp(nvlist_get_string(nvl, "nvl/nvl/teststr"), somestr[i]) == 0); } for (i = 0; i < nitems(testfd); i++) { close(testfd[i]); } for (i = 0; i < nitems(testnvl); i++) { nvlist_destroy(testnvl[i]); } nvlist_destroy(src); nvlist_destroy(dst); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_bool_array__move); ATF_TEST_CASE_BODY(nvlist_bool_array__move) { bool *testbool; const bool *const_result; nvlist_t *nvl; size_t num_items, count; unsigned int i; const char *key; key = "nvl/bool"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); count = 16; testbool = (bool*)malloc(sizeof(*testbool) * count); ATF_REQUIRE(testbool != NULL); for (i = 0; i < count; i++) testbool[i] = (i % 2 == 0); nvlist_move_bool_array(nvl, key, testbool, count); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_bool_array(nvl, key)); const_result = nvlist_get_bool_array(nvl, key, &num_items); ATF_REQUIRE_EQ(num_items, count); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE(const_result == testbool); for (i = 0; i < num_items; i++) ATF_REQUIRE_EQ(const_result[i], (i % 2 == 0)); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array__move); ATF_TEST_CASE_BODY(nvlist_string_array__move) { char **teststr; const char * const *const_result; nvlist_t *nvl; size_t num_items, count; unsigned int i; const char *key; key = "nvl/string"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); count = 26; teststr = (char**)malloc(sizeof(*teststr) * count); ATF_REQUIRE(teststr != NULL); for (i = 0; i < count; i++) { teststr[i] = (char*)malloc(sizeof(**teststr) * 2); ATF_REQUIRE(teststr[i] != NULL); teststr[i][0] = 'a' + i; teststr[i][1] = '\0'; } nvlist_move_string_array(nvl, key, teststr, count); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_string_array(nvl, key)); const_result = nvlist_get_string_array(nvl, key, &num_items); ATF_REQUIRE_EQ(num_items, count); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE((intptr_t)const_result == (intptr_t)teststr); for (i = 0; i < num_items; i++) { ATF_REQUIRE_EQ(const_result[i][0], (char)('a' + i)); ATF_REQUIRE_EQ(const_result[i][1], '\0'); } nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__move); ATF_TEST_CASE_BODY(nvlist_nvlist_array__move) { nvlist **testnv; const nvlist * const *const_result; nvlist_t *nvl; size_t num_items, count; unsigned int i; const char *key; key = "nvl/nvlist"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_nvlist_array(nvl, key)); count = 26; testnv = (nvlist**)malloc(sizeof(*testnv) * count); ATF_REQUIRE(testnv != NULL); for (i = 0; i < count; i++) { testnv[i] = nvlist_create(0); ATF_REQUIRE(testnv[i] != NULL); } nvlist_move_nvlist_array(nvl, key, testnv, count); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, key)); const_result = nvlist_get_nvlist_array(nvl, key, &num_items); ATF_REQUIRE_EQ(num_items, count); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE((intptr_t)const_result == (intptr_t)testnv); for (i = 0; i < num_items; i++) { ATF_REQUIRE_EQ(nvlist_error(const_result[i]), 0); ATF_REQUIRE(nvlist_empty(const_result[i])); if (i < num_items - 1) { ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == const_result[i + 1]); } else { ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == NULL); } ATF_REQUIRE(nvlist_get_parent(const_result[i], NULL) == nvl); ATF_REQUIRE(nvlist_in_array(const_result[i])); } nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_number_array__move); ATF_TEST_CASE_BODY(nvlist_number_array__move) { uint64_t *testnumber; const uint64_t *const_result; nvlist_t *nvl; size_t num_items, count; unsigned int i; const char *key; key = "nvl/number"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); count = 1000; testnumber = (uint64_t*)malloc(sizeof(*testnumber) * count); ATF_REQUIRE(testnumber != NULL); for (i = 0; i < count; i++) testnumber[i] = i; nvlist_move_number_array(nvl, key, testnumber, count); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_number_array(nvl, key)); const_result = nvlist_get_number_array(nvl, key, &num_items); ATF_REQUIRE_EQ(num_items, count); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE(const_result == testnumber); for (i = 0; i < num_items; i++) ATF_REQUIRE_EQ(const_result[i], i); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_descriptor_array__move); ATF_TEST_CASE_BODY(nvlist_descriptor_array__move) { int *testfd; const int *const_result; nvlist_t *nvl; size_t num_items, count; unsigned int i; const char *key; key = "nvl/fd"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); count = 50; testfd = (int*)malloc(sizeof(*testfd) * count); ATF_REQUIRE(testfd != NULL); for (i = 0; i < count; i++) { testfd[i] = dup(STDERR_FILENO); ATF_REQUIRE(fd_is_valid(testfd[i])); } nvlist_move_descriptor_array(nvl, key, testfd, count); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key)); const_result = nvlist_get_descriptor_array(nvl, key, &num_items); ATF_REQUIRE_EQ(num_items, count); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE(const_result == testfd); for (i = 0; i < num_items; i++) ATF_REQUIRE(fd_is_valid(const_result[i])); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_arrays__error_null); ATF_TEST_CASE_BODY(nvlist_arrays__error_null) { nvlist_t *nvl; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_add_number_array(nvl, "nvl/number", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_move_number_array(nvl, "nvl/number", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_add_descriptor_array(nvl, "nvl/fd", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_move_descriptor_array(nvl, "nvl/fd", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_add_string_array(nvl, "nvl/string", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_move_string_array(nvl, "nvl/string", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_add_nvlist_array(nvl, "nvl/nvlist", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_move_nvlist_array(nvl, "nvl/nvlist", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_add_bool_array(nvl, "nvl/bool", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_move_bool_array(nvl, "nvl/bool", NULL, 0); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_arrays__bad_value); ATF_TEST_CASE_BODY(nvlist_arrays__bad_value) { nvlist_t *nvl, *nvladd[1], **nvlmove; int fdadd[1], *fdmove; nvladd[0] = NULL; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_add_nvlist_array(nvl, "nvl/nvlist", nvladd, 1); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); nvlmove = (nvlist_t**)malloc(sizeof(*nvlmove)); ATF_REQUIRE(nvlmove != NULL); nvlmove[0] = NULL; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_move_nvlist_array(nvl, "nvl/nvlist", nvlmove, 1); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); fdadd[0] = -2; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_add_descriptor_array(nvl, "nvl/fd", fdadd, 1); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); fdmove = (int*)malloc(sizeof(*fdmove)); ATF_REQUIRE(fdmove != NULL); fdmove[0] = -2; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_move_descriptor_array(nvl, "nvl/fd", fdmove, 1); ATF_REQUIRE(nvlist_error(nvl) != 0); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__travel); ATF_TEST_CASE_BODY(nvlist_nvlist_array__travel) { nvlist_t *nvl, *test[5], *nasted; const nvlist_t *travel; const char *name; void *cookie; int type; unsigned int i, index; for (i = 0; i < nitems(test); i++) { test[i] = nvlist_create(0); ATF_REQUIRE(test[i] != NULL); nvlist_add_number(test[i], "nvl/number", i); ATF_REQUIRE(nvlist_error(test[i]) == 0); } nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_add_nvlist_array(nvl, "nvl/nvlist_array", test, nitems(test)); ATF_REQUIRE(nvlist_error(nvl) == 0); nasted = nvlist_create(0); ATF_REQUIRE(nasted != NULL); nvlist_add_nvlist_array(nasted, "nvl/nvl/nvlist_array", test, nitems(test)); ATF_REQUIRE(nvlist_error(nasted) == 0); nvlist_move_nvlist(nvl, "nvl/nvl", nasted); ATF_REQUIRE(nvlist_error(nvl) == 0); nvlist_add_string(nvl, "nvl/string", "END"); ATF_REQUIRE(nvlist_error(nvl) == 0); cookie = NULL; index = 0; travel = nvl; do { while ((name = nvlist_next(travel, &type, &cookie)) != NULL) { if (index == 0) { ATF_REQUIRE(type == NV_TYPE_NVLIST_ARRAY); } else if (index >= 1 && index <= nitems(test)) { ATF_REQUIRE(type == NV_TYPE_NUMBER); } else if (index == nitems(test) + 1) { ATF_REQUIRE(type == NV_TYPE_NVLIST); } else if (index == nitems(test) + 2) { ATF_REQUIRE(type == NV_TYPE_NVLIST_ARRAY); } else if (index >= nitems(test) + 3 && index <= 2 * nitems(test) + 2) { ATF_REQUIRE(type == NV_TYPE_NUMBER); } else if (index == 2 * nitems(test) + 3) { ATF_REQUIRE(type == NV_TYPE_STRING); } if (type == NV_TYPE_NVLIST) { travel = nvlist_get_nvlist(travel, name); cookie = NULL; } else if (type == NV_TYPE_NVLIST_ARRAY) { travel = nvlist_get_nvlist_array(travel, name, NULL)[0]; cookie = NULL; } index ++; } } while ((travel = nvlist_get_pararr(travel, &cookie)) != NULL); for (i = 0; i < nitems(test); i++) nvlist_destroy(test[i]); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__travel_alternative); ATF_TEST_CASE_BODY(nvlist_nvlist_array__travel_alternative) { nvlist_t *nvl, *test[5], *nasted; const nvlist_t *travel, *tmp; void *cookie; int index, i, type; const char *name; for (i = 0; i < 5; i++) { test[i] = nvlist_create(0); ATF_REQUIRE(test[i] != NULL); nvlist_add_number(test[i], "nvl/number", i); ATF_REQUIRE(nvlist_error(test[i]) == 0); } nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); nvlist_add_nvlist_array(nvl, "nvl/nvlist_array", test, 5); ATF_REQUIRE(nvlist_error(nvl) == 0); nasted = nvlist_create(0); ATF_REQUIRE(nasted != NULL); nvlist_add_nvlist_array(nasted, "nvl/nvl/nvlist_array", test, 5); ATF_REQUIRE(nvlist_error(nasted) == 0); nvlist_move_nvlist(nvl, "nvl/nvl", nasted); ATF_REQUIRE(nvlist_error(nvl) == 0); nvlist_add_string(nvl, "nvl/string", "END"); ATF_REQUIRE(nvlist_error(nvl) == 0); cookie = NULL; index = 0; tmp = travel = nvl; do { do { travel = tmp; while ((name = nvlist_next(travel, &type, &cookie)) != NULL) { if (index == 0) { ATF_REQUIRE(type == NV_TYPE_NVLIST_ARRAY); } else if (index >= 1 && index <= 5) { ATF_REQUIRE(type == NV_TYPE_NUMBER); } else if (index == 6) { ATF_REQUIRE(type == NV_TYPE_NVLIST); } else if (index == 7) { ATF_REQUIRE(type == NV_TYPE_NVLIST_ARRAY); } else if (index >= 8 && index <= 12) { ATF_REQUIRE(type == NV_TYPE_NUMBER); } else if (index == 13) { ATF_REQUIRE(type == NV_TYPE_STRING); } if (type == NV_TYPE_NVLIST) { travel = nvlist_get_nvlist(travel, name); cookie = NULL; } else if (type == NV_TYPE_NVLIST_ARRAY) { travel = nvlist_get_nvlist_array(travel, name, NULL)[0]; cookie = NULL; } index ++; } cookie = NULL; } while ((tmp = nvlist_get_array_next(travel)) != NULL); } while ((tmp = nvlist_get_parent(travel, &cookie)) != NULL); for (i = 0; i < 5; i++) nvlist_destroy(test[i]); nvlist_destroy(nvl); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_bool_array__pack); ATF_TEST_CASE_BODY(nvlist_bool_array__pack) { nvlist_t *nvl, *unpacked; const char *key; size_t packed_size, count; void *packed; unsigned int i; const bool *const_result; bool testbool[16]; for (i = 0; i < nitems(testbool); i++) testbool[i] = (i % 2 == 0); key = "nvl/bool"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); nvlist_add_bool_array(nvl, key, testbool, nitems(testbool)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_bool_array(nvl, key)); packed = nvlist_pack(nvl, &packed_size); ATF_REQUIRE(packed != NULL); unpacked = nvlist_unpack(packed, packed_size, 0); ATF_REQUIRE(unpacked != NULL); ATF_REQUIRE_EQ(nvlist_error(unpacked), 0); ATF_REQUIRE(nvlist_exists_bool_array(unpacked, key)); const_result = nvlist_get_bool_array(unpacked, key, &count); ATF_REQUIRE_EQ(count, nitems(testbool)); for (i = 0; i < count; i++) { ATF_REQUIRE_EQ(testbool[i], const_result[i]); } nvlist_destroy(nvl); nvlist_destroy(unpacked); free(packed); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_number_array__pack); ATF_TEST_CASE_BODY(nvlist_number_array__pack) { nvlist_t *nvl, *unpacked; const char *key; size_t packed_size, count; void *packed; unsigned int i; const uint64_t *const_result; const uint64_t number[8] = { 0, UINT_MAX, 7, 123, 90, 100000, 8, 1 }; key = "nvl/number"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); nvlist_add_number_array(nvl, key, number, 8); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_number_array(nvl, key)); packed = nvlist_pack(nvl, &packed_size); ATF_REQUIRE(packed != NULL); unpacked = nvlist_unpack(packed, packed_size, 0); ATF_REQUIRE(unpacked != NULL); ATF_REQUIRE_EQ(nvlist_error(unpacked), 0); ATF_REQUIRE(nvlist_exists_number_array(unpacked, key)); const_result = nvlist_get_number_array(unpacked, key, &count); ATF_REQUIRE_EQ(count, nitems(number)); for (i = 0; i < count; i++) { ATF_REQUIRE_EQ(number[i], const_result[i]); } nvlist_destroy(nvl); nvlist_destroy(unpacked); free(packed); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_descriptor_array__pack); ATF_TEST_CASE_BODY(nvlist_descriptor_array__pack) { nvlist_t *nvl; const char *key; size_t num_items; unsigned int i; const int *const_result; int desc[32], fd, socks[2]; pid_t pid; key = "nvl/descriptor"; ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0); pid = atf::utils::fork(); ATF_REQUIRE(pid >= 0); if (pid == 0) { /* Child. */ fd = socks[0]; close(socks[1]); for (i = 0; i < nitems(desc); i++) { desc[i] = dup(STDERR_FILENO); ATF_REQUIRE(fd_is_valid(desc[i])); } nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_descriptor_array(nvl, key)); nvlist_add_descriptor_array(nvl, key, desc, nitems(desc)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key)); ATF_REQUIRE(nvlist_send(fd, nvl) >= 0); for (i = 0; i < nitems(desc); i++) close(desc[i]); } else { /* Parent */ fd = socks[1]; close(socks[0]); errno = 0; nvl = nvlist_recv(fd, 0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key)); const_result = nvlist_get_descriptor_array(nvl, key, &num_items); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE_EQ(num_items, nitems(desc)); for (i = 0; i < num_items; i++) ATF_REQUIRE(fd_is_valid(const_result[i])); atf::utils::wait(pid, 0, "", ""); } nvlist_destroy(nvl); close(fd); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array__pack); ATF_TEST_CASE_BODY(nvlist_string_array__pack) { nvlist_t *nvl, *unpacked; const char *key; size_t packed_size, count; void *packed; unsigned int i; const char * const *const_result; const char *string_arr[8] = { "a", "b", "kot", "foo", "tests", "nice test", "", "abcdef" }; key = "nvl/string"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); nvlist_add_string_array(nvl, key, string_arr, nitems(string_arr)); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_string_array(nvl, key)); packed = nvlist_pack(nvl, &packed_size); ATF_REQUIRE(packed != NULL); unpacked = nvlist_unpack(packed, packed_size, 0); ATF_REQUIRE(unpacked != NULL); ATF_REQUIRE_EQ(nvlist_error(unpacked), 0); ATF_REQUIRE(nvlist_exists_string_array(unpacked, key)); const_result = nvlist_get_string_array(unpacked, key, &count); ATF_REQUIRE_EQ(count, nitems(string_arr)); for (i = 0; i < count; i++) { ATF_REQUIRE_EQ(strcmp(string_arr[i], const_result[i]), 0); } nvlist_destroy(nvl); nvlist_destroy(unpacked); free(packed); } ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__pack); ATF_TEST_CASE_BODY(nvlist_nvlist_array__pack) { nvlist_t *testnvl[8], *unpacked; const nvlist_t * const *const_result; nvlist_t *nvl; size_t num_items, packed_size; unsigned int i; void *packed; const char *somestr[8] = { "a", "b", "c", "d", "e", "f", "g", "h" }; const char *key; for (i = 0; i < nitems(testnvl); i++) { testnvl[i] = nvlist_create(0); ATF_REQUIRE(testnvl[i] != NULL); ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0); nvlist_add_string(testnvl[i], "nvl/string", somestr[i]); ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0); ATF_REQUIRE(nvlist_exists_string(testnvl[i], "nvl/string")); } key = "nvl/nvlist"; nvl = nvlist_create(0); ATF_REQUIRE(nvl != NULL); ATF_REQUIRE(nvlist_empty(nvl)); ATF_REQUIRE(!nvlist_exists_string_array(nvl, key)); nvlist_add_nvlist_array(nvl, key, (const nvlist_t * const *)testnvl, 8); ATF_REQUIRE_EQ(nvlist_error(nvl), 0); ATF_REQUIRE(!nvlist_empty(nvl)); ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, key)); ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, "nvl/nvlist")); packed = nvlist_pack(nvl, &packed_size); ATF_REQUIRE(packed != NULL); unpacked = nvlist_unpack(packed, packed_size, 0); ATF_REQUIRE(unpacked != NULL); ATF_REQUIRE_EQ(nvlist_error(unpacked), 0); ATF_REQUIRE(nvlist_exists_nvlist_array(unpacked, key)); const_result = nvlist_get_nvlist_array(unpacked, key, &num_items); ATF_REQUIRE(const_result != NULL); ATF_REQUIRE_EQ(num_items, nitems(testnvl)); for (i = 0; i < num_items; i++) { ATF_REQUIRE_EQ(nvlist_error(const_result[i]), 0); if (i < num_items - 1) { ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == const_result[i + 1]); } else { ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == NULL); } ATF_REQUIRE(nvlist_get_parent(const_result[i], NULL) == unpacked); ATF_REQUIRE(nvlist_in_array(const_result[i])); ATF_REQUIRE(nvlist_exists_string(const_result[i], "nvl/string")); ATF_REQUIRE(strcmp(nvlist_get_string(const_result[i], "nvl/string"), somestr[i]) == 0); } for (i = 0; i < nitems(testnvl); i++) nvlist_destroy(testnvl[i]); nvlist_destroy(nvl); nvlist_destroy(unpacked); free(packed); } + +ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array_nonull__pack); +ATF_TEST_CASE_BODY(nvlist_string_array_nonull__pack) +{ + nvlist_t *testnvl, *unpacked; + const char *somestr[3] = { "a", "b", "XXX" }; + uint8_t *packed, *twopages, *dataptr, *secondpage; + size_t packed_size, page_size; + bool found; + + page_size = sysconf(_SC_PAGESIZE); + testnvl = nvlist_create(0); + ATF_REQUIRE(testnvl != NULL); + ATF_REQUIRE_EQ(nvlist_error(testnvl), 0); + nvlist_add_string_array(testnvl, "nvl/string", somestr, + nitems(somestr)); + ATF_REQUIRE_EQ(nvlist_error(testnvl), 0); + + packed = (uint8_t *)nvlist_pack(testnvl, &packed_size); + ATF_REQUIRE(packed != NULL); + + twopages = (uint8_t *)mmap(NULL, page_size * 2, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ATF_REQUIRE(twopages != MAP_FAILED); + dataptr = &twopages[page_size - packed_size]; + secondpage = &twopages[page_size]; + + memset(twopages, 'A', page_size * 2); + + mprotect(secondpage, page_size, PROT_NONE); + memcpy(dataptr, packed, packed_size); + + found = false; + for (size_t i = 0; i < packed_size - 3; i++) { + if (dataptr[i] == 'X' && dataptr[i + 1] == 'X' && + dataptr[i + 2] == 'X' && dataptr[i + 3] == '\0') { + dataptr[i + 3] = 'X'; + found = true; + break; + } + } + ATF_REQUIRE(found == true); + + unpacked = nvlist_unpack(dataptr, packed_size, 0); + ATF_REQUIRE(unpacked == NULL); + + nvlist_destroy(testnvl); + free(packed); + munmap(twopages, page_size * 2); +} + + ATF_INIT_TEST_CASES(tp) { ATF_ADD_TEST_CASE(tp, nvlist_bool_array__basic); ATF_ADD_TEST_CASE(tp, nvlist_string_array__basic); ATF_ADD_TEST_CASE(tp, nvlist_descriptor_array__basic); ATF_ADD_TEST_CASE(tp, nvlist_number_array__basic); ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__basic) ATF_ADD_TEST_CASE(tp, nvlist_clone_array) ATF_ADD_TEST_CASE(tp, nvlist_bool_array__move); ATF_ADD_TEST_CASE(tp, nvlist_string_array__move); ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__move); ATF_ADD_TEST_CASE(tp, nvlist_number_array__move); ATF_ADD_TEST_CASE(tp, nvlist_descriptor_array__move); ATF_ADD_TEST_CASE(tp, nvlist_arrays__error_null); ATF_ADD_TEST_CASE(tp, nvlist_arrays__bad_value) ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__travel) ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__travel_alternative) ATF_ADD_TEST_CASE(tp, nvlist_bool_array__pack) ATF_ADD_TEST_CASE(tp, nvlist_number_array__pack) ATF_ADD_TEST_CASE(tp, nvlist_descriptor_array__pack) ATF_ADD_TEST_CASE(tp, nvlist_string_array__pack) ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__pack) + + ATF_ADD_TEST_CASE(tp, nvlist_string_array_nonull__pack) }