summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2016-01-07 18:08:08 -0200
committerRenato Botelho <renato@netgate.com>2016-01-07 18:08:08 -0200
commit7a579754077b3460c9509c75cdd1b78769c1db3f (patch)
treec15015685ccb82b7db1ac19d663a3c6e41e64587 /lib
parentd8ff3484131f428fcc0727cd504acb5050a36490 (diff)
parentbc6ee646001a22150936ff06bf11cd08195e208d (diff)
downloadFreeBSD-src-7a579754077b3460c9509c75cdd1b78769c1db3f.zip
FreeBSD-src-7a579754077b3460c9509c75cdd1b78769c1db3f.tar.gz
Merge remote-tracking branch 'origin/stable/10' into devel
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile1
-rw-r--r--lib/libbsm/Makefile4
-rw-r--r--lib/libc/net/gethostbynis.c55
-rw-r--r--lib/libc/net/netdb_private.h2
-rw-r--r--lib/libnv/Makefile92
-rw-r--r--lib/libnv/common_impl.h37
-rw-r--r--lib/libnv/msgio.c469
-rw-r--r--lib/libnv/msgio.h50
-rw-r--r--lib/libnv/nv.3653
-rw-r--r--lib/libnv/tests/Makefile21
-rw-r--r--lib/libnv/tests/dnv_tests.cc567
-rw-r--r--lib/libnv/tests/nv_tests.cc1240
-rw-r--r--lib/libnv/tests/nvlist_add_test.c196
-rw-r--r--lib/libnv/tests/nvlist_exists_test.c321
-rw-r--r--lib/libnv/tests/nvlist_free_test.c221
-rw-r--r--lib/libnv/tests/nvlist_get_test.c182
-rw-r--r--lib/libnv/tests/nvlist_move_test.c161
-rw-r--r--lib/libnv/tests/nvlist_send_recv_test.c342
-rw-r--r--lib/msun/tests/Makefile22
-rw-r--r--lib/msun/tests/cexp_test.c322
-rw-r--r--lib/msun/tests/conj_test.c139
-rw-r--r--lib/msun/tests/csqrt_test.c295
-rw-r--r--lib/msun/tests/fenv_test.c576
-rw-r--r--lib/msun/tests/fmaxmin_test.c136
-rw-r--r--lib/msun/tests/ilogb_test.c83
-rw-r--r--lib/msun/tests/invctrig_test.c367
-rw-r--r--lib/msun/tests/logarithm_test.c286
-rw-r--r--lib/msun/tests/lrint_test.c149
-rw-r--r--lib/msun/tests/nan_test.c122
-rw-r--r--lib/msun/tests/nearbyint_test.c176
-rw-r--r--lib/msun/tests/next_test.c265
-rw-r--r--lib/msun/tests/rem_test.c207
-rw-r--r--lib/msun/tests/trig_test.c280
33 files changed, 7982 insertions, 57 deletions
diff --git a/lib/Makefile b/lib/Makefile
index ee83d59..250d583 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -70,6 +70,7 @@ SUBDIR= ${SUBDIR_ORDERED} \
libnetbsd \
${_libnetgraph} \
${_libngatm} \
+ libnv \
libopie \
libpam \
libpcap \
diff --git a/lib/libbsm/Makefile b/lib/libbsm/Makefile
index eec2c40..2e0dbe1 100644
--- a/lib/libbsm/Makefile
+++ b/lib/libbsm/Makefile
@@ -48,6 +48,7 @@ MAN= libbsm.3 \
au_free_token.3 \
au_io.3 \
au_mask.3 \
+ au_notify.3 \
au_open.3 \
au_socket_type.3 \
au_token.3 \
@@ -112,6 +113,9 @@ MLINKS= libbsm.3 bsm.3 \
au_mask.3 au_preselect.3 \
au_mask.3 getauditflagsbin.3 \
au_mask.3 getauditflagschar.3 \
+ au_notify.3 au_get_state.3 \
+ au_notify.3 au_notify_initialize.3 \
+ au_notify.3 au_notify_terminate.3 \
au_open.3 au_close.3 \
au_open.3 au_close_buffer.3 \
au_open.3 au_close_token.3 \
diff --git a/lib/libc/net/gethostbynis.c b/lib/libc/net/gethostbynis.c
index c0d5177..6bafdb1 100644
--- a/lib/libc/net/gethostbynis.c
+++ b/lib/libc/net/gethostbynis.c
@@ -198,61 +198,6 @@ _gethostbynisaddr_r(const void *addr, socklen_t len, int af,
}
#endif /* YP */
-/* XXX _gethostbynisname/_gethostbynisaddr only used by getipnodeby*() */
-struct hostent *
-_gethostbynisname(const char *name, int af)
-{
-#ifdef YP
- struct hostent *he;
- struct hostent_data *hed;
- u_long oresopt;
- int error;
- res_state statp;
-
- statp = __res_state();
- if ((he = __hostent_init()) == NULL ||
- (hed = __hostent_data_init()) == NULL) {
- RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
- return (NULL);
- }
-
- oresopt = statp->options;
- statp->options &= ~RES_USE_INET6;
- error = _gethostbynisname_r(name, af, he, hed);
- statp->options = oresopt;
- return (error == 0) ? he : NULL;
-#else
- return (NULL);
-#endif
-}
-
-struct hostent *
-_gethostbynisaddr(const void *addr, socklen_t len, int af)
-{
-#ifdef YP
- struct hostent *he;
- struct hostent_data *hed;
- u_long oresopt;
- int error;
- res_state statp;
-
- statp = __res_state();
- if ((he = __hostent_init()) == NULL ||
- (hed = __hostent_data_init()) == NULL) {
- RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
- return (NULL);
- }
-
- oresopt = statp->options;
- statp->options &= ~RES_USE_INET6;
- error = _gethostbynisaddr_r(addr, len, af, he, hed);
- statp->options = oresopt;
- return (error == 0) ? he : NULL;
-#else
- return (NULL);
-#endif
-}
-
int
_nis_gethostbyname(void *rval, void *cb_data, va_list ap)
{
diff --git a/lib/libc/net/netdb_private.h b/lib/libc/net/netdb_private.h
index b48dd7b..4ed598c 100644
--- a/lib/libc/net/netdb_private.h
+++ b/lib/libc/net/netdb_private.h
@@ -133,8 +133,6 @@ void _endhostdnsent(void);
void _endhosthtent(struct hostent_data *);
void _endnetdnsent(void);
void _endnethtent(struct netent_data *);
-struct hostent *_gethostbynisaddr(const void *, socklen_t, int);
-struct hostent *_gethostbynisname(const char *, int);
void _map_v4v6_address(const char *, char *);
void _map_v4v6_hostent(struct hostent *, char **, char *);
void _sethostdnsent(int);
diff --git a/lib/libnv/Makefile b/lib/libnv/Makefile
new file mode 100644
index 0000000..47dfe04
--- /dev/null
+++ b/lib/libnv/Makefile
@@ -0,0 +1,92 @@
+# $FreeBSD$
+
+SHLIBDIR?= /lib
+
+.include <bsd.own.mk>
+
+LIB= nv
+SHLIB_MAJOR= 0
+
+.PATH: ${.CURDIR}/../../sys/kern ${.CURDIR}/../../sys/sys
+CFLAGS+=-I${.CURDIR}/../../sys -I${.CURDIR}
+
+SRCS= subr_dnvlist.c
+SRCS+= msgio.c
+SRCS+= subr_nvlist.c
+SRCS+= subr_nvpair.c
+
+INCS= dnv.h
+INCS+= nv.h
+
+MAN+= nv.3
+
+MLINKS+=nv.3 libnv.3 \
+ nv.3 nvlist.3
+MLINKS+=nv.3 nvlist_add_binary.3 \
+ nv.3 nvlist_add_bool.3 \
+ nv.3 nvlist_add_descriptor.3 \
+ nv.3 nvlist_add_null.3 \
+ nv.3 nvlist_add_number.3 \
+ nv.3 nvlist_add_nvlist.3 \
+ nv.3 nvlist_add_string.3 \
+ nv.3 nvlist_add_stringf.3 \
+ nv.3 nvlist_add_stringv.3 \
+ nv.3 nvlist_clone.3 \
+ nv.3 nvlist_create.3 \
+ nv.3 nvlist_destroy.3 \
+ nv.3 nvlist_dump.3 \
+ nv.3 nvlist_empty.3 \
+ nv.3 nvlist_error.3 \
+ nv.3 nvlist_exists.3 \
+ nv.3 nvlist_exists_binary.3 \
+ nv.3 nvlist_exists_bool.3 \
+ nv.3 nvlist_exists_descriptor.3 \
+ nv.3 nvlist_exists_null.3 \
+ nv.3 nvlist_exists_number.3 \
+ nv.3 nvlist_exists_nvlist.3 \
+ nv.3 nvlist_exists_string.3 \
+ nv.3 nvlist_exists_type.3 \
+ nv.3 nvlist_fdump.3 \
+ nv.3 nvlist_flags.3 \
+ nv.3 nvlist_free.3 \
+ nv.3 nvlist_free_binary.3 \
+ nv.3 nvlist_free_bool.3 \
+ nv.3 nvlist_free_descriptor.3 \
+ nv.3 nvlist_free_null.3 \
+ nv.3 nvlist_free_number.3 \
+ nv.3 nvlist_free_nvlist.3 \
+ nv.3 nvlist_free_string.3 \
+ nv.3 nvlist_free_type.3 \
+ nv.3 nvlist_get_binary.3 \
+ nv.3 nvlist_get_bool.3 \
+ nv.3 nvlist_get_descriptor.3 \
+ nv.3 nvlist_get_number.3 \
+ nv.3 nvlist_get_nvlist.3 \
+ nv.3 nvlist_get_parent.3 \
+ nv.3 nvlist_get_string.3 \
+ nv.3 nvlist_move_binary.3 \
+ nv.3 nvlist_move_descriptor.3 \
+ nv.3 nvlist_move_nvlist.3 \
+ nv.3 nvlist_move_string.3 \
+ nv.3 nvlist_next.3 \
+ nv.3 nvlist_pack.3 \
+ nv.3 nvlist_recv.3 \
+ nv.3 nvlist_send.3 \
+ nv.3 nvlist_set_error.3 \
+ nv.3 nvlist_size.3 \
+ nv.3 nvlist_take_binary.3 \
+ nv.3 nvlist_take_bool.3 \
+ nv.3 nvlist_take_descriptor.3 \
+ nv.3 nvlist_take_number.3 \
+ nv.3 nvlist_take_nvlist.3 \
+ nv.3 nvlist_take_string.3 \
+ nv.3 nvlist_unpack.3 \
+ nv.3 nvlist_xfer.3
+
+WARNS?= 6
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libnv/common_impl.h b/lib/libnv/common_impl.h
new file mode 100644
index 0000000..5af4db2
--- /dev/null
+++ b/lib/libnv/common_impl.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMMON_IMPL_H_
+#define _COMMON_IMPL_H_
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+#endif /* !_COMMON_IMPL_H_ */
diff --git a/lib/libnv/msgio.c b/lib/libnv/msgio.c
new file mode 100644
index 0000000..27620a1
--- /dev/null
+++ b/lib/libnv/msgio.c
@@ -0,0 +1,469 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_PJDLOG
+#include <pjdlog.h>
+#endif
+
+#include "common_impl.h"
+#include "msgio.h"
+
+#ifndef HAVE_PJDLOG
+#include <assert.h>
+#define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) assert(expr)
+#define PJDLOG_ABORT(...) abort()
+#endif
+
+#define PKG_MAX_SIZE (MCLBYTES / CMSG_SPACE(sizeof(int)) - 1)
+
+static int
+msghdr_add_fd(struct cmsghdr *cmsg, int fd)
+{
+
+ PJDLOG_ASSERT(fd >= 0);
+
+ if (!fd_is_valid(fd)) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
+
+ return (0);
+}
+
+static int
+msghdr_get_fd(struct cmsghdr *cmsg)
+{
+ int fd;
+
+ if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET ||
+ cmsg->cmsg_type != SCM_RIGHTS ||
+ cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+#ifndef MSG_CMSG_CLOEXEC
+ /*
+ * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the
+ * close-on-exec flag atomically, but we still want to set it for
+ * consistency.
+ */
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ return (fd);
+}
+
+static void
+fd_wait(int fd, bool doread)
+{
+ fd_set fds;
+
+ PJDLOG_ASSERT(fd >= 0);
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ (void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds,
+ NULL, NULL);
+}
+
+static int
+msg_recv(int sock, struct msghdr *msg)
+{
+ int flags;
+
+ PJDLOG_ASSERT(sock >= 0);
+
+#ifdef MSG_CMSG_CLOEXEC
+ flags = MSG_CMSG_CLOEXEC;
+#else
+ flags = 0;
+#endif
+
+ for (;;) {
+ fd_wait(sock, true);
+ if (recvmsg(sock, msg, flags) == -1) {
+ if (errno == EINTR)
+ continue;
+ return (-1);
+ }
+ break;
+ }
+
+ return (0);
+}
+
+static int
+msg_send(int sock, const struct msghdr *msg)
+{
+
+ PJDLOG_ASSERT(sock >= 0);
+
+ for (;;) {
+ fd_wait(sock, false);
+ if (sendmsg(sock, msg, 0) == -1) {
+ if (errno == EINTR)
+ continue;
+ return (-1);
+ }
+ break;
+ }
+
+ return (0);
+}
+
+int
+cred_send(int sock)
+{
+ unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ uint8_t dummy;
+
+ bzero(credbuf, sizeof(credbuf));
+ bzero(&msg, sizeof(msg));
+ bzero(&iov, sizeof(iov));
+
+ /*
+ * XXX: We send one byte along with the control message, because
+ * setting msg_iov to NULL only works if this is the first
+ * packet send over the socket. Once we send some data we
+ * won't be able to send credentials anymore. This is most
+ * likely a kernel bug.
+ */
+ dummy = 0;
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = credbuf;
+ msg.msg_controllen = sizeof(credbuf);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_CREDS;
+
+ if (msg_send(sock, &msg) == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
+cred_recv(int sock, struct cmsgcred *cred)
+{
+ unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ uint8_t dummy;
+
+ bzero(credbuf, sizeof(credbuf));
+ bzero(&msg, sizeof(msg));
+ bzero(&iov, sizeof(iov));
+
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = credbuf;
+ msg.msg_controllen = sizeof(credbuf);
+
+ if (msg_recv(sock, &msg) == -1)
+ return (-1);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg == NULL ||
+ cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) ||
+ cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred));
+
+ return (0);
+}
+
+static int
+fd_package_send(int sock, const int *fds, size_t nfds)
+{
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ unsigned int i;
+ int serrno, ret;
+ uint8_t dummy;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(fds != NULL);
+ PJDLOG_ASSERT(nfds > 0);
+
+ bzero(&msg, sizeof(msg));
+
+ /*
+ * XXX: Look into cred_send function for more details.
+ */
+ dummy = 0;
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
+ msg.msg_control = calloc(1, msg.msg_controllen);
+ if (msg.msg_control == NULL)
+ return (-1);
+
+ ret = -1;
+
+ for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
+ i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (msghdr_add_fd(cmsg, fds[i]) == -1)
+ goto end;
+ }
+
+ if (msg_send(sock, &msg) == -1)
+ goto end;
+
+ ret = 0;
+end:
+ serrno = errno;
+ free(msg.msg_control);
+ errno = serrno;
+ return (ret);
+}
+
+static int
+fd_package_recv(int sock, int *fds, size_t nfds)
+{
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ unsigned int i;
+ int serrno, ret;
+ struct iovec iov;
+ uint8_t dummy;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(nfds > 0);
+ PJDLOG_ASSERT(fds != NULL);
+
+ i = 0;
+ bzero(&msg, sizeof(msg));
+ bzero(&iov, sizeof(iov));
+
+ /*
+ * XXX: Look into cred_send function for more details.
+ */
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
+ msg.msg_control = calloc(1, msg.msg_controllen);
+ if (msg.msg_control == NULL)
+ return (-1);
+
+ ret = -1;
+
+ if (msg_recv(sock, &msg) == -1)
+ goto end;
+
+ for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
+ i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ fds[i] = msghdr_get_fd(cmsg);
+ if (fds[i] < 0)
+ break;
+ }
+
+ if (cmsg != NULL || i < nfds) {
+ int fd;
+
+ /*
+ * We need to close all received descriptors, even if we have
+ * different control message (eg. SCM_CREDS) in between.
+ */
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ fd = msghdr_get_fd(cmsg);
+ if (fd >= 0)
+ close(fd);
+ }
+ errno = EINVAL;
+ goto end;
+ }
+
+ ret = 0;
+end:
+ serrno = errno;
+ free(msg.msg_control);
+ errno = serrno;
+ return (ret);
+}
+
+int
+fd_recv(int sock, int *fds, size_t nfds)
+{
+ unsigned int i, step, j;
+ int ret, serrno;
+
+ if (nfds == 0 || fds == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ret = i = step = 0;
+ while (i < nfds) {
+ if (PKG_MAX_SIZE < nfds - i)
+ step = PKG_MAX_SIZE;
+ else
+ step = nfds - i;
+ ret = fd_package_recv(sock, fds + i, step);
+ if (ret != 0) {
+ /* Close all received descriptors. */
+ serrno = errno;
+ for (j = 0; j < i; j++)
+ close(fds[j]);
+ errno = serrno;
+ break;
+ }
+ i += step;
+ }
+
+ return (ret);
+}
+
+int
+fd_send(int sock, const int *fds, size_t nfds)
+{
+ unsigned int i, step;
+ int ret;
+
+ if (nfds == 0 || fds == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ret = i = step = 0;
+ while (i < nfds) {
+ if (PKG_MAX_SIZE < nfds - i)
+ step = PKG_MAX_SIZE;
+ else
+ step = nfds - i;
+ ret = fd_package_send(sock, fds + i, step);
+ if (ret != 0)
+ break;
+ i += step;
+ }
+
+ return (ret);
+}
+
+int
+buf_send(int sock, void *buf, size_t size)
+{
+ ssize_t done;
+ unsigned char *ptr;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(size > 0);
+ PJDLOG_ASSERT(buf != NULL);
+
+ ptr = buf;
+ do {
+ fd_wait(sock, false);
+ done = send(sock, ptr, size, 0);
+ if (done == -1) {
+ if (errno == EINTR)
+ continue;
+ return (-1);
+ } else if (done == 0) {
+ errno = ENOTCONN;
+ return (-1);
+ }
+ size -= done;
+ ptr += done;
+ } while (size > 0);
+
+ return (0);
+}
+
+int
+buf_recv(int sock, void *buf, size_t size)
+{
+ ssize_t done;
+ unsigned char *ptr;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(buf != NULL);
+
+ ptr = buf;
+ while (size > 0) {
+ fd_wait(sock, true);
+ done = recv(sock, ptr, size, 0);
+ if (done == -1) {
+ if (errno == EINTR)
+ continue;
+ return (-1);
+ } else if (done == 0) {
+ errno = ENOTCONN;
+ return (-1);
+ }
+ size -= done;
+ ptr += done;
+ }
+
+ return (0);
+}
diff --git a/lib/libnv/msgio.h b/lib/libnv/msgio.h
new file mode 100644
index 0000000..fd5e462
--- /dev/null
+++ b/lib/libnv/msgio.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ *
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MSGIO_H_
+#define _MSGIO_H_
+
+struct cmsgcred;
+struct iovec;
+struct msghdr;
+
+int cred_send(int sock);
+int cred_recv(int sock, struct cmsgcred *cred);
+
+int fd_send(int sock, const int *fds, size_t nfds);
+int fd_recv(int sock, int *fds, size_t nfds);
+
+int buf_send(int sock, void *buf, size_t size);
+int buf_recv(int sock, void *buf, size_t size);
+
+#endif /* !_MSGIO_H_ */
diff --git a/lib/libnv/nv.3 b/lib/libnv/nv.3
new file mode 100644
index 0000000..947bca8
--- /dev/null
+++ b/lib/libnv/nv.3
@@ -0,0 +1,653 @@
+.\"
+.\" Copyright (c) 2013 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Pawel Jakub Dawidek under sponsorship
+.\" the FreeBSD Foundation.
+.\"
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 1, 2015
+.Dt NV 3
+.Os
+.Sh NAME
+.Nm nvlist_create ,
+.Nm nvlist_destroy ,
+.Nm nvlist_error ,
+.Nm nvlist_set_error ,
+.Nm nvlist_empty ,
+.Nm nvlist_flags ,
+.Nm nvlist_exists ,
+.Nm nvlist_free ,
+.Nm nvlist_clone ,
+.Nm nvlist_dump ,
+.Nm nvlist_fdump ,
+.Nm nvlist_size ,
+.Nm nvlist_pack ,
+.Nm nvlist_unpack ,
+.Nm nvlist_send ,
+.Nm nvlist_recv ,
+.Nm nvlist_xfer ,
+.Nm nvlist_next ,
+.Nm nvlist_add ,
+.Nm nvlist_move ,
+.Nm nvlist_get ,
+.Nm nvlist_take
+.Nd "library for name/value pairs"
+.Sh LIBRARY
+.Lb libnv
+.Sh SYNOPSIS
+.In nv.h
+.Ft "nvlist_t *"
+.Fn nvlist_create "int flags"
+.Ft void
+.Fn nvlist_destroy "nvlist_t *nvl"
+.Ft int
+.Fn nvlist_error "const nvlist_t *nvl"
+.Ft void
+.Fn nvlist_set_error "nvlist_t *nvl, int error"
+.Ft bool
+.Fn nvlist_empty "const nvlist_t *nvl"
+.Ft int
+.Fn nvlist_flags "const nvlist_t *nvl"
+.\"
+.Ft "nvlist_t *"
+.Fn nvlist_clone "const nvlist_t *nvl"
+.\"
+.Ft void
+.Fn nvlist_dump "const nvlist_t *nvl, int fd"
+.Ft void
+.Fn nvlist_fdump "const nvlist_t *nvl, FILE *fp"
+.\"
+.Ft size_t
+.Fn nvlist_size "const nvlist_t *nvl"
+.Ft "void *"
+.Fn nvlist_pack "const nvlist_t *nvl" "size_t *sizep"
+.Ft "nvlist_t *"
+.Fn nvlist_unpack "const void *buf" "size_t size"
+.\"
+.Ft int
+.Fn nvlist_send "int sock" "const nvlist_t *nvl"
+.Ft "nvlist_t *"
+.Fn nvlist_recv "int sock"
+.Ft "nvlist_t *"
+.Fn nvlist_xfer "int sock" "nvlist_t *nvl"
+.\"
+.Ft "const char *"
+.Fn nvlist_next "const nvlist_t *nvl" "int *typep" "void **cookiep"
+.\"
+.Ft bool
+.Fn nvlist_exists "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_type "const nvlist_t *nvl" "const char *name" "int type"
+.Ft bool
+.Fn nvlist_exists_null "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_bool "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_number "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_string "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_nvlist "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_descriptor "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_binary "const nvlist_t *nvl" "const char *name"
+.\"
+.Ft void
+.Fn nvlist_add_null "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_add_bool "nvlist_t *nvl" "const char *name" "bool value"
+.Ft void
+.Fn nvlist_add_number "nvlist_t *nvl" "const char *name" "uint64_t value"
+.Ft void
+.Fn nvlist_add_string "nvlist_t *nvl" "const char *name" "const char *value"
+.Ft void
+.Fn nvlist_add_stringf "nvlist_t *nvl" "const char *name" "const char *valuefmt" "..."
+.Ft void
+.Fn nvlist_add_stringv "nvlist_t *nvl" "const char *name" "const char *valuefmt" "va_list valueap"
+.Ft void
+.Fn nvlist_add_nvlist "nvlist_t *nvl" "const char *name" "const nvlist_t *value"
+.Ft void
+.Fn nvlist_add_descriptor "nvlist_t *nvl" "const char *name" "int value"
+.Ft void
+.Fn nvlist_add_binary "nvlist_t *nvl" "const char *name" "const void *value" "size_t size"
+.\"
+.Ft void
+.Fn nvlist_move_string "nvlist_t *nvl" "const char *name" "char *value"
+.Ft void
+.Fn nvlist_move_nvlist "nvlist_t *nvl" "const char *name" "nvlist_t *value"
+.Ft void
+.Fn nvlist_move_descriptor "nvlist_t *nvl" "const char *name" "int value"
+.Ft void
+.Fn nvlist_move_binary "nvlist_t *nvl" "const char *name" "void *value" "size_t size"
+.\"
+.Ft bool
+.Fn nvlist_get_bool "const nvlist_t *nvl" "const char *name"
+.Ft uint64_t
+.Fn nvlist_get_number "const nvlist_t *nvl" "const char *name"
+.Ft "const char *"
+.Fn nvlist_get_string "const nvlist_t *nvl" "const char *name"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_nvlist "const nvlist_t *nvl" "const char *name"
+.Ft int
+.Fn nvlist_get_descriptor "const nvlist_t *nvl" "const char *name"
+.Ft "const void *"
+.Fn nvlist_get_binary "const nvlist_t *nvl" "const char *name" "size_t *sizep"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_parent "const nvlist_t *nvl" "void **cookiep"
+.\"
+.Ft bool
+.Fn nvlist_take_bool "nvlist_t *nvl" "const char *name"
+.Ft uint64_t
+.Fn nvlist_take_number "nvlist_t *nvl" "const char *name"
+.Ft "char *"
+.Fn nvlist_take_string "nvlist_t *nvl" "const char *name"
+.Ft "nvlist_t *"
+.Fn nvlist_take_nvlist "nvlist_t *nvl" "const char *name"
+.Ft int
+.Fn nvlist_take_descriptor "nvlist_t *nvl" "const char *name"
+.Ft "void *"
+.Fn nvlist_take_binary "nvlist_t *nvl" "const char *name" "size_t *sizep"
+.\"
+.Ft void
+.Fn nvlist_free "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_type "nvlist_t *nvl" "const char *name" "int type"
+.\"
+.Ft void
+.Fn nvlist_free_null "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_bool "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_number "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_string "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_nvlist "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_descriptor "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_binary "nvlist_t *nvl" "const char *name"
+.Sh DESCRIPTION
+The
+.Nm libnv
+library allows to easily manage name value pairs as well as send and receive
+them over sockets.
+A group (list) of name value pairs is called an
+.Nm nvlist .
+The API supports the following data types:
+.Bl -ohang -offset indent
+.It Sy null ( NV_TYPE_NULL )
+There is no data associated with the name.
+.It Sy bool ( NV_TYPE_BOOL )
+The value can be either
+.Dv true
+or
+.Dv false .
+.It Sy number ( NV_TYPE_NUMBER )
+The value is a number stored as
+.Vt uint64_t .
+.It Sy string ( NV_TYPE_STRING )
+The value is a C string.
+.It Sy nvlist ( NV_TYPE_NVLIST )
+The value is a nested nvlist.
+.It Sy descriptor ( NV_TYPE_DESCRIPTOR )
+The value is a file descriptor.
+Note that file descriptors can be sent only over
+.Xr unix 4
+domain sockets.
+.It Sy binary ( NV_TYPE_BINARY )
+The value is a binary buffer.
+.El
+.Pp
+The
+.Fn nvlist_create
+function allocates memory and initializes an nvlist.
+.Pp
+The following flag can be provided:
+.Pp
+.Bl -tag -width "NV_FLAG_IGNORE_CASE" -compact -offset indent
+.It Dv NV_FLAG_IGNORE_CASE
+Perform case-insensitive lookups of provided names.
+.El
+.Pp
+The
+.Fn nvlist_destroy
+function destroys the given nvlist.
+Function does nothing if
+.Dv NULL
+nvlist is provided.
+Function never modifies the
+.Va errno
+global variable.
+.Pp
+The
+.Fn nvlist_error
+function returns any error value that the nvlist accumulated.
+If the given nvlist is
+.Dv NULL
+the
+.Er ENOMEM
+error will be returned.
+.Pp
+The
+.Fn nvlist_set_error
+function sets an nvlist to be in the error state.
+Subsequent calls to
+.Fn nvlist_error
+will return the given error value.
+This function cannot be used to clear the error state from an nvlist.
+This function does nothing if the nvlist is already in the error state.
+.Pp
+The
+.Fn nvlist_empty
+function returns
+.Dv true
+if the given nvlist is empty and
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_flags
+function returns flags used to create the nvlist with the
+.Fn nvlist_create
+function.
+.Pp
+The
+.Fn nvlist_clone
+functions clones the given nvlist.
+The clone shares no resources with its origin.
+This also means that all file descriptors that are part of the nvlist will be
+duplicated with the
+.Xr dup 2
+system call before placing them in the clone.
+.Pp
+The
+.Fn nvlist_dump
+dumps nvlist content for debugging purposes to the given file descriptor
+.Fa fd .
+.Pp
+The
+.Fn nvlist_fdump
+dumps nvlist content for debugging purposes to the given file stream
+.Fa fp .
+.Pp
+The
+.Fn nvlist_size
+function returns the size of the given nvlist after converting it to binary
+buffer with the
+.Fn nvlist_pack
+function.
+.Pp
+The
+.Fn nvlist_pack
+function converts the given nvlist to a binary buffer.
+The function allocates memory for the buffer, which should be freed with the
+.Xr free 3
+function.
+If the
+.Fa sizep
+argument is not
+.Dv NULL ,
+the size of the buffer will be stored there.
+The function returns
+.Dv NULL
+in case of an error (allocation failure).
+If the nvlist contains any file descriptors
+.Dv NULL
+will be returned.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_unpack
+function converts the given buffer to the nvlist.
+The function returns
+.Dv NULL
+in case of an error.
+.Pp
+The
+.Fn nvlist_send
+function sends the given nvlist over the socket given by the
+.Fa sock
+argument.
+Note that nvlist that contains file descriptors can only be send over
+.Xr unix 4
+domain sockets.
+.Pp
+The
+.Fn nvlist_recv
+function receives nvlist over the socket given by the
+.Fa sock
+argument.
+.Pp
+The
+.Fn nvlist_xfer
+function sends the given nvlist over the socket given by the
+.Fa sock
+argument and receives nvlist over the same socket.
+The given nvlist is always destroyed.
+.Pp
+The
+.Fn nvlist_next
+function iterates over the given nvlist returning names and types of subsequent
+elements.
+The
+.Fa cookiep
+argument allows the function to figure out which element should be returned
+next.
+The
+.Va *cookiep
+should be set to
+.Dv NULL
+for the first call and should not be changed later.
+Returning
+.Dv NULL
+means there are no more elements on the nvlist.
+The
+.Fa typep
+argument can be NULL.
+Elements may not be removed from the nvlist while traversing it.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_exists
+function returns
+.Dv true
+if element of the given name exists (besides of its type) or
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_exists_type
+function returns
+.Dv true
+if element of the given name and the given type exists or
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_exists_null ,
+.Fn nvlist_exists_bool ,
+.Fn nvlist_exists_number ,
+.Fn nvlist_exists_string ,
+.Fn nvlist_exists_nvlist ,
+.Fn nvlist_exists_descriptor ,
+.Fn nvlist_exists_binary
+functions return
+.Dv true
+if element of the given name and the given type determined by the function name
+exists or
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_add_null ,
+.Fn nvlist_add_bool ,
+.Fn nvlist_add_number ,
+.Fn nvlist_add_string ,
+.Fn nvlist_add_stringf ,
+.Fn nvlist_add_stringv ,
+.Fn nvlist_add_nvlist ,
+.Fn nvlist_add_descriptor ,
+.Fn nvlist_add_binary
+functions add element to the given nvlist.
+When adding string or binary buffor the functions will allocate memory
+and copy the data over.
+When adding nvlist, the nvlist will be cloned and clone will be added.
+When adding descriptor, the descriptor will be duplicated using the
+.Xr dup 2
+system call and the new descriptor will be added.
+If an error occurs while adding new element, internal error is set which can be
+examined using the
+.Fn nvlist_error
+function.
+.Pp
+The
+.Fn nvlist_move_string ,
+.Fn nvlist_move_nvlist ,
+.Fn nvlist_move_descriptor ,
+.Fn nvlist_move_binary
+functions add new element to the given nvlist, but unlike
+.Fn nvlist_add_<type>
+functions they will consume the given resource.
+If an error occurs while adding new element, the resource is destroyed and
+internal error is set which can be examined using the
+.Fn nvlist_error
+function.
+.Pp
+The
+.Fn nvlist_get_bool ,
+.Fn nvlist_get_number ,
+.Fn nvlist_get_string ,
+.Fn nvlist_get_nvlist ,
+.Fn nvlist_get_descriptor ,
+.Fn nvlist_get_binary
+functions allow to obtain value of the given name.
+In case of string, nvlist, descriptor or binary, returned resource should
+not be modified - it still belongs to the nvlist.
+If element of the given name does not exist, the program will be aborted.
+To avoid that the caller should check for existence before trying to obtain
+the value or use
+.Xr dnvlist 3
+extension, which allows to provide default value for a missing element.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_get_parent
+function allows to obtain the parent nvlist from the nested nvlist.
+.Pp
+The
+.Fn nvlist_take_bool ,
+.Fn nvlist_take_number ,
+.Fn nvlist_take_string ,
+.Fn nvlist_take_nvlist ,
+.Fn nvlist_take_descriptor ,
+.Fn nvlist_take_binary
+functions return value associated with the given name and remove the element
+from the nvlist.
+In case of string and binary values, the caller is responsible for free returned
+memory using the
+.Xr free 3
+function.
+In case of nvlist, the caller is responsible for destroying returned nvlist
+using the
+.Fn nvlist_destroy
+function.
+In case of descriptor, the caller is responsible for closing returned descriptor
+using the
+.Fn close 2
+system call.
+If element of the given name does not exist, the program will be aborted.
+To avoid that the caller should check for existence before trying to obtain
+the value or use
+.Xr dnvlist 3
+extension, which allows to provide default value for a missing element.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_free
+function removes element of the given name from the nvlist (besides of its type)
+and frees all resources associated with it.
+If element of the given name does not exist, the program will be aborted.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_free_type
+function removes element of the given name and the given type from the nvlist
+and frees all resources associated with it.
+If element of the given name and the given type does not exist, the program
+will be aborted.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_free_null ,
+.Fn nvlist_free_bool ,
+.Fn nvlist_free_number ,
+.Fn nvlist_free_string ,
+.Fn nvlist_free_nvlist ,
+.Fn nvlist_free_descriptor ,
+.Fn nvlist_free_binary
+functions remove element of the given name and the given type determined by the
+function name from the nvlist and free all resources associated with it.
+If element of the given name and the given type does not exist, the program
+will be aborted.
+The nvlist must not be in error state.
+.Sh EXAMPLES
+The following example demonstrates how to prepare an nvlist and send it over
+.Xr unix 4
+domain socket.
+.Bd -literal
+nvlist_t *nvl;
+int fd;
+
+fd = open("/tmp/foo", O_RDONLY);
+if (fd < 0)
+ err(1, "open(\\"/tmp/foo\\") failed");
+
+nvl = nvlist_create(0);
+/*
+ * There is no need to check if nvlist_create() succeeded,
+ * as the nvlist_add_<type>() functions can cope.
+ * If it failed, nvlist_send() will fail.
+ */
+nvlist_add_string(nvl, "filename", "/tmp/foo");
+nvlist_add_number(nvl, "flags", O_RDONLY);
+/*
+ * We just want to send the descriptor, so we can give it
+ * for the nvlist to consume (that's why we use nvlist_move
+ * not nvlist_add).
+ */
+nvlist_move_descriptor(nvl, "fd", fd);
+if (nvlist_send(sock, nvl) < 0) {
+ nvlist_destroy(nvl);
+ err(1, "nvlist_send() failed");
+}
+nvlist_destroy(nvl);
+.Ed
+.Pp
+Receiving nvlist and getting data:
+.Bd -literal
+nvlist_t *nvl;
+const char *command;
+char *filename;
+int fd;
+
+nvl = nvlist_recv(sock);
+if (nvl == NULL)
+ err(1, "nvlist_recv() failed");
+
+/* For command we take pointer to nvlist's buffer. */
+command = nvlist_get_string(nvl, "command");
+/*
+ * For filename we remove it from the nvlist and take
+ * ownership of the buffer.
+ */
+filename = nvlist_take_string(nvl, "filename");
+/* The same for the descriptor. */
+fd = nvlist_take_descriptor(nvl, "fd");
+
+printf("command=%s filename=%s fd=%d\n", command, filename, fd);
+
+nvlist_destroy(nvl);
+free(filename);
+close(fd);
+/* command was freed by nvlist_destroy() */
+.Ed
+.Pp
+Iterating over nvlist:
+.Bd -literal
+nvlist_t *nvl;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock);
+if (nvl == NULL)
+ err(1, "nvlist_recv() failed");
+
+cookie = NULL;
+while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ printf("%s=", name);
+ switch (type) {
+ case NV_TYPE_NUMBER:
+ printf("%ju", (uintmax_t)nvlist_get_number(nvl, name));
+ break;
+ case NV_TYPE_STRING:
+ printf("%s", nvlist_get_string(nvl, name));
+ break;
+ default:
+ printf("N/A");
+ break;
+ }
+ printf("\\n");
+}
+.Ed
+.Pp
+Iterating over every nested nvlist:
+.Bd -literal
+nvlist_t *nvl;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock);
+if (nvl == NULL)
+ err(1, "nvlist_recv() failed");
+
+cookie = NULL;
+do {
+ while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ if (type == NV_TYPE_NVLIST) {
+ nvl = nvlist_get_nvlist(nvl, name);
+ cookie = NULL;
+ }
+ }
+} while ((nvl = nvlist_get_parent(nvl, &cookie)) != NULL);
+.Ed
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr dup 2 ,
+.Xr open 2 ,
+.Xr err 3 ,
+.Xr free 3 ,
+.Xr printf 3 ,
+.Xr unix 4
+.Sh HISTORY
+The
+.Nm libnv
+library appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libnv
+library was implemented by
+.An Pawel Jakub Dawidek Aq pawel@dawidek.net
+under sponsorship from the FreeBSD Foundation.
diff --git a/lib/libnv/tests/Makefile b/lib/libnv/tests/Makefile
new file mode 100644
index 0000000..d8e0904
--- /dev/null
+++ b/lib/libnv/tests/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libnv
+
+ATF_TESTS_CXX= \
+ dnv_tests \
+ nv_tests \
+
+TAP_TESTS_C+= nvlist_add_test
+TAP_TESTS_C+= nvlist_exists_test
+TAP_TESTS_C+= nvlist_free_test
+TAP_TESTS_C+= nvlist_get_test
+TAP_TESTS_C+= nvlist_move_test
+TAP_TESTS_C+= nvlist_send_recv_test
+
+DPADD+= ${LIBNV}
+LDADD+= -lnv
+
+WARNS?= 3
+
+.include <bsd.test.mk>
diff --git a/lib/libnv/tests/dnv_tests.cc b/lib/libnv/tests/dnv_tests.cc
new file mode 100644
index 0000000..2f92d9d
--- /dev/null
+++ b/lib/libnv/tests/dnv_tests.cc
@@ -0,0 +1,567 @@
+/*-
+ * Copyright (c) 2014-2015 Sandvine Inc. All rights reserved.
+ * All rights reserved.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <atf-c++.hpp>
+#include <dnv.h>
+#include <nv.h>
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_bool__present);
+ATF_TEST_CASE_BODY(dnvlist_get_bool__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ bool value;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = true;
+ nvlist_add_bool(nvl, key, value);
+
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, key, false), value);
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "name", false), value);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_bool__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_bool__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ key = "123";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, key, false), false);
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "123", true), true);
+
+ nvlist_add_bool(nvl, key, true);
+
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "otherkey", true), true);
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "12c", false), false);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_number__present);
+ATF_TEST_CASE_BODY(dnvlist_get_number__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ uint64_t value;
+
+ nvl = nvlist_create(0);
+
+ key = "key";
+ value = 48952;
+ nvlist_add_number(nvl, key, value);
+
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, key, 19), value);
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "key", 65), value);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_number__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_number__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ key = "123";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, key, 5), 5);
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "1234", 5), 5);
+
+ nvlist_add_number(nvl, key, 24841);
+
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "1234", 5641), 5641);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_string__present);
+ATF_TEST_CASE_BODY(dnvlist_get_string__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ const char *value, *actual_value;
+
+ nvl = nvlist_create(0);
+
+ key = "string";
+ value = "fjdojfdi";
+ nvlist_add_string(nvl, key, value);
+
+ ATF_REQUIRE_EQ(strcmp(dnvlist_get_string(nvl, key, "g"), value), 0);
+
+ actual_value = dnvlist_get_string(nvl, key, "rs");
+ ATF_REQUIRE_EQ(strcmp(actual_value, value), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_string__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_string__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+ const char *actual_value;
+
+ key = "123";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(strcmp(dnvlist_get_string(nvl, key, "bar"), "bar"), 0);
+
+ actual_value = dnvlist_get_string(nvl, key, "d");
+ ATF_REQUIRE_EQ(strcmp(actual_value, "d"), 0);
+
+ nvlist_add_string(nvl, key, "cxhweh");
+
+ ATF_REQUIRE_EQ(strcmp(dnvlist_get_string(nvl, "hthth", "fd"), "fd"), 0);
+ actual_value = dnvlist_get_string(nvl, "5", "5");
+ ATF_REQUIRE_EQ(strcmp("5", "5"), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_nvlist__present);
+ATF_TEST_CASE_BODY(dnvlist_get_nvlist__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ nvlist_t *value;
+ const nvlist_t *actual_value;
+
+ nvl = nvlist_create(0);
+
+ key = "nvlist";
+ value = nvlist_create(0);
+ nvlist_move_nvlist(nvl, key, value);
+
+ actual_value = dnvlist_get_nvlist(nvl, key, NULL);
+ ATF_REQUIRE(actual_value != NULL);
+ ATF_REQUIRE(nvlist_empty(actual_value));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_nvlist__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_nvlist__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+ nvlist_t *dummy;
+
+ key = "123";
+ nvl = nvlist_create(0);
+ dummy = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_get_nvlist(nvl, key, dummy), dummy);
+
+ nvlist_move_nvlist(nvl, key, nvlist_create(0));
+ ATF_REQUIRE_EQ(dnvlist_get_nvlist(nvl, "456", dummy), dummy);
+ ATF_REQUIRE_EQ(dnvlist_get_nvlist(nvl, "gh", dummy), dummy);
+
+ nvlist_destroy(nvl);
+}
+
+static void
+set_const_binary_value(const void *&value, size_t &size, const char *str)
+{
+
+ value = str;
+ size = strlen(str) + 1; /* +1 to include '\0' */
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_binary__present);
+ATF_TEST_CASE_BODY(dnvlist_get_binary__present)
+{
+ nvlist_t *nvl;
+ const char *k;
+ const void *value, *actual_value;
+ size_t value_size, actual_size;
+
+ nvl = nvlist_create(0);
+
+ k = "binary";
+ set_const_binary_value(value, value_size, "fjdojfdi");
+ nvlist_add_binary(nvl, k, value, value_size);
+
+ actual_value = dnvlist_get_binary(nvl, k, &actual_size, "g", 1);
+ ATF_REQUIRE_EQ(value_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, value, actual_size), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_binary__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_binary__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+ const void *default_value, *actual_value;
+ size_t default_size, actual_size;
+
+ key = "123";
+ nvl = nvlist_create(0);
+
+ set_const_binary_value(default_value, default_size, "bar");
+ actual_value = dnvlist_get_binary(nvl, key, &actual_size, default_value,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
+
+ set_const_binary_value(default_value, default_size, "atf");
+ actual_value = dnvlist_get_binary(nvl, key, &actual_size, default_value,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
+
+ nvlist_add_binary(nvl, key, "test", 4);
+
+ set_const_binary_value(default_value, default_size, "bthrg");
+ actual_value = dnvlist_get_binary(nvl, "k", &actual_size, default_value,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
+
+ set_const_binary_value(default_value, default_size,
+ "rrhgrythtyrtgbrhgrtdsvdfbtjlkul");
+ actual_value = dnvlist_get_binary(nvl, "s", &actual_size, default_value,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_bool__present);
+ATF_TEST_CASE_BODY(dnvlist_take_bool__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ bool value;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = true;
+ nvlist_add_bool(nvl, key, value);
+
+ ATF_REQUIRE_EQ(dnvlist_take_bool(nvl, key, false), value);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_bool__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_bool__empty)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_take_bool(nvl, "123", false), false);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_bool__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_bool__default_value)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_bool(nvl, "key", true);
+
+ ATF_REQUIRE_EQ(dnvlist_take_bool(nvl, "otherkey", true), true);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_number__present);
+ATF_TEST_CASE_BODY(dnvlist_take_number__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ uint64_t value;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = 194154;
+ nvlist_add_number(nvl, key, value);
+
+ ATF_REQUIRE_EQ(dnvlist_take_number(nvl, key, 2), value);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_number__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_number__empty)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_take_number(nvl, "123", 126484), 126484);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_number__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_number__default_value)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_number(nvl, "key", 12);
+
+ ATF_REQUIRE_EQ(dnvlist_take_number(nvl, "otherkey", 13), 13);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_string__present);
+ATF_TEST_CASE_BODY(dnvlist_take_string__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ const char *value;
+ char *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = "wrowm";
+ default_val = strdup("default");
+ nvlist_add_string(nvl, key, value);
+
+ actual_val = dnvlist_take_string(nvl, key, default_val);
+ ATF_REQUIRE_EQ(strcmp(actual_val, value), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ free(actual_val);
+ free(default_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_string__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_string__empty)
+{
+ nvlist_t *nvl;
+ char *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+ default_val = strdup("");
+
+ actual_val = dnvlist_take_string(nvl, "123", default_val);
+ ATF_REQUIRE_EQ(strcmp(actual_val, default_val), 0);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_string__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_string__default_value)
+{
+ nvlist_t *nvl;
+ char *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "key", "foobar");
+ default_val = strdup("other");
+
+ actual_val = dnvlist_take_string(nvl, "otherkey", default_val);
+ ATF_REQUIRE_EQ(strcmp(actual_val, default_val), 0);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_nvlist__present);
+ATF_TEST_CASE_BODY(dnvlist_take_nvlist__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ nvlist_t *value, *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = nvlist_create(0);
+ default_val = nvlist_create(0);
+ nvlist_move_nvlist(nvl, key, value);
+
+ actual_val = dnvlist_take_nvlist(nvl, key, default_val);
+ ATF_REQUIRE_EQ(actual_val, value);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ free(actual_val);
+ free(default_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_nvlist__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_nvlist__empty)
+{
+ nvlist_t *nvl, *actual_val;
+
+ nvl = nvlist_create(0);
+
+ actual_val = dnvlist_take_nvlist(nvl, "123", NULL);
+ ATF_REQUIRE_EQ(actual_val, static_cast<nvlist_t *>(NULL));
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_nvlist__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_nvlist__default_value)
+{
+ nvlist_t *nvl;
+ nvlist_t *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+ nvlist_move_nvlist(nvl, "key", nvlist_create(0));
+ default_val = nvlist_create(0);
+
+ actual_val = dnvlist_take_nvlist(nvl, "otherkey", default_val);
+ ATF_REQUIRE_EQ(actual_val, default_val);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+static void
+set_binary_value(void *&value, size_t &size, const char *str)
+{
+
+ value = strdup(str);
+ size = strlen(str) + 1; /* +1 to include '\0' */
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_binary__present);
+ATF_TEST_CASE_BODY(dnvlist_take_binary__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ void *value, *default_val, *actual_val;
+ size_t value_size, default_size, actual_size;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ set_binary_value(value, value_size, "fkdojvmo908");
+ set_binary_value(default_val, default_size, "16546");
+ nvlist_add_binary(nvl, key, value, value_size);
+
+ actual_val = dnvlist_take_binary(nvl, key, &actual_size, default_val,
+ default_size);
+ ATF_REQUIRE_EQ(value_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_val, value, value_size), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ free(actual_val);
+ free(default_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_binary__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_binary__empty)
+{
+ nvlist_t *nvl;
+ void *default_val, *actual_val;
+ size_t default_size, actual_size;
+
+ nvl = nvlist_create(0);
+ set_binary_value(default_val, default_size, "\xa8\x89\x49\xff\xe2\x08");
+
+ actual_val = dnvlist_take_binary(nvl, "123", &actual_size, default_val,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_val, default_val, actual_size), 0);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_binary__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_binary__default_value)
+{
+ nvlist_t *nvl;
+ void *default_val, *actual_val;
+ size_t default_size, actual_size;
+
+ nvl = nvlist_create(0);
+ nvlist_add_binary(nvl, "key", "foobar", 6);
+ set_binary_value(default_val, default_size, "vbhag");
+
+ actual_val = dnvlist_take_binary(nvl, "otherkey", &actual_size,
+ default_val, default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_val, default_val, default_size), 0);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_INIT_TEST_CASES(tp)
+{
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_bool__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_bool__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_number__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_number__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_string__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_string__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_nvlist__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_nvlist__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_binary__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_binary__default_value);
+
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_bool__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_bool__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_bool__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_number__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_number__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_number__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_string__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_string__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_string__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_nvlist__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_nvlist__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_nvlist__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_binary__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_binary__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_binary__default_value);
+}
diff --git a/lib/libnv/tests/nv_tests.cc b/lib/libnv/tests/nv_tests.cc
new file mode 100644
index 0000000..2d9fd97
--- /dev/null
+++ b/lib/libnv/tests/nv_tests.cc
@@ -0,0 +1,1240 @@
+/*-
+ * Copyright (c) 2014-2015 Sandvine Inc. All rights reserved.
+ * All rights reserved.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <atf-c++.hpp>
+#include <nv.h>
+
+#include <errno.h>
+#include <limits>
+#include <set>
+#include <sstream>
+#include <string>
+
+/*
+ * Test that a newly created nvlist has no errors, and is empty.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_create__is_empty);
+ATF_TEST_CASE_BODY(nvlist_create__is_empty)
+{
+ nvlist_t *nvl;
+ int type;
+ void *it;
+
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ it = NULL;
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type, &it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_null__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_null__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ int type;
+
+ key = "key";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_null(nvl, key);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists_null(nvl, key));
+ ATF_REQUIRE(nvlist_exists_null(nvl, "key"));
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NULL);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_bool__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_bool__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ int type;
+
+ key = "name";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_bool(nvl, key, true);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "name"));
+ ATF_REQUIRE(nvlist_exists_bool(nvl, key));
+ ATF_REQUIRE(nvlist_exists_bool(nvl, "name"));
+ ATF_REQUIRE_EQ(nvlist_get_bool(nvl, key), true);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_BOOL);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_number__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_number__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ uint64_t value;
+ int type;
+
+ key = "foo123";
+ value = 71965;
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_number(nvl, key, value);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "foo123"));
+ ATF_REQUIRE(nvlist_exists_number(nvl, key));
+ ATF_REQUIRE_EQ(nvlist_get_number(nvl, key), value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NUMBER);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_string__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_string__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ const char *value;
+ int type;
+
+ key = "test";
+ value = "fgjdkgjdk";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_string(nvl, key, value);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "test"));
+ ATF_REQUIRE(nvlist_exists_string(nvl, key));
+ ATF_REQUIRE(nvlist_exists_string(nvl, "test"));
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(nvl, key), value), 0);
+
+ /* nvlist_add_* is required to clone the value, so check for that. */
+ ATF_REQUIRE(nvlist_get_string(nvl, key) != value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_STRING);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_nvlist__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_nvlist__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key, *subkey;
+ nvlist_t *sublist;
+ const nvlist_t *value;
+ int type;
+
+ key = "test";
+ subkey = "subkey";
+ sublist = nvlist_create(0);
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_null(sublist, subkey);
+ nvlist_add_nvlist(nvl, key, sublist);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "test"));
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, key));
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, "test"));
+
+ value = nvlist_get_nvlist(nvl, key);
+ ATF_REQUIRE(nvlist_exists_null(value, subkey));
+
+ /* nvlist_add_* is required to clone the value, so check for that. */
+ ATF_REQUIRE(sublist != value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NVLIST);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(sublist);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_nvlist__child_with_error);
+ATF_TEST_CASE_BODY(nvlist_add_nvlist__child_with_error)
+{
+ nvlist_t *nvl, *parent;
+
+ nvl = nvlist_create(0);
+ parent = nvlist_create(0);
+
+ nvlist_set_error(nvl, EBADF);
+ nvlist_add_nvlist(parent, "test", nvl);
+ ATF_REQUIRE_EQ(nvlist_error(parent), EBADF);
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(parent);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_binary__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_binary__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ void *value;
+ const void *ret_value;
+ size_t value_size, ret_size;
+ int type;
+
+ key = "binary";
+ value_size = 13;
+ value = malloc(value_size);
+ memset(value, 0xa5, value_size);
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_binary(nvl, key, value, value_size);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "binary"));
+ ATF_REQUIRE(nvlist_exists_binary(nvl, key));
+ ATF_REQUIRE(nvlist_exists_binary(nvl, "binary"));
+
+ ret_value = nvlist_get_binary(nvl, key, &ret_size);
+ ATF_REQUIRE_EQ(value_size, ret_size);
+ ATF_REQUIRE_EQ(memcmp(value, ret_value, ret_size), 0);
+
+ /* nvlist_add_* is required to clone the value, so check for that. */
+ ATF_REQUIRE(value != ret_value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_BINARY);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+ free(value);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone__empty_nvlist);
+ATF_TEST_CASE_BODY(nvlist_clone__empty_nvlist)
+{
+ nvlist_t *nvl, *clone;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ clone = nvlist_clone(nvl);
+ ATF_REQUIRE(clone != NULL);
+ ATF_REQUIRE(clone != nvl);
+ ATF_REQUIRE(nvlist_empty(clone));
+
+ nvlist_destroy(clone);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone__nonempty_nvlist);
+ATF_TEST_CASE_BODY(nvlist_clone__nonempty_nvlist)
+{
+ nvlist_t *nvl, *clone;
+ const char *key;
+ void *it;
+ uint64_t value;
+ int type;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ key = "testkey";
+ value = 684874;
+ nvlist_add_number(nvl, key, value);
+
+ clone = nvlist_clone(nvl);
+ ATF_REQUIRE(clone != NULL);
+ ATF_REQUIRE(clone != nvl);
+ ATF_REQUIRE(nvlist_exists_number(clone, key));
+ ATF_REQUIRE_EQ(nvlist_get_number(clone, key), value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(clone, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NUMBER);
+ ATF_REQUIRE_EQ(nvlist_next(clone, &type, &it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(clone);
+ nvlist_destroy(nvl);
+}
+
+static const char * const test_subnvlist_key = "nvlist";
+
+static const char * const test_string_key = "string";
+static const char * const test_string_val = "59525";
+
+static nvlist_t*
+create_test_nvlist(void)
+{
+ nvlist_t *nvl, *sublist;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ sublist = nvlist_create(0);
+ ATF_REQUIRE(sublist != NULL);
+
+ nvlist_add_string(sublist, test_string_key, test_string_val);
+ nvlist_move_nvlist(nvl, test_subnvlist_key, sublist);
+
+ return (nvl);
+}
+
+static void
+verify_test_nvlist(const nvlist_t *nvl)
+{
+ void *it;
+ const nvlist_t *value;
+ int type;
+
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, test_subnvlist_key));
+
+ value = nvlist_get_nvlist(nvl, test_subnvlist_key);
+
+ ATF_REQUIRE(nvlist_exists_string(value, test_string_key));
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(value, test_string_key), test_string_val), 0);
+ ATF_REQUIRE(nvlist_get_string(value, test_string_key) != test_string_val);
+
+ /* Iterate over both nvlists; ensure that each has only the one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(value, &type, &it),
+ test_string_key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_STRING);
+ ATF_REQUIRE_EQ(nvlist_next(value, &type, &it), static_cast<const char *>(NULL));
+
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it),
+ test_subnvlist_key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NVLIST);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type, &it), static_cast<const char *>(NULL));
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone__nested_nvlist);
+ATF_TEST_CASE_BODY(nvlist_clone__nested_nvlist)
+{
+ nvlist_t *nvl, *clone;
+
+ nvl = create_test_nvlist();
+ clone = nvlist_clone(nvl);
+
+ ATF_REQUIRE(clone != NULL);
+ ATF_REQUIRE(clone != nvl);
+ verify_test_nvlist(clone);
+
+ nvlist_destroy(clone);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone__error_nvlist);
+ATF_TEST_CASE_BODY(nvlist_clone__error_nvlist)
+{
+ nvlist_t *nvl, *clone;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ nvlist_set_error(nvl, ENOMEM);
+
+ clone = nvlist_clone(nvl);
+ ATF_REQUIRE(clone == NULL);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_pack__empty_nvlist);
+ATF_TEST_CASE_BODY(nvlist_pack__empty_nvlist)
+{
+ nvlist_t *nvl, *unpacked;
+ void *packed;
+ size_t packed_size;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE(unpacked != nvl);
+ ATF_REQUIRE(nvlist_empty(unpacked));
+
+ nvlist_destroy(unpacked);
+ nvlist_destroy(nvl);
+ free(packed);
+}
+
+static void
+verify_null(const nvlist_t *nvl, int type)
+{
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_NULL);
+}
+
+static void
+verify_number(const nvlist_t *nvl, const char *name, int type, uint64_t value)
+{
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_NUMBER);
+ ATF_REQUIRE_EQ(nvlist_get_number(nvl, name), value);
+}
+
+static void
+verify_string(const nvlist_t *nvl, const char *name, int type,
+ const char * value)
+{
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_STRING);
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(nvl, name), value), 0);
+}
+
+static void
+verify_nvlist(const nvlist_t *nvl, const char *name, int type)
+{
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_NVLIST);
+ verify_test_nvlist(nvlist_get_nvlist(nvl, name));
+}
+
+static void
+verify_binary(const nvlist_t *nvl, const char *name, int type,
+ const void * value, size_t size)
+{
+ const void *actual_value;
+ size_t actual_size;
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_BINARY);
+ actual_value = nvlist_get_binary(nvl, name, &actual_size);
+ ATF_REQUIRE_EQ(size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(value, actual_value, size), 0);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_pack__multiple_values);
+ATF_TEST_CASE_BODY(nvlist_pack__multiple_values)
+{
+ std::ostringstream msg;
+ std::set<std::string> keys_seen;
+ nvlist_t *nvl, *unpacked, *nvvalue;
+ const char *nullkey, *numkey, *strkey, *nvkey, *binkey, *name;
+ int numvalue;
+ const char * strvalue;
+ void *binvalue, *packed, *it;
+ size_t binsize, packed_size;
+ int type;
+
+ nvl = nvlist_create(0);
+
+ nullkey = "null";
+ nvlist_add_null(nvl, nullkey);
+
+ numkey = "number";
+ numvalue = 939853984;
+ nvlist_add_number(nvl, numkey, numvalue);
+
+ strkey = "string";
+ strvalue = "jfieutijf";
+ nvlist_add_string(nvl, strkey, strvalue);
+
+ nvkey = "nvlist";
+ nvvalue = create_test_nvlist();
+ nvlist_move_nvlist(nvl, nvkey, nvvalue);
+
+ binkey = "binary";
+ binsize = 4;
+ binvalue = malloc(binsize);
+ memset(binvalue, 'b', binsize);
+ nvlist_move_binary(nvl, binkey, binvalue, binsize);
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size);
+ ATF_REQUIRE(unpacked != 0);
+
+ it = NULL;
+ while ((name = nvlist_next(unpacked, &type, &it)) != NULL) {
+ /* Ensure that we see every key only once. */
+ ATF_REQUIRE_EQ(keys_seen.count(name), 0);
+
+ if (strcmp(name, nullkey) == 0)
+ verify_null(unpacked, type);
+ else if (strcmp(name, numkey) == 0)
+ verify_number(unpacked, name, type, numvalue);
+ else if (strcmp(name, strkey) == 0)
+ verify_string(unpacked, name, type, strvalue);
+ else if (strcmp(name, nvkey) == 0)
+ verify_nvlist(unpacked, name, type);
+ else if (strcmp(name, binkey) == 0)
+ verify_binary(unpacked, name, type, binvalue, binsize);
+ else {
+ msg << "Unexpected key :'" << name << "'";
+ ATF_FAIL(msg.str().c_str());
+ }
+
+ keys_seen.insert(name);
+ }
+
+ /* Ensure that we saw every key. */
+ ATF_REQUIRE_EQ(keys_seen.size(), 5);
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_pack__error_nvlist);
+ATF_TEST_CASE_BODY(nvlist_pack__error_nvlist)
+{
+ nvlist_t *nvl;
+ void *packed;
+ size_t size;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ nvlist_set_error(nvl, ENOMEM);
+
+ packed = nvlist_pack(nvl, &size);
+ ATF_REQUIRE(packed == NULL);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_unpack__duplicate_key);
+ATF_TEST_CASE_BODY(nvlist_unpack__duplicate_key)
+{
+ nvlist_t *nvl, *unpacked;
+ const char *key1, *key2;
+ void *packed, *keypos;
+ size_t size, keylen;
+
+ nvl = nvlist_create(0);
+
+ key1 = "key1";
+ keylen = strlen(key1);
+ nvlist_add_number(nvl, key1, 5);
+
+ key2 = "key2";
+ ATF_REQUIRE_EQ(keylen, strlen(key2));
+ nvlist_add_number(nvl, key2, 10);
+
+ packed = nvlist_pack(nvl, &size);
+
+ /*
+ * Mangle the packed nvlist by replacing key1 with key2, creating a
+ * packed nvlist with a duplicate key.
+ */
+ keypos = memmem(packed, size, key1, keylen);
+ ATF_REQUIRE(keypos != NULL);
+ memcpy(keypos, key2, keylen);
+
+ unpacked = nvlist_unpack(packed, size);
+ ATF_REQUIRE(nvlist_error(unpacked) != 0);
+
+ free(packed);
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_string__single_insert);
+ATF_TEST_CASE_BODY(nvlist_move_string__single_insert)
+{
+ nvlist_t *nvl;
+ const char *key;
+ char *value;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ key = "testkey";
+ value = strdup("testval");
+ ATF_REQUIRE(value != NULL);
+
+ nvlist_move_string(nvl, key, value);
+ ATF_REQUIRE_EQ(nvlist_get_string(nvl, key), value);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_nvlist__null_child);
+ATF_TEST_CASE_BODY(nvlist_move_nvlist__null_child)
+{
+ nvlist_t *parent;
+
+ parent = nvlist_create(0);
+
+ nvlist_move_nvlist(parent, "test", NULL);
+
+ ATF_REQUIRE(nvlist_error(parent) != 0);
+
+ nvlist_destroy(parent);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_nvlist__child_with_error);
+ATF_TEST_CASE_BODY(nvlist_move_nvlist__child_with_error)
+{
+ nvlist_t *nvl, *parent;
+
+ nvl = nvlist_create(0);
+ parent = nvlist_create(0);
+
+ nvlist_set_error(nvl, EBADF);
+ nvlist_move_nvlist(parent, "test", nvl);
+ ATF_REQUIRE_EQ(nvlist_error(parent), EBADF);
+
+ nvlist_destroy(parent);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_nvlist__single_insert);
+ATF_TEST_CASE_BODY(nvlist_move_nvlist__single_insert)
+{
+ nvlist_t *nvl;
+ const char *key;
+ nvlist_t *value;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ key = "testkey";
+ value = nvlist_create(0);
+ ATF_REQUIRE(value != NULL);
+
+ nvlist_move_nvlist(nvl, key, value);
+ ATF_REQUIRE_EQ(nvlist_get_nvlist(nvl, key), value);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_binary__single_insert);
+ATF_TEST_CASE_BODY(nvlist_move_binary__single_insert)
+{
+ nvlist_t *nvl;
+ const char *key;
+ void *value;
+ size_t size, actual_size;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ key = "testkey";
+ size = 73;
+ value = malloc(size);
+ ATF_REQUIRE(value != NULL);
+
+ nvlist_move_binary(nvl, key, value, size);
+ ATF_REQUIRE_EQ(nvlist_get_binary(nvl, key, &actual_size), value);
+ ATF_REQUIRE_EQ(size, actual_size);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_bool__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_bool__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ bool testval;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "boolkey";
+ testval = false;
+ nvlist_add_bool(nvl, testkey, testval);
+
+ ATF_REQUIRE_EQ(nvlist_take_bool(nvl, testkey), testval);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_bool__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_bool__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ bool testval, otherval1;
+ nvlist_t *otherval2;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "boolkey";
+ testval = true;
+ nvlist_add_bool(nvl, testkey, testval);
+
+ otherkey1 = "key1";
+ otherval1 = false;
+ nvlist_add_bool(nvl, otherkey1, otherval1);
+
+ otherkey2 = "key2";
+ otherval2 = create_test_nvlist();
+ nvlist_move_nvlist(nvl, otherkey2, otherval2);
+
+ ATF_REQUIRE_EQ(nvlist_take_bool(nvl, testkey), testval);
+
+ ATF_REQUIRE(nvlist_exists_bool(nvl, otherkey1));
+ ATF_REQUIRE_EQ(nvlist_get_bool(nvl, otherkey1), otherval1);
+
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, otherkey2));
+ verify_test_nvlist(nvlist_get_nvlist(nvl, otherkey2));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_number__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_number__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ uint64_t testval;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "numkey";
+ testval = std::numeric_limits<uint64_t>::max();
+ nvlist_add_number(nvl, testkey, testval);
+
+ ATF_REQUIRE_EQ(nvlist_take_number(nvl, testkey), testval);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_number__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_number__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ uint64_t testval, otherval1;
+ const char *otherval2;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ otherkey1 = "key1";
+ otherval1 = 5;
+ nvlist_add_number(nvl, otherkey1, otherval1);
+
+ testkey = "numkey";
+ testval = 1654;
+ nvlist_add_number(nvl, testkey, testval);
+
+ otherkey2 = "key2";
+ otherval2 = "string";
+ nvlist_add_string(nvl, otherkey2, otherval2);
+
+ ATF_REQUIRE_EQ(nvlist_take_number(nvl, testkey), testval);
+
+ ATF_REQUIRE(nvlist_exists_number(nvl, otherkey1));
+ ATF_REQUIRE_EQ(nvlist_get_number(nvl, otherkey1), otherval1);
+
+ ATF_REQUIRE(nvlist_exists_string(nvl, otherkey2));
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(nvl, otherkey2), otherval2), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_string__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_string__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ const char *testval;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "numkey";
+ testval = "nvlist";
+ nvlist_add_string(nvl, testkey, testval);
+
+ ATF_REQUIRE_EQ(strcmp(nvlist_take_string(nvl, testkey), testval), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_string__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_string__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ const char *testval, *otherval1;
+ bool otherval2;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ otherkey1 = "key1";
+ otherval1 = "fjdifjdk";
+ nvlist_add_string(nvl, otherkey1, otherval1);
+
+ otherkey2 = "key2";
+ otherval2 = true;
+ nvlist_add_bool(nvl, otherkey2, otherval2);
+
+ testkey = "strkey";
+ testval = "1654";
+ nvlist_add_string(nvl, testkey, testval);
+
+ ATF_REQUIRE_EQ(strcmp(nvlist_take_string(nvl, testkey), testval), 0);
+
+ ATF_REQUIRE(nvlist_exists_string(nvl, otherkey1));
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(nvl, otherkey1), otherval1), 0);
+
+ ATF_REQUIRE(nvlist_exists_bool(nvl, otherkey2));
+ ATF_REQUIRE_EQ(nvlist_get_bool(nvl, otherkey2), otherval2);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_nvlist__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_nvlist__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ nvlist_t *testval;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "numkey";
+ testval = create_test_nvlist();
+ nvlist_move_nvlist(nvl, testkey, testval);
+
+ verify_test_nvlist(nvlist_take_nvlist(nvl, testkey));
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_nvlist__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_nvlist__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ nvlist_t *testval, *otherval1;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "strkey";
+ testval = create_test_nvlist();
+ nvlist_move_nvlist(nvl, testkey, testval);
+
+ otherkey1 = "key1";
+ otherval1 = nvlist_create(0);
+ nvlist_move_nvlist(nvl, otherkey1, otherval1);
+
+ otherkey2 = "key2";
+ nvlist_add_null(nvl, otherkey2);
+
+ verify_test_nvlist(nvlist_take_nvlist(nvl, testkey));
+
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, otherkey1));
+ ATF_REQUIRE(nvlist_empty(nvlist_get_nvlist(nvl, otherkey1)));
+
+ ATF_REQUIRE(nvlist_exists_null(nvl, otherkey2));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_binary__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_binary__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ void *testval;
+ const void *actual_val;
+ size_t testsize, actual_size;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "numkey";
+ testsize = 457;
+ testval = malloc(testsize);
+ memset(testval, '5', testsize);
+ nvlist_move_binary(nvl, testkey, testval, testsize);
+
+ actual_val = nvlist_take_binary(nvl, testkey, &actual_size);
+ ATF_REQUIRE_EQ(testsize, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_val, testval, testsize), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_binary__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_binary__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ const void *actual_value;
+ char testval[] = "gjiertj";
+ char otherval1[] = "fdreg";
+ size_t testsize, othersize, actual_size;
+ bool otherval2;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ otherkey1 = "key1";
+ othersize = sizeof(otherval1);
+ nvlist_add_binary(nvl, otherkey1, otherval1, othersize);
+
+ otherkey2 = "key2";
+ otherval2 = true;
+ nvlist_add_bool(nvl, otherkey2, otherval2);
+
+ testkey = "strkey";
+ testsize = sizeof(testval);
+ nvlist_add_binary(nvl, testkey, testval, testsize);
+
+ actual_value = nvlist_take_binary(nvl, testkey, &actual_size);
+ ATF_REQUIRE_EQ(testsize, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, testval, testsize), 0);
+
+ ATF_REQUIRE(nvlist_exists_binary(nvl, otherkey1));
+ actual_value = nvlist_get_binary(nvl, otherkey1, &actual_size);
+ ATF_REQUIRE_EQ(othersize, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, otherval1, othersize), 0);
+
+ ATF_REQUIRE(nvlist_exists_bool(nvl, otherkey2));
+ ATF_REQUIRE_EQ(nvlist_get_bool(nvl, otherkey2), otherval2);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_null);
+ATF_TEST_CASE_BODY(nvlist_free__single_null)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_null(nvl, key);
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_bool);
+ATF_TEST_CASE_BODY(nvlist_free__single_bool)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_bool(nvl, key, true);
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_number);
+ATF_TEST_CASE_BODY(nvlist_free__single_number)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_number(nvl, key, 584);
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_string);
+ATF_TEST_CASE_BODY(nvlist_free__single_string)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_string(nvl, key, "gjkfkjd");
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_nvlist);
+ATF_TEST_CASE_BODY(nvlist_free__single_nvlist)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_nvlist(nvl, key, nvlist_create(0));
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_binary);
+ATF_TEST_CASE_BODY(nvlist_free__single_binary)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_binary(nvl, key, "jgjgfd", 6);
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_null__single_null);
+ATF_TEST_CASE_BODY(nvlist_free_null__single_null)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_null(nvl, key);
+
+ nvlist_free_null(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_bool__single_bool);
+ATF_TEST_CASE_BODY(nvlist_free_bool__single_bool)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_bool(nvl, key, true);
+
+ nvlist_free_bool(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_number__single_number);
+ATF_TEST_CASE_BODY(nvlist_free_number__single_number)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_number(nvl, key, 584);
+
+ nvlist_free_number(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_string__single_string);
+ATF_TEST_CASE_BODY(nvlist_free_string__single_string)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_string(nvl, key, "gjkfkjd");
+
+ nvlist_free_string(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_nvlist__single_nvlist);
+ATF_TEST_CASE_BODY(nvlist_free_nvlist__single_nvlist)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_nvlist(nvl, key, nvlist_create(0));
+
+ nvlist_free_nvlist(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_binary__single_binary);
+ATF_TEST_CASE_BODY(nvlist_free_binary__single_binary)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_binary(nvl, key, "jgjgfd", 6);
+
+ nvlist_free_binary(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_INIT_TEST_CASES(tp)
+{
+ ATF_ADD_TEST_CASE(tp, nvlist_create__is_empty);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_null__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_bool__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_number__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_string__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_nvlist__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_nvlist__child_with_error);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_binary__single_insert);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_clone__empty_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_clone__nonempty_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_clone__nested_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_clone__error_nvlist);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_pack__empty_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_pack__multiple_values);
+ ATF_ADD_TEST_CASE(tp, nvlist_pack__error_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_unpack__duplicate_key);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_move_string__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_move_nvlist__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_move_nvlist__null_child);
+ ATF_ADD_TEST_CASE(tp, nvlist_move_nvlist__child_with_error);
+ ATF_ADD_TEST_CASE(tp, nvlist_move_binary__single_insert);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_take_bool__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_bool__other_keys_unchanged);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_number__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_number__other_keys_unchanged);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_string__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_string__other_keys_unchanged);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_nvlist__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_nvlist__other_keys_unchanged);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_binary__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_binary__other_keys_unchanged);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_null);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_bool);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_number);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_string);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_binary);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_free_null__single_null);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_bool__single_bool);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_number__single_number);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_string__single_string);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_nvlist__single_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_binary__single_binary);
+}
diff --git a/lib/libnv/tests/nvlist_add_test.c b/lib/libnv/tests/nvlist_add_test.c
new file mode 100644
index 0000000..06bcc63
--- /dev/null
+++ b/lib/libnv/tests/nvlist_add_test.c
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ const nvlist_t *cnvl;
+ nvlist_t *nvl;
+
+ printf("1..94\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ nvlist_add_null(nvl, "nvlist/null");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/true"));
+ nvlist_add_bool(nvl, "nvlist/bool/true", true);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/true"));
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/false"));
+ nvlist_add_bool(nvl, "nvlist/bool/false", false);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/false"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/0"));
+ nvlist_add_number(nvl, "nvlist/number/0", 0);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/0"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/1"));
+ nvlist_add_number(nvl, "nvlist/number/1", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/1"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/-1"));
+ nvlist_add_number(nvl, "nvlist/number/-1", -1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/-1"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/"));
+ nvlist_add_string(nvl, "nvlist/string/", "");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/x"));
+ nvlist_add_string(nvl, "nvlist/string/x", "x");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/stringf/"));
+ nvlist_add_stringf(nvl, "nvlist/stringf/", "%s", "");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/stringf/x"));
+ nvlist_add_stringf(nvl, "nvlist/stringf/x", "%s", "x");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/x"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/stringf/666Xabc"));
+ nvlist_add_stringf(nvl, "nvlist/stringf/666Xabc", "%d%c%s", 666, 'X', "abc");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/666Xabc"));
+
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/true"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/false"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/0"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/1"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/-1"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/x"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/666Xabc"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+
+ cnvl = nvlist_get_nvlist(nvl, "nvlist/nvlist");
+ CHECK(nvlist_exists_null(cnvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(cnvl, "nvlist/bool/true"));
+ CHECK(nvlist_exists_bool(cnvl, "nvlist/bool/false"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/0"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/1"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/-1"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/UINT64_MAX"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/INT64_MIN"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/INT64_MAX"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/stringf/"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/stringf/x"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/stringf/666Xabc"));
+ CHECK(nvlist_exists_descriptor(cnvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(cnvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(cnvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_exists_test.c b/lib/libnv/tests/nvlist_exists_test.c
new file mode 100644
index 0000000..cb595d7
--- /dev/null
+++ b/lib/libnv/tests/nvlist_exists_test.c
@@ -0,0 +1,321 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ nvlist_t *nvl;
+
+ printf("1..232\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/null"));
+ nvlist_add_null(nvl, "nvlist/null");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/null"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/bool"));
+ nvlist_add_bool(nvl, "nvlist/bool", true);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/bool"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/number"));
+ nvlist_add_number(nvl, "nvlist/number", 0);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/number"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/string"));
+ nvlist_add_string(nvl, "nvlist/string", "test");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/string"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/nvlist"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/nvlist"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/descriptor"));
+ nvlist_add_descriptor(nvl, "nvlist/descriptor", STDERR_FILENO);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/descriptor"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+ nvlist_add_binary(nvl, "nvlist/binary", "test", 4);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/binary"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_exists(nvl, "nvlist/null"));
+ CHECK(nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_null(nvl, "nvlist/null");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_bool(nvl, "nvlist/bool");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_number(nvl, "nvlist/number");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_string(nvl, "nvlist/string");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_nvlist(nvl, "nvlist/nvlist");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_descriptor(nvl, "nvlist/descriptor");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_binary(nvl, "nvlist/binary");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_free_test.c b/lib/libnv/tests/nvlist_free_test.c
new file mode 100644
index 0000000..4417a44
--- /dev/null
+++ b/lib/libnv/tests/nvlist_free_test.c
@@ -0,0 +1,221 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ nvlist_t *nvl;
+
+ printf("1..114\n");
+
+ nvl = nvlist_create(0);
+
+ nvlist_add_null(nvl, "nvlist/null");
+ nvlist_add_bool(nvl, "nvlist/bool", true);
+ nvlist_add_number(nvl, "nvlist/number", 0);
+ nvlist_add_string(nvl, "nvlist/string", "test");
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ nvlist_add_descriptor(nvl, "nvlist/descriptor", STDERR_FILENO);
+ nvlist_add_binary(nvl, "nvlist/binary", "test", 4);
+
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_null(nvl, "nvlist/null");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_bool(nvl, "nvlist/bool");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_number(nvl, "nvlist/number");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_string(nvl, "nvlist/string");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_nvlist(nvl, "nvlist/nvlist");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_descriptor(nvl, "nvlist/descriptor");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_binary(nvl, "nvlist/binary");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_empty(nvl));
+
+ nvlist_add_null(nvl, "nvlist/null");
+ nvlist_add_bool(nvl, "nvlist/bool", true);
+ nvlist_add_number(nvl, "nvlist/number", 0);
+ nvlist_add_string(nvl, "nvlist/string", "test");
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ nvlist_add_descriptor(nvl, "nvlist/descriptor", STDERR_FILENO);
+ nvlist_add_binary(nvl, "nvlist/binary", "test", 4);
+
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/null");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/bool");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/number");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/string");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/nvlist");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/descriptor");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/binary");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_get_test.c b/lib/libnv/tests/nvlist_get_test.c
new file mode 100644
index 0000000..b4468db
--- /dev/null
+++ b/lib/libnv/tests/nvlist_get_test.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+int
+main(void)
+{
+ const nvlist_t *cnvl;
+ nvlist_t *nvl;
+ size_t size;
+
+ printf("1..83\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/true"));
+ nvlist_add_bool(nvl, "nvlist/bool/true", true);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/true") == true);
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/false"));
+ nvlist_add_bool(nvl, "nvlist/bool/false", false);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/false") == false);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/0"));
+ nvlist_add_number(nvl, "nvlist/number/0", 0);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/0") == 0);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/1"));
+ nvlist_add_number(nvl, "nvlist/number/1", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/1") == 1);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/-1"));
+ nvlist_add_number(nvl, "nvlist/number/-1", -1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK((int)nvlist_get_number(nvl, "nvlist/number/-1") == -1);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/UINT64_MAX") == UINT64_MAX);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MIN") == INT64_MIN);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MAX") == INT64_MAX);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/"));
+ nvlist_add_string(nvl, "nvlist/string/", "");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/"), "") == 0);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/x"));
+ nvlist_add_string(nvl, "nvlist/string/x", "x");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/x"), "x") == 0);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"), "abcdefghijklmnopqrstuvwxyz") == 0);
+
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO")));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", &size), "x", 1) == 0);
+ CHECK(size == 1);
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ CHECK(nvlist_error(nvl) == 0);
+ cnvl = nvlist_get_nvlist(nvl, "nvlist/nvlist");
+ CHECK(nvlist_get_bool(cnvl, "nvlist/bool/true") == true);
+ CHECK(nvlist_get_bool(cnvl, "nvlist/bool/false") == false);
+ CHECK(nvlist_get_number(cnvl, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(cnvl, "nvlist/number/1") == 1);
+ CHECK((int)nvlist_get_number(cnvl, "nvlist/number/-1") == -1);
+ CHECK(nvlist_get_number(cnvl, "nvlist/number/UINT64_MAX") == UINT64_MAX);
+ CHECK((int64_t)nvlist_get_number(cnvl, "nvlist/number/INT64_MIN") == INT64_MIN);
+ CHECK((int64_t)nvlist_get_number(cnvl, "nvlist/number/INT64_MAX") == INT64_MAX);
+ CHECK(strcmp(nvlist_get_string(cnvl, "nvlist/string/"), "") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, "nvlist/string/x"), "x") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"), "abcdefghijklmnopqrstuvwxyz") == 0);
+ /* TODO */
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/x", NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/x", &size), "x", 1) == 0);
+ CHECK(size == 1);
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/true") == true);
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/false") == false);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/1") == 1);
+ CHECK((int)nvlist_get_number(nvl, "nvlist/number/-1") == -1);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/UINT64_MAX") == UINT64_MAX);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MIN") == INT64_MIN);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MAX") == INT64_MAX);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/"), "") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/x"), "x") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"), "abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO")));
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", &size), "x", 1) == 0);
+ CHECK(size == 1);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_move_test.c b/lib/libnv/tests/nvlist_move_test.c
new file mode 100644
index 0000000..760399d
--- /dev/null
+++ b/lib/libnv/tests/nvlist_move_test.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ const nvlist_t *cnvl;
+ nvlist_t *nvl;
+ void *ptr;
+ size_t size;
+ int fd;
+
+ printf("1..52\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/"));
+ ptr = strdup("");
+ CHECK(ptr != NULL);
+ nvlist_move_string(nvl, "nvlist/string/", ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+ CHECK(ptr == nvlist_get_string(nvl, "nvlist/string/"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/x"));
+ ptr = strdup("x");
+ CHECK(ptr != NULL);
+ nvlist_move_string(nvl, "nvlist/string/x", ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+ CHECK(ptr == nvlist_get_string(nvl, "nvlist/string/x"));
+
+ CHECK(!nvlist_exists_string(nvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ ptr = strdup("abcdefghijklmnopqrstuvwxyz");
+ CHECK(ptr != NULL);
+ nvlist_move_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz",
+ ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(ptr ==
+ nvlist_get_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_descriptor(nvl,
+ "nvlist/descriptor/STDERR_FILENO"));
+ fd = dup(STDERR_FILENO);
+ CHECK(fd >= 0);
+ nvlist_move_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", fd);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(fd ==
+ nvlist_get_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ ptr = malloc(1);
+ CHECK(ptr != NULL);
+ memcpy(ptr, "x", 1);
+ nvlist_move_binary(nvl, "nvlist/binary/x", ptr, 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ CHECK(ptr == nvlist_get_binary(nvl, "nvlist/binary/x", NULL));
+ CHECK(ptr == nvlist_get_binary(nvl, "nvlist/binary/x", &size));
+ CHECK(size == 1);
+
+ CHECK(!nvlist_exists_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ ptr = malloc(sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(ptr != NULL);
+ memcpy(ptr, "abcdefghijklmnopqrstuvwxyz",
+ sizeof("abcdefghijklmnopqrstuvwxyz"));
+ nvlist_move_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz",
+ ptr, sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(ptr == nvlist_get_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL));
+ CHECK(ptr == nvlist_get_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size));
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ ptr = nvlist_clone(nvl);
+ CHECK(ptr != NULL);
+ nvlist_move_nvlist(nvl, "nvlist/nvlist", ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(ptr == nvlist_get_nvlist(nvl, "nvlist/nvlist"));
+
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(nvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+
+ cnvl = nvlist_get_nvlist(nvl, "nvlist/nvlist");
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(cnvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_descriptor(cnvl,
+ "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(cnvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(cnvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_send_recv_test.c b/lib/libnv/tests/nvlist_send_recv_test.c
new file mode 100644
index 0000000..1b083c3
--- /dev/null
+++ b/lib/libnv/tests/nvlist_send_recv_test.c
@@ -0,0 +1,342 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+static void
+child(int sock)
+{
+ nvlist_t *nvl;
+ nvlist_t *empty;
+
+ nvl = nvlist_create(0);
+ empty = nvlist_create(0);
+
+ nvlist_add_bool(nvl, "nvlist/bool/true", true);
+ nvlist_add_bool(nvl, "nvlist/bool/false", false);
+ nvlist_add_number(nvl, "nvlist/number/0", 0);
+ nvlist_add_number(nvl, "nvlist/number/1", 1);
+ nvlist_add_number(nvl, "nvlist/number/-1", -1);
+ nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
+ nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
+ nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
+ nvlist_add_string(nvl, "nvlist/string/", "");
+ nvlist_add_string(nvl, "nvlist/string/x", "x");
+ nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
+ nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
+ nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
+ nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
+ nvlist_move_nvlist(nvl, "nvlist/nvlist/empty", empty);
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+
+ nvlist_send(sock, nvl);
+
+ nvlist_destroy(nvl);
+}
+
+static void
+parent(int sock)
+{
+ nvlist_t *nvl;
+ const nvlist_t *cnvl, *empty;
+ const char *name, *cname;
+ void *cookie, *ccookie;
+ int type, ctype;
+ size_t size;
+
+ nvl = nvlist_recv(sock);
+ CHECK(nvlist_error(nvl) == 0);
+ if (nvlist_error(nvl) != 0)
+ err(1, "nvlist_recv() failed");
+
+ cookie = NULL;
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BOOL);
+ CHECK(strcmp(name, "nvlist/bool/true") == 0);
+ CHECK(nvlist_get_bool(nvl, name) == true);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BOOL);
+ CHECK(strcmp(name, "nvlist/bool/false") == 0);
+ CHECK(nvlist_get_bool(nvl, name) == false);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(nvl, name) == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/1") == 0);
+ CHECK(nvlist_get_number(nvl, name) == 1);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/-1") == 0);
+ CHECK((int)nvlist_get_number(nvl, name) == -1);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/UINT64_MAX") == 0);
+ CHECK(nvlist_get_number(nvl, name) == UINT64_MAX);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/INT64_MIN") == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, name) == INT64_MIN);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/INT64_MAX") == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, name) == INT64_MAX);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_STRING);
+ CHECK(strcmp(name, "nvlist/string/") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, name), "") == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_STRING);
+ CHECK(strcmp(name, "nvlist/string/x") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, name), "x") == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_STRING);
+ CHECK(strcmp(name, "nvlist/string/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, name), "abcdefghijklmnopqrstuvwxyz") == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_DESCRIPTOR);
+ CHECK(strcmp(name, "nvlist/descriptor/STDERR_FILENO") == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(nvl, name)));
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BINARY);
+ CHECK(strcmp(name, "nvlist/binary/x") == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, &size), "x", 1) == 0);
+ CHECK(size == 1);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BINARY);
+ CHECK(strcmp(name, "nvlist/binary/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NVLIST);
+ CHECK(strcmp(name, "nvlist/nvlist/empty") == 0);
+ cnvl = nvlist_get_nvlist(nvl, name);
+ CHECK(nvlist_empty(cnvl));
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NVLIST);
+ CHECK(strcmp(name, "nvlist/nvlist") == 0);
+ cnvl = nvlist_get_nvlist(nvl, name);
+
+ ccookie = NULL;
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BOOL);
+ CHECK(strcmp(cname, "nvlist/bool/true") == 0);
+ CHECK(nvlist_get_bool(cnvl, cname) == true);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BOOL);
+ CHECK(strcmp(cname, "nvlist/bool/false") == 0);
+ CHECK(nvlist_get_bool(cnvl, cname) == false);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(cnvl, cname) == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/1") == 0);
+ CHECK(nvlist_get_number(cnvl, cname) == 1);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/-1") == 0);
+ CHECK((int)nvlist_get_number(cnvl, cname) == -1);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/UINT64_MAX") == 0);
+ CHECK(nvlist_get_number(cnvl, cname) == UINT64_MAX);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/INT64_MIN") == 0);
+ CHECK((int64_t)nvlist_get_number(cnvl, cname) == INT64_MIN);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/INT64_MAX") == 0);
+ CHECK((int64_t)nvlist_get_number(cnvl, cname) == INT64_MAX);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_STRING);
+ CHECK(strcmp(cname, "nvlist/string/") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, cname), "") == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_STRING);
+ CHECK(strcmp(cname, "nvlist/string/x") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, cname), "x") == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_STRING);
+ CHECK(strcmp(cname, "nvlist/string/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, cname), "abcdefghijklmnopqrstuvwxyz") == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_DESCRIPTOR);
+ CHECK(strcmp(cname, "nvlist/descriptor/STDERR_FILENO") == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BINARY);
+ CHECK(strcmp(cname, "nvlist/binary/x") == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, &size), "x", 1) == 0);
+ CHECK(size == 1);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BINARY);
+ CHECK(strcmp(cname, "nvlist/binary/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NVLIST);
+ CHECK(strcmp(cname, "nvlist/nvlist/empty") == 0);
+ empty = nvlist_get_nvlist(cnvl, cname);
+ CHECK(nvlist_empty(empty));
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname == NULL);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name == NULL);
+}
+
+int
+main(void)
+{
+ int status, socks[2];
+ pid_t pid;
+
+ printf("1..134\n");
+ fflush(stdout);
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, socks) < 0)
+ err(1, "socketpair() failed");
+ pid = fork();
+ switch (pid) {
+ case -1:
+ /* Failure. */
+ err(1, "unable to fork");
+ case 0:
+ /* Child. */
+ close(socks[0]);
+ child(socks[1]);
+ return (0);
+ default:
+ /* Parent. */
+ close(socks[1]);
+ parent(socks[0]);
+ break;
+ }
+
+ if (waitpid(pid, &status, 0) < 0)
+ err(1, "waitpid() failed");
+
+ return (0);
+}
diff --git a/lib/msun/tests/Makefile b/lib/msun/tests/Makefile
index 7199ea7..ffa1765 100644
--- a/lib/msun/tests/Makefile
+++ b/lib/msun/tests/Makefile
@@ -36,12 +36,34 @@ NETBSD_ATF_TESTS_C+= sqrt_test
NETBSD_ATF_TESTS_C+= tan_test
NETBSD_ATF_TESTS_C+= tanh_test
+TAP_TESTS_C+= cexp_test
+TAP_TESTS_C+= conj_test
+TAP_TESTS_C+= csqrt_test
+TAP_TESTS_C+= fenv_test
+TAP_TESTS_C+= fmaxmin_test
+TAP_TESTS_C+= ilogb_test
+TAP_TESTS_C+= invctrig_test
+TAP_TESTS_C+= logarithm_test
+TAP_TESTS_C+= lrint_test
+TAP_TESTS_C+= nan_test
+TAP_TESTS_C+= nearbyint_test
+TAP_TESTS_C+= next_test
+TAP_TESTS_C+= rem_test
+TAP_TESTS_C+= trig_test
+
+.for t in ${TAP_TESTS_C}
+CFLAGS.$t+= -O0
+CFLAGS.$t+= -I${SRCTOP}/tools/regression/lib/msun
+.endfor
+
CSTD= c99
LDADD+= -lm
DPADD+= ${LIBM}
#COPTS+= -Wfloat-equal
+IGNORE_PRAGMA=
+
# Copied from lib/msun/Makefile
.if ${MACHINE_CPUARCH} == "i386"
ARCH_SUBDIR= i387
diff --git a/lib/msun/tests/cexp_test.c b/lib/msun/tests/cexp_test.c
new file mode 100644
index 0000000..6be71ad
--- /dev/null
+++ b/lib/msun/tests/cexp_test.c
@@ -0,0 +1,322 @@
+/*-
+ * Copyright (c) 2008-2011 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Tests for corner cases in cexp*().
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <complex.h>
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "test-utils.h"
+
+#pragma STDC FENV_ACCESS ON
+#pragma STDC CX_LIMITED_RANGE OFF
+
+/*
+ * Test that a function returns the correct value and sets the
+ * exception flags correctly. The exceptmask specifies which
+ * exceptions we should check. We need to be lenient for several
+ * reasons, but mainly because on some architectures it's impossible
+ * to raise FE_OVERFLOW without raising FE_INEXACT. In some cases,
+ * whether cexp() raises an invalid exception is unspecified.
+ *
+ * These are macros instead of functions so that assert provides more
+ * meaningful error messages.
+ *
+ * XXX The volatile here is to avoid gcc's bogus constant folding and work
+ * around the lack of support for the FENV_ACCESS pragma.
+ */
+#define test(func, z, result, exceptmask, excepts, checksign) do { \
+ volatile long double complex _d = z; \
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
+ assert(cfpequal_cs((func)(_d), (result), (checksign))); \
+ assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
+} while (0)
+
+/* Test within a given tolerance. */
+#define test_tol(func, z, result, tol) do { \
+ volatile long double complex _d = z; \
+ assert(cfpequal_tol((func)(_d), (result), (tol), \
+ FPE_ABS_ZERO | CS_BOTH)); \
+} while (0)
+
+/* Test all the functions that compute cexp(x). */
+#define testall(x, result, exceptmask, excepts, checksign) do { \
+ test(cexp, x, result, exceptmask, excepts, checksign); \
+ test(cexpf, x, result, exceptmask, excepts, checksign); \
+} while (0)
+
+/*
+ * Test all the functions that compute cexp(x), within a given tolerance.
+ * The tolerance is specified in ulps.
+ */
+#define testall_tol(x, result, tol) do { \
+ test_tol(cexp, x, result, tol * DBL_ULP()); \
+ test_tol(cexpf, x, result, tol * FLT_ULP()); \
+} while (0)
+
+/* Various finite non-zero numbers to test. */
+static const float finites[] =
+{ -42.0e20, -1.0, -1.0e-10, -0.0, 0.0, 1.0e-10, 1.0, 42.0e20 };
+
+
+/* Tests for 0 */
+void
+test_zero(void)
+{
+
+ /* cexp(0) = 1, no exceptions raised */
+ testall(0.0, 1.0, ALL_STD_EXCEPT, 0, 1);
+ testall(-0.0, 1.0, ALL_STD_EXCEPT, 0, 1);
+ testall(CMPLXL(0.0, -0.0), CMPLXL(1.0, -0.0), ALL_STD_EXCEPT, 0, 1);
+ testall(CMPLXL(-0.0, -0.0), CMPLXL(1.0, -0.0), ALL_STD_EXCEPT, 0, 1);
+}
+
+/*
+ * Tests for NaN. The signs of the results are indeterminate unless the
+ * imaginary part is 0.
+ */
+void
+test_nan()
+{
+ int i;
+
+ /* cexp(x + NaNi) = NaN + NaNi and optionally raises invalid */
+ /* cexp(NaN + yi) = NaN + NaNi and optionally raises invalid (|y|>0) */
+ for (i = 0; i < nitems(finites); i++) {
+ printf("# Run %d..\n", i);
+ testall(CMPLXL(finites[i], NAN), CMPLXL(NAN, NAN),
+ ALL_STD_EXCEPT & ~FE_INVALID, 0, 0);
+ if (finites[i] == 0.0)
+ continue;
+ /* XXX FE_INEXACT shouldn't be raised here */
+ testall(CMPLXL(NAN, finites[i]), CMPLXL(NAN, NAN),
+ ALL_STD_EXCEPT & ~(FE_INVALID | FE_INEXACT), 0, 0);
+ }
+
+ /* cexp(NaN +- 0i) = NaN +- 0i */
+ testall(CMPLXL(NAN, 0.0), CMPLXL(NAN, 0.0), ALL_STD_EXCEPT, 0, 1);
+ testall(CMPLXL(NAN, -0.0), CMPLXL(NAN, -0.0), ALL_STD_EXCEPT, 0, 1);
+
+ /* cexp(inf + NaN i) = inf + nan i */
+ testall(CMPLXL(INFINITY, NAN), CMPLXL(INFINITY, NAN),
+ ALL_STD_EXCEPT, 0, 0);
+ /* cexp(-inf + NaN i) = 0 */
+ testall(CMPLXL(-INFINITY, NAN), CMPLXL(0.0, 0.0),
+ ALL_STD_EXCEPT, 0, 0);
+ /* cexp(NaN + NaN i) = NaN + NaN i */
+ testall(CMPLXL(NAN, NAN), CMPLXL(NAN, NAN),
+ ALL_STD_EXCEPT, 0, 0);
+}
+
+void
+test_inf(void)
+{
+ int i;
+
+ /* cexp(x + inf i) = NaN + NaNi and raises invalid */
+ for (i = 0; i < nitems(finites); i++) {
+ printf("# Run %d..\n", i);
+ testall(CMPLXL(finites[i], INFINITY), CMPLXL(NAN, NAN),
+ ALL_STD_EXCEPT, FE_INVALID, 1);
+ }
+ /* cexp(-inf + yi) = 0 * (cos(y) + sin(y)i) */
+ /* XXX shouldn't raise an inexact exception */
+ testall(CMPLXL(-INFINITY, M_PI_4), CMPLXL(0.0, 0.0),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ testall(CMPLXL(-INFINITY, 3 * M_PI_4), CMPLXL(-0.0, 0.0),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ testall(CMPLXL(-INFINITY, 5 * M_PI_4), CMPLXL(-0.0, -0.0),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ testall(CMPLXL(-INFINITY, 7 * M_PI_4), CMPLXL(0.0, -0.0),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ testall(CMPLXL(-INFINITY, 0.0), CMPLXL(0.0, 0.0),
+ ALL_STD_EXCEPT, 0, 1);
+ testall(CMPLXL(-INFINITY, -0.0), CMPLXL(0.0, -0.0),
+ ALL_STD_EXCEPT, 0, 1);
+ /* cexp(inf + yi) = inf * (cos(y) + sin(y)i) (except y=0) */
+ /* XXX shouldn't raise an inexact exception */
+ testall(CMPLXL(INFINITY, M_PI_4), CMPLXL(INFINITY, INFINITY),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ testall(CMPLXL(INFINITY, 3 * M_PI_4), CMPLXL(-INFINITY, INFINITY),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ testall(CMPLXL(INFINITY, 5 * M_PI_4), CMPLXL(-INFINITY, -INFINITY),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ testall(CMPLXL(INFINITY, 7 * M_PI_4), CMPLXL(INFINITY, -INFINITY),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ /* cexp(inf + 0i) = inf + 0i */
+ testall(CMPLXL(INFINITY, 0.0), CMPLXL(INFINITY, 0.0),
+ ALL_STD_EXCEPT, 0, 1);
+ testall(CMPLXL(INFINITY, -0.0), CMPLXL(INFINITY, -0.0),
+ ALL_STD_EXCEPT, 0, 1);
+}
+
+void
+test_reals(void)
+{
+ int i;
+
+ for (i = 0; i < nitems(finites); i++) {
+ /* XXX could check exceptions more meticulously */
+ printf("# Run %d..\n", i);
+ test(cexp, CMPLXL(finites[i], 0.0),
+ CMPLXL(exp(finites[i]), 0.0),
+ FE_INVALID | FE_DIVBYZERO, 0, 1);
+ test(cexp, CMPLXL(finites[i], -0.0),
+ CMPLXL(exp(finites[i]), -0.0),
+ FE_INVALID | FE_DIVBYZERO, 0, 1);
+ test(cexpf, CMPLXL(finites[i], 0.0),
+ CMPLXL(expf(finites[i]), 0.0),
+ FE_INVALID | FE_DIVBYZERO, 0, 1);
+ test(cexpf, CMPLXL(finites[i], -0.0),
+ CMPLXL(expf(finites[i]), -0.0),
+ FE_INVALID | FE_DIVBYZERO, 0, 1);
+ }
+}
+
+void
+test_imaginaries(void)
+{
+ int i;
+
+ for (i = 0; i < nitems(finites); i++) {
+ printf("# Run %d..\n", i);
+ test(cexp, CMPLXL(0.0, finites[i]),
+ CMPLXL(cos(finites[i]), sin(finites[i])),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ test(cexp, CMPLXL(-0.0, finites[i]),
+ CMPLXL(cos(finites[i]), sin(finites[i])),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ test(cexpf, CMPLXL(0.0, finites[i]),
+ CMPLXL(cosf(finites[i]), sinf(finites[i])),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ test(cexpf, CMPLXL(-0.0, finites[i]),
+ CMPLXL(cosf(finites[i]), sinf(finites[i])),
+ ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
+ }
+}
+
+void
+test_small(void)
+{
+ static const double tests[] = {
+ /* csqrt(a + bI) = x + yI */
+ /* a b x y */
+ 1.0, M_PI_4, M_SQRT2 * 0.5 * M_E, M_SQRT2 * 0.5 * M_E,
+ -1.0, M_PI_4, M_SQRT2 * 0.5 / M_E, M_SQRT2 * 0.5 / M_E,
+ 2.0, M_PI_2, 0.0, M_E * M_E,
+ M_LN2, M_PI, -2.0, 0.0,
+ };
+ double a, b;
+ double x, y;
+ int i;
+
+ for (i = 0; i < nitems(tests); i += 4) {
+ printf("# Run %d..\n", i);
+ a = tests[i];
+ b = tests[i + 1];
+ x = tests[i + 2];
+ y = tests[i + 3];
+ test_tol(cexp, CMPLXL(a, b), CMPLXL(x, y), 3 * DBL_ULP());
+
+ /* float doesn't have enough precision to pass these tests */
+ if (x == 0 || y == 0)
+ continue;
+ test_tol(cexpf, CMPLXL(a, b), CMPLXL(x, y), 1 * FLT_ULP());
+ }
+}
+
+/* Test inputs with a real part r that would overflow exp(r). */
+void
+test_large(void)
+{
+
+ test_tol(cexp, CMPLXL(709.79, 0x1p-1074),
+ CMPLXL(INFINITY, 8.94674309915433533273e-16), DBL_ULP());
+ test_tol(cexp, CMPLXL(1000, 0x1p-1074),
+ CMPLXL(INFINITY, 9.73344457300016401328e+110), DBL_ULP());
+ test_tol(cexp, CMPLXL(1400, 0x1p-1074),
+ CMPLXL(INFINITY, 5.08228858149196559681e+284), DBL_ULP());
+ test_tol(cexp, CMPLXL(900, 0x1.23456789abcdep-1020),
+ CMPLXL(INFINITY, 7.42156649354218408074e+83), DBL_ULP());
+ test_tol(cexp, CMPLXL(1300, 0x1.23456789abcdep-1020),
+ CMPLXL(INFINITY, 3.87514844965996756704e+257), DBL_ULP());
+
+ test_tol(cexpf, CMPLXL(88.73, 0x1p-149),
+ CMPLXL(INFINITY, 4.80265603e-07), 2 * FLT_ULP());
+ test_tol(cexpf, CMPLXL(90, 0x1p-149),
+ CMPLXL(INFINITY, 1.7101492622e-06f), 2 * FLT_ULP());
+ test_tol(cexpf, CMPLXL(192, 0x1p-149),
+ CMPLXL(INFINITY, 3.396809344e+38f), 2 * FLT_ULP());
+ test_tol(cexpf, CMPLXL(120, 0x1.234568p-120),
+ CMPLXL(INFINITY, 1.1163382522e+16f), 2 * FLT_ULP());
+ test_tol(cexpf, CMPLXL(170, 0x1.234568p-120),
+ CMPLXL(INFINITY, 5.7878851079e+37f), 2 * FLT_ULP());
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..7\n");
+
+ test_zero();
+ printf("ok 1 - cexp zero\n");
+
+ test_nan();
+ printf("ok 2 - cexp nan\n");
+
+ test_inf();
+ printf("ok 3 - cexp inf\n");
+
+#if defined(__i386__)
+ printf("not ok 4 - cexp reals # TODO: PR # 191676 fails assertion on i386\n");
+#else
+ test_reals();
+ printf("ok 4 - cexp reals\n");
+#endif
+
+ test_imaginaries();
+ printf("ok 5 - cexp imaginaries\n");
+
+ test_small();
+ printf("ok 6 - cexp small\n");
+
+ test_large();
+ printf("ok 7 - cexp large\n");
+
+ return (0);
+}
diff --git a/lib/msun/tests/conj_test.c b/lib/msun/tests/conj_test.c
new file mode 100644
index 0000000..7426f9e
--- /dev/null
+++ b/lib/msun/tests/conj_test.c
@@ -0,0 +1,139 @@
+/*-
+ * Copyright (c) 2008 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Tests for conj{,f,l}()
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <complex.h>
+#include <fenv.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "test-utils.h"
+
+#pragma STDC CX_LIMITED_RANGE OFF
+
+/* Make sure gcc doesn't use builtin versions of these or honor __pure2. */
+static float complex (*libconjf)(float complex) = conjf;
+static double complex (*libconj)(double complex) = conj;
+static long double complex (*libconjl)(long double complex) = conjl;
+static float (*libcrealf)(float complex) = crealf;
+static double (*libcreal)(double complex) = creal;
+static long double (*libcreall)(long double complex) = creall;
+static float (*libcimagf)(float complex) = cimagf;
+static double (*libcimag)(double complex) = cimag;
+static long double (*libcimagl)(long double complex) = cimagl;
+
+static const double tests[] = {
+ /* a + bI */
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ -1.0, 0.0,
+ 1.0, -0.0,
+ 0.0, -1.0,
+ 2.0, 4.0,
+ 0.0, INFINITY,
+ 0.0, -INFINITY,
+ INFINITY, 0.0,
+ NAN, 1.0,
+ 1.0, NAN,
+ NAN, NAN,
+ -INFINITY, INFINITY,
+};
+
+int
+main(int argc, char *argv[])
+{
+ static const int ntests = sizeof(tests) / sizeof(tests[0]) / 2;
+ complex float in;
+ complex long double expected;
+ int i;
+
+ printf("1..%d\n", ntests * 3);
+
+ for (i = 0; i < ntests; i++) {
+ __real__ expected = __real__ in = tests[2 * i];
+ __imag__ in = tests[2 * i + 1];
+ __imag__ expected = -cimag(in);
+
+ assert(fpequal(libcrealf(in), __real__ in));
+ assert(fpequal(libcreal(in), __real__ in));
+ assert(fpequal(libcreall(in), __real__ in));
+ assert(fpequal(libcimagf(in), __imag__ in));
+ assert(fpequal(libcimag(in), __imag__ in));
+ assert(fpequal(libcimagl(in), __imag__ in));
+
+ feclearexcept(FE_ALL_EXCEPT);
+ if (!cfpequal(libconjf(in), expected)) {
+ printf("not ok %d\t# conjf(%#.2g + %#.2gI): "
+ "wrong value\n",
+ 3 * i + 1, creal(in), cimag(in));
+ } else if (fetestexcept(FE_ALL_EXCEPT)) {
+ printf("not ok %d\t# conjf(%#.2g + %#.2gI): "
+ "threw an exception\n",
+ 3 * i + 1, creal(in), cimag(in));
+ } else {
+ printf("ok %d\t\t# conjf(%#.2g + %#.2gI)\n",
+ 3 * i + 1, creal(in), cimag(in));
+ }
+
+ feclearexcept(FE_ALL_EXCEPT);
+ if (!cfpequal(libconj(in), expected)) {
+ printf("not ok %d\t# conj(%#.2g + %#.2gI): "
+ "wrong value\n",
+ 3 * i + 2, creal(in), cimag(in));
+ } else if (fetestexcept(FE_ALL_EXCEPT)) {
+ printf("not ok %d\t# conj(%#.2g + %#.2gI): "
+ "threw an exception\n",
+ 3 * i + 2, creal(in), cimag(in));
+ } else {
+ printf("ok %d\t\t# conj(%#.2g + %#.2gI)\n",
+ 3 * i + 2, creal(in), cimag(in));
+ }
+
+ feclearexcept(FE_ALL_EXCEPT);
+ if (!cfpequal(libconjl(in), expected)) {
+ printf("not ok %d\t# conjl(%#.2g + %#.2gI): "
+ "wrong value\n",
+ 3 * i + 3, creal(in), cimag(in));
+ } else if (fetestexcept(FE_ALL_EXCEPT)) {
+ printf("not ok %d\t# conjl(%#.2g + %#.2gI): "
+ "threw an exception\n",
+ 3 * i + 3, creal(in), cimag(in));
+ } else {
+ printf("ok %d\t\t# conjl(%#.2g + %#.2gI)\n",
+ 3 * i + 3, creal(in), cimag(in));
+ }
+ }
+
+ return (0);
+}
diff --git a/lib/msun/tests/csqrt_test.c b/lib/msun/tests/csqrt_test.c
new file mode 100644
index 0000000..aa119d1
--- /dev/null
+++ b/lib/msun/tests/csqrt_test.c
@@ -0,0 +1,295 @@
+/*-
+ * Copyright (c) 2007 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Tests for csqrt{,f}()
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <complex.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "test-utils.h"
+
+/*
+ * This is a test hook that can point to csqrtl(), _csqrt(), or to _csqrtf().
+ * The latter two convert to float or double, respectively, and test csqrtf()
+ * and csqrt() with the same arguments.
+ */
+long double complex (*t_csqrt)(long double complex);
+
+static long double complex
+_csqrtf(long double complex d)
+{
+
+ return (csqrtf((float complex)d));
+}
+
+static long double complex
+_csqrt(long double complex d)
+{
+
+ return (csqrt((double complex)d));
+}
+
+#pragma STDC CX_LIMITED_RANGE OFF
+
+/*
+ * Compare d1 and d2 using special rules: NaN == NaN and +0 != -0.
+ * Fail an assertion if they differ.
+ */
+static void
+assert_equal(long double complex d1, long double complex d2)
+{
+
+ assert(cfpequal(d1, d2));
+}
+
+/*
+ * Test csqrt for some finite arguments where the answer is exact.
+ * (We do not test if it produces correctly rounded answers when the
+ * result is inexact, nor do we check whether it throws spurious
+ * exceptions.)
+ */
+static void
+test_finite()
+{
+ static const double tests[] = {
+ /* csqrt(a + bI) = x + yI */
+ /* a b x y */
+ 0, 8, 2, 2,
+ 0, -8, 2, -2,
+ 4, 0, 2, 0,
+ -4, 0, 0, 2,
+ 3, 4, 2, 1,
+ 3, -4, 2, -1,
+ -3, 4, 1, 2,
+ -3, -4, 1, -2,
+ 5, 12, 3, 2,
+ 7, 24, 4, 3,
+ 9, 40, 5, 4,
+ 11, 60, 6, 5,
+ 13, 84, 7, 6,
+ 33, 56, 7, 4,
+ 39, 80, 8, 5,
+ 65, 72, 9, 4,
+ 987, 9916, 74, 67,
+ 5289, 6640, 83, 40,
+ 460766389075.0, 16762287900.0, 678910, 12345
+ };
+ /*
+ * We also test some multiples of the above arguments. This
+ * array defines which multiples we use. Note that these have
+ * to be small enough to not cause overflow for float precision
+ * with all of the constants in the above table.
+ */
+ static const double mults[] = {
+ 1,
+ 2,
+ 3,
+ 13,
+ 16,
+ 0x1.p30,
+ 0x1.p-30,
+ };
+
+ double a, b;
+ double x, y;
+ int i, j;
+
+ for (i = 0; i < nitems(tests); i += 4) {
+ for (j = 0; j < nitems(mults); j++) {
+ a = tests[i] * mults[j] * mults[j];
+ b = tests[i + 1] * mults[j] * mults[j];
+ x = tests[i + 2] * mults[j];
+ y = tests[i + 3] * mults[j];
+ assert(t_csqrt(CMPLXL(a, b)) == CMPLXL(x, y));
+ }
+ }
+
+}
+
+/*
+ * Test the handling of +/- 0.
+ */
+static void
+test_zeros()
+{
+
+ assert_equal(t_csqrt(CMPLXL(0.0, 0.0)), CMPLXL(0.0, 0.0));
+ assert_equal(t_csqrt(CMPLXL(-0.0, 0.0)), CMPLXL(0.0, 0.0));
+ assert_equal(t_csqrt(CMPLXL(0.0, -0.0)), CMPLXL(0.0, -0.0));
+ assert_equal(t_csqrt(CMPLXL(-0.0, -0.0)), CMPLXL(0.0, -0.0));
+}
+
+/*
+ * Test the handling of infinities when the other argument is not NaN.
+ */
+static void
+test_infinities()
+{
+ static const double vals[] = {
+ 0.0,
+ -0.0,
+ 42.0,
+ -42.0,
+ INFINITY,
+ -INFINITY,
+ };
+
+ int i;
+
+ for (i = 0; i < nitems(vals); i++) {
+ if (isfinite(vals[i])) {
+ assert_equal(t_csqrt(CMPLXL(-INFINITY, vals[i])),
+ CMPLXL(0.0, copysignl(INFINITY, vals[i])));
+ assert_equal(t_csqrt(CMPLXL(INFINITY, vals[i])),
+ CMPLXL(INFINITY, copysignl(0.0, vals[i])));
+ }
+ assert_equal(t_csqrt(CMPLXL(vals[i], INFINITY)),
+ CMPLXL(INFINITY, INFINITY));
+ assert_equal(t_csqrt(CMPLXL(vals[i], -INFINITY)),
+ CMPLXL(INFINITY, -INFINITY));
+ }
+}
+
+/*
+ * Test the handling of NaNs.
+ */
+static void
+test_nans()
+{
+
+ assert(creall(t_csqrt(CMPLXL(INFINITY, NAN))) == INFINITY);
+ assert(isnan(cimagl(t_csqrt(CMPLXL(INFINITY, NAN)))));
+
+ assert(isnan(creall(t_csqrt(CMPLXL(-INFINITY, NAN)))));
+ assert(isinf(cimagl(t_csqrt(CMPLXL(-INFINITY, NAN)))));
+
+ assert_equal(t_csqrt(CMPLXL(NAN, INFINITY)),
+ CMPLXL(INFINITY, INFINITY));
+ assert_equal(t_csqrt(CMPLXL(NAN, -INFINITY)),
+ CMPLXL(INFINITY, -INFINITY));
+
+ assert_equal(t_csqrt(CMPLXL(0.0, NAN)), CMPLXL(NAN, NAN));
+ assert_equal(t_csqrt(CMPLXL(-0.0, NAN)), CMPLXL(NAN, NAN));
+ assert_equal(t_csqrt(CMPLXL(42.0, NAN)), CMPLXL(NAN, NAN));
+ assert_equal(t_csqrt(CMPLXL(-42.0, NAN)), CMPLXL(NAN, NAN));
+ assert_equal(t_csqrt(CMPLXL(NAN, 0.0)), CMPLXL(NAN, NAN));
+ assert_equal(t_csqrt(CMPLXL(NAN, -0.0)), CMPLXL(NAN, NAN));
+ assert_equal(t_csqrt(CMPLXL(NAN, 42.0)), CMPLXL(NAN, NAN));
+ assert_equal(t_csqrt(CMPLXL(NAN, -42.0)), CMPLXL(NAN, NAN));
+ assert_equal(t_csqrt(CMPLXL(NAN, NAN)), CMPLXL(NAN, NAN));
+}
+
+/*
+ * Test whether csqrt(a + bi) works for inputs that are large enough to
+ * cause overflow in hypot(a, b) + a. In this case we are using
+ * csqrt(115 + 252*I) == 14 + 9*I
+ * scaled up to near MAX_EXP.
+ */
+static void
+test_overflow(int maxexp)
+{
+ long double a, b;
+ long double complex result;
+
+ a = ldexpl(115 * 0x1p-8, maxexp);
+ b = ldexpl(252 * 0x1p-8, maxexp);
+ result = t_csqrt(CMPLXL(a, b));
+ assert(creall(result) == ldexpl(14 * 0x1p-4, maxexp / 2));
+ assert(cimagl(result) == ldexpl(9 * 0x1p-4, maxexp / 2));
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..15\n");
+
+ /* Test csqrt() */
+ t_csqrt = _csqrt;
+
+ test_finite();
+ printf("ok 1 - csqrt\n");
+
+ test_zeros();
+ printf("ok 2 - csqrt\n");
+
+ test_infinities();
+ printf("ok 3 - csqrt\n");
+
+ test_nans();
+ printf("ok 4 - csqrt\n");
+
+ test_overflow(DBL_MAX_EXP);
+ printf("ok 5 - csqrt\n");
+
+ /* Now test csqrtf() */
+ t_csqrt = _csqrtf;
+
+ test_finite();
+ printf("ok 6 - csqrt\n");
+
+ test_zeros();
+ printf("ok 7 - csqrt\n");
+
+ test_infinities();
+ printf("ok 8 - csqrt\n");
+
+ test_nans();
+ printf("ok 9 - csqrt\n");
+
+ test_overflow(FLT_MAX_EXP);
+ printf("ok 10 - csqrt\n");
+
+ /* Now test csqrtl() */
+ t_csqrt = csqrtl;
+
+ test_finite();
+ printf("ok 11 - csqrt\n");
+
+ test_zeros();
+ printf("ok 12 - csqrt\n");
+
+ test_infinities();
+ printf("ok 13 - csqrt\n");
+
+ test_nans();
+ printf("ok 14 - csqrt\n");
+
+ test_overflow(LDBL_MAX_EXP);
+ printf("ok 15 - csqrt\n");
+
+ return (0);
+}
diff --git a/lib/msun/tests/fenv_test.c b/lib/msun/tests/fenv_test.c
new file mode 100644
index 0000000..0ea6e42
--- /dev/null
+++ b/lib/msun/tests/fenv_test.c
@@ -0,0 +1,576 @@
+/*-
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Test the correctness and C99-compliance of various fenv.h features.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <err.h>
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * Implementations are permitted to define additional exception flags
+ * not specified in the standard, so it is not necessarily true that
+ * FE_ALL_EXCEPT == ALL_STD_EXCEPT.
+ */
+#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
+ FE_OVERFLOW | FE_UNDERFLOW)
+
+#define NEXCEPTS (sizeof(std_excepts) / sizeof(std_excepts[0]))
+
+static const int std_excepts[] = {
+ FE_INVALID,
+ FE_DIVBYZERO,
+ FE_OVERFLOW,
+ FE_UNDERFLOW,
+ FE_INEXACT,
+};
+
+/* init_exceptsets() initializes this to the power set of std_excepts[] */
+static int std_except_sets[1 << NEXCEPTS];
+
+static void init_exceptsets(void);
+
+static void test_dfl_env(void);
+static void test_fegsetenv(void);
+static void test_fegsetexceptflag(void);
+static void test_masking(void);
+static void test_fegsetround(void);
+static void test_feholdupdate(void);
+static void test_feraiseexcept(void);
+static void test_fetestclearexcept(void);
+
+static int getround(void);
+static void raiseexcept(int excepts);
+static void trap_handler(int sig);
+
+#pragma STDC FENV_ACCESS ON
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..8\n");
+ init_exceptsets();
+ test_dfl_env();
+ printf("ok 1 - fenv\n");
+ test_fetestclearexcept();
+ printf("ok 2 - fenv\n");
+ test_fegsetexceptflag();
+ printf("ok 3 - fenv\n");
+ test_feraiseexcept();
+ printf("ok 4 - fenv\n");
+ test_fegsetround();
+ printf("ok 5 - fenv\n");
+ test_fegsetenv();
+ printf("ok 6 - fenv\n");
+ test_masking();
+ printf("ok 7 - fenv\n");
+ test_feholdupdate();
+ printf("ok 8 - fenv\n");
+
+ return (0);
+}
+
+/*
+ * Initialize std_except_sets[] to the power set of std_excepts[]
+ */
+void
+init_exceptsets(void)
+{
+ int i, j, sr;
+
+ for (i = 0; i < 1 << NEXCEPTS; i++) {
+ for (sr = i, j = 0; sr != 0; sr >>= 1, j++)
+ std_except_sets[i] |= std_excepts[j] & ((~sr & 1) - 1);
+ }
+}
+
+/*
+ * This tests checks the default FP environment, so it must be first.
+ * The memcmp() test below may be too much to ask for, since there
+ * could be multiple machine-specific default environments.
+ */
+static void
+test_dfl_env(void)
+{
+#ifndef NO_STRICT_DFL_ENV
+ fenv_t env;
+
+ fegetenv(&env);
+
+#ifdef __amd64__
+ /*
+ * Compare the fields that the AMD [1] and Intel [2] specs say will be
+ * set once fnstenv returns.
+ *
+ * Not all amd64 capable processors implement the fnstenv instruction
+ * by zero'ing out the env.__x87.__other field (example: AMD Opteron
+ * 6308). The AMD64/x64 specs aren't explicit on what the
+ * env.__x87.__other field will contain after fnstenv is executed, so
+ * the values in env.__x87.__other could be filled with arbitrary
+ * data depending on how the CPU implements fnstenv.
+ *
+ * 1. http://support.amd.com/TechDocs/26569_APM_v5.pdf
+ * 2. http://www.intel.com/Assets/en_US/PDF/manual/253666.pdf
+ */
+ assert(memcmp(&env.__mxcsr, &FE_DFL_ENV->__mxcsr,
+ sizeof(env.__mxcsr)) == 0);
+ assert(memcmp(&env.__x87.__control, &FE_DFL_ENV->__x87.__control,
+ sizeof(env.__x87.__control)) == 0);
+ assert(memcmp(&env.__x87.__status, &FE_DFL_ENV->__x87.__status,
+ sizeof(env.__x87.__status)) == 0);
+ assert(memcmp(&env.__x87.__tag, &FE_DFL_ENV->__x87.__tag,
+ sizeof(env.__x87.__tag)) == 0);
+#else
+ assert(memcmp(&env, FE_DFL_ENV, sizeof(env)) == 0);
+#endif
+
+#endif
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+}
+
+/*
+ * Test fetestexcept() and feclearexcept().
+ */
+static void
+test_fetestclearexcept(void)
+{
+ int excepts, i;
+
+ for (i = 0; i < 1 << NEXCEPTS; i++)
+ assert(fetestexcept(std_except_sets[i]) == 0);
+ for (i = 0; i < 1 << NEXCEPTS; i++) {
+ excepts = std_except_sets[i];
+
+ /* FE_ALL_EXCEPT might be special-cased, as on i386. */
+ raiseexcept(excepts);
+ assert(fetestexcept(excepts) == excepts);
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0);
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+
+ raiseexcept(excepts);
+ assert(fetestexcept(excepts) == excepts);
+ if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) {
+ excepts |= FE_INEXACT;
+ assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) ==
+ excepts);
+ } else {
+ assert(fetestexcept(ALL_STD_EXCEPT) == excepts);
+ }
+ assert(feclearexcept(excepts) == 0);
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+ }
+}
+
+/*
+ * Test fegetexceptflag() and fesetexceptflag().
+ *
+ * Prerequisites: fetestexcept(), feclearexcept()
+ */
+static void
+test_fegsetexceptflag(void)
+{
+ fexcept_t flag;
+ int excepts, i;
+
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+ for (i = 0; i < 1 << NEXCEPTS; i++) {
+ excepts = std_except_sets[i];
+
+ assert(fegetexceptflag(&flag, excepts) == 0);
+ raiseexcept(ALL_STD_EXCEPT);
+ assert(fesetexceptflag(&flag, excepts) == 0);
+ assert(fetestexcept(ALL_STD_EXCEPT) ==
+ (ALL_STD_EXCEPT ^ excepts));
+
+ assert(fegetexceptflag(&flag, FE_ALL_EXCEPT) == 0);
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0);
+ assert(fesetexceptflag(&flag, excepts) == 0);
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+ assert(fesetexceptflag(&flag, ALL_STD_EXCEPT ^ excepts) == 0);
+ assert(fetestexcept(ALL_STD_EXCEPT) ==
+ (ALL_STD_EXCEPT ^ excepts));
+
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0);
+ }
+}
+
+/*
+ * Test feraiseexcept().
+ *
+ * Prerequisites: fetestexcept(), feclearexcept()
+ */
+static void
+test_feraiseexcept(void)
+{
+ int excepts, i;
+
+ for (i = 0; i < 1 << NEXCEPTS; i++) {
+ excepts = std_except_sets[i];
+
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+ assert(feraiseexcept(excepts) == 0);
+ if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) {
+ excepts |= FE_INEXACT;
+ assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) ==
+ excepts);
+ } else {
+ assert(fetestexcept(ALL_STD_EXCEPT) == excepts);
+ }
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0);
+ }
+ assert(feraiseexcept(FE_INVALID | FE_DIVBYZERO) == 0);
+ assert(fetestexcept(ALL_STD_EXCEPT) == (FE_INVALID | FE_DIVBYZERO));
+ assert(feraiseexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) == 0);
+ assert(fetestexcept(ALL_STD_EXCEPT) == ALL_STD_EXCEPT);
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0);
+}
+
+/*
+ * Test fegetround() and fesetround().
+ */
+static void
+test_fegsetround(void)
+{
+
+ assert(fegetround() == FE_TONEAREST);
+ assert(getround() == FE_TONEAREST);
+ assert(FLT_ROUNDS == 1);
+
+ assert(fesetround(FE_DOWNWARD) == 0);
+ assert(fegetround() == FE_DOWNWARD);
+ assert(getround() == FE_DOWNWARD);
+ assert(FLT_ROUNDS == 3);
+
+ assert(fesetround(FE_UPWARD) == 0);
+ assert(getround() == FE_UPWARD);
+ assert(fegetround() == FE_UPWARD);
+ assert(FLT_ROUNDS == 2);
+
+ assert(fesetround(FE_TOWARDZERO) == 0);
+ assert(getround() == FE_TOWARDZERO);
+ assert(fegetround() == FE_TOWARDZERO);
+ assert(FLT_ROUNDS == 0);
+
+ assert(fesetround(FE_TONEAREST) == 0);
+ assert(getround() == FE_TONEAREST);
+ assert(FLT_ROUNDS == 1);
+
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0);
+}
+
+/*
+ * Test fegetenv() and fesetenv().
+ *
+ * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround()
+ */
+static void
+test_fegsetenv(void)
+{
+ fenv_t env1, env2;
+ int excepts, i;
+
+ for (i = 0; i < 1 << NEXCEPTS; i++) {
+ excepts = std_except_sets[i];
+
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+ assert(fegetround() == FE_TONEAREST);
+ assert(fegetenv(&env1) == 0);
+
+ /*
+ * fe[gs]etenv() should be able to save and restore
+ * exception flags without the spurious inexact
+ * exceptions that afflict raiseexcept().
+ */
+ raiseexcept(excepts);
+ if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0 &&
+ (excepts & FE_INEXACT) == 0)
+ assert(feclearexcept(FE_INEXACT) == 0);
+
+ fesetround(FE_DOWNWARD);
+ assert(fegetenv(&env2) == 0);
+ assert(fesetenv(&env1) == 0);
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+ assert(fegetround() == FE_TONEAREST);
+
+ assert(fesetenv(&env2) == 0);
+ assert(fetestexcept(FE_ALL_EXCEPT) == excepts);
+ assert(fegetround() == FE_DOWNWARD);
+ assert(fesetenv(&env1) == 0);
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+ assert(fegetround() == FE_TONEAREST);
+ }
+}
+
+/*
+ * Test fegetexcept(), fedisableexcept(), and feenableexcept().
+ *
+ * Prerequisites: fetestexcept(), feraiseexcept()
+ */
+static void
+test_masking(void)
+{
+ struct sigaction act;
+ int except, i, pass, raise, status;
+
+ assert((fegetexcept() & ALL_STD_EXCEPT) == 0);
+ assert((feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT) == 0);
+ assert((feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT) ==
+ (FE_INVALID | FE_OVERFLOW));
+ assert((fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT) ==
+ (FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW));
+ assert((fegetexcept() & ALL_STD_EXCEPT) == (FE_INVALID | FE_UNDERFLOW));
+ assert((fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT) ==
+ (FE_INVALID | FE_UNDERFLOW));
+ assert((fegetexcept() & ALL_STD_EXCEPT) == 0);
+
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = trap_handler;
+ for (pass = 0; pass < 2; pass++) {
+ for (i = 0; i < NEXCEPTS; i++) {
+ except = std_excepts[i];
+ /* over/underflow may also raise inexact */
+ if (except == FE_INEXACT)
+ raise = FE_DIVBYZERO | FE_INVALID;
+ else
+ raise = ALL_STD_EXCEPT ^ except;
+
+ /*
+ * We need to fork a child process because
+ * there isn't a portable way to recover from
+ * a floating-point exception.
+ */
+ switch(fork()) {
+ case 0: /* child */
+ assert((fegetexcept() & ALL_STD_EXCEPT) == 0);
+ assert((feenableexcept(except)
+ & ALL_STD_EXCEPT) == 0);
+ assert(fegetexcept() == except);
+ raiseexcept(raise);
+ assert(feraiseexcept(raise) == 0);
+ assert(fetestexcept(ALL_STD_EXCEPT) == raise);
+
+ assert(sigaction(SIGFPE, &act, NULL) == 0);
+ switch (pass) {
+ case 0:
+ raiseexcept(except);
+ case 1:
+ feraiseexcept(except);
+ default:
+ assert(0);
+ }
+ assert(0);
+ default: /* parent */
+ assert(wait(&status) > 0);
+ /*
+ * Avoid assert() here so that it's possible
+ * to examine a failed child's core dump.
+ */
+ if (!WIFEXITED(status))
+ errx(1, "child aborted\n");
+ assert(WEXITSTATUS(status) == 0);
+ break;
+ case -1: /* error */
+ assert(0);
+ }
+ }
+ }
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+}
+
+/*
+ * Test feholdexcept() and feupdateenv().
+ *
+ * Prerequisites: fetestexcept(), fegetround(), fesetround(),
+ * fedisableexcept(), feenableexcept()
+ */
+static void
+test_feholdupdate(void)
+{
+ fenv_t env;
+
+ struct sigaction act;
+ int except, i, pass, status, raise;
+
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = trap_handler;
+ for (pass = 0; pass < 2; pass++) {
+ for (i = 0; i < NEXCEPTS; i++) {
+ except = std_excepts[i];
+ /* over/underflow may also raise inexact */
+ if (except == FE_INEXACT)
+ raise = FE_DIVBYZERO | FE_INVALID;
+ else
+ raise = ALL_STD_EXCEPT ^ except;
+
+ /*
+ * We need to fork a child process because
+ * there isn't a portable way to recover from
+ * a floating-point exception.
+ */
+ switch(fork()) {
+ case 0: /* child */
+ /*
+ * We don't want to cause a fatal exception in
+ * the child until the second pass, so we can
+ * check other properties of feupdateenv().
+ */
+ if (pass == 1)
+ assert((feenableexcept(except) &
+ ALL_STD_EXCEPT) == 0);
+ raiseexcept(raise);
+ assert(fesetround(FE_DOWNWARD) == 0);
+ assert(feholdexcept(&env) == 0);
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+ raiseexcept(except);
+ assert(fesetround(FE_UPWARD) == 0);
+
+ if (pass == 1)
+ assert(sigaction(SIGFPE, &act, NULL) ==
+ 0);
+ assert(feupdateenv(&env) == 0);
+ assert(fegetround() == FE_DOWNWARD);
+ assert(fetestexcept(ALL_STD_EXCEPT) ==
+ (except | raise));
+
+ assert(pass == 0);
+ _exit(0);
+ default: /* parent */
+ assert(wait(&status) > 0);
+ /*
+ * Avoid assert() here so that it's possible
+ * to examine a failed child's core dump.
+ */
+ if (!WIFEXITED(status))
+ errx(1, "child aborted\n");
+ assert(WEXITSTATUS(status) == 0);
+ break;
+ case -1: /* error */
+ assert(0);
+ }
+ }
+ }
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+}
+
+/*
+ * Raise a floating-point exception without relying on the standard
+ * library routines, which we are trying to test.
+ *
+ * XXX We can't raise an {over,under}flow without also raising an
+ * inexact exception.
+ */
+static void
+raiseexcept(int excepts)
+{
+ volatile double d;
+
+ /*
+ * With a compiler that supports the FENV_ACCESS pragma
+ * properly, simple expressions like '0.0 / 0.0' should
+ * be sufficient to generate traps. Unfortunately, we
+ * need to bring a volatile variable into the equation
+ * to prevent incorrect optimizations.
+ */
+ if (excepts & FE_INVALID) {
+ d = 0.0;
+ d = 0.0 / d;
+ }
+ if (excepts & FE_DIVBYZERO) {
+ d = 0.0;
+ d = 1.0 / d;
+ }
+ if (excepts & FE_OVERFLOW) {
+ d = DBL_MAX;
+ d *= 2.0;
+ }
+ if (excepts & FE_UNDERFLOW) {
+ d = DBL_MIN;
+ d /= DBL_MAX;
+ }
+ if (excepts & FE_INEXACT) {
+ d = DBL_MIN;
+ d += 1.0;
+ }
+
+ /*
+ * On the x86 (and some other architectures?) the FPU and
+ * integer units are decoupled. We need to execute an FWAIT
+ * or a floating-point instruction to get synchronous exceptions.
+ */
+ d = 1.0;
+ d += 1.0;
+}
+
+/*
+ * Determine the current rounding mode without relying on the fenv
+ * routines. This function may raise an inexact exception.
+ */
+static int
+getround(void)
+{
+ volatile double d;
+
+ /*
+ * This test works just as well with 0.0 - 0.0, except on ia64
+ * where 0.0 - 0.0 gives the wrong sign when rounding downwards.
+ */
+ d = 1.0;
+ d -= 1.0;
+ if (copysign(1.0, d) < 0.0)
+ return (FE_DOWNWARD);
+
+ d = 1.0;
+ if (d + (DBL_EPSILON * 3.0 / 4.0) == 1.0)
+ return (FE_TOWARDZERO);
+ if (d + (DBL_EPSILON * 1.0 / 4.0) > 1.0)
+ return (FE_UPWARD);
+
+ return (FE_TONEAREST);
+}
+
+static void
+trap_handler(int sig)
+{
+
+ assert(sig == SIGFPE);
+ _exit(0);
+}
diff --git a/lib/msun/tests/fmaxmin_test.c b/lib/msun/tests/fmaxmin_test.c
new file mode 100644
index 0000000..7ddcc87
--- /dev/null
+++ b/lib/msun/tests/fmaxmin_test.c
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 2008 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Tests for fmax{,f,l}() and fmin{,f,l}.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "test-utils.h"
+
+#pragma STDC FENV_ACCESS ON
+
+/*
+ * Test whether func(x, y) has the expected result, and make sure no
+ * exceptions are raised.
+ */
+#define TEST(func, type, x, y, expected) do { \
+ type __x = (x); /* convert before we clear exceptions */ \
+ type __y = (y); \
+ feclearexcept(ALL_STD_EXCEPT); \
+ long double __result = func((__x), (__y)); \
+ if (fetestexcept(ALL_STD_EXCEPT)) { \
+ fprintf(stderr, #func "(%.20Lg, %.20Lg) raised 0x%x\n", \
+ (x), (y), fetestexcept(FE_ALL_EXCEPT)); \
+ ok = 0; \
+ } \
+ if (!fpequal(__result, (expected))) { \
+ fprintf(stderr, #func "(%.20Lg, %.20Lg) = %.20Lg, " \
+ "expected %.20Lg\n", (x), (y), __result, (expected)); \
+ ok = 0; \
+ } \
+} while (0)
+
+int
+testall_r(long double big, long double small)
+{
+ int ok;
+
+ long double expected_max = isnan(big) ? small : big;
+ long double expected_min = isnan(small) ? big : small;
+ ok = 1;
+
+ TEST(fmaxf, float, big, small, expected_max);
+ TEST(fmaxf, float, small, big, expected_max);
+ TEST(fmax, double, big, small, expected_max);
+ TEST(fmax, double, small, big, expected_max);
+ TEST(fmaxl, long double, big, small, expected_max);
+ TEST(fmaxl, long double, small, big, expected_max);
+ TEST(fminf, float, big, small, expected_min);
+ TEST(fminf, float, small, big, expected_min);
+ TEST(fmin, double, big, small, expected_min);
+ TEST(fmin, double, small, big, expected_min);
+ TEST(fminl, long double, big, small, expected_min);
+ TEST(fminl, long double, small, big, expected_min);
+
+ return (ok);
+}
+
+/*
+ * Test all the functions: fmaxf, fmax, fmaxl, fminf, fmin, and fminl,
+ * in all rounding modes and with the arguments in different orders.
+ * The input 'big' must be >= 'small'.
+ */
+void
+testall(int testnum, long double big, long double small)
+{
+ static const int rmodes[] = {
+ FE_TONEAREST, FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO
+ };
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ fesetround(rmodes[i]);
+ if (!testall_r(big, small)) {
+ fprintf(stderr, "FAILURE in rounding mode %d\n",
+ rmodes[i]);
+ break;
+ }
+ }
+ printf("%sok %d - big = %.20Lg, small = %.20Lg\n",
+ (i == 4) ? "" : "not ", testnum, big, small);
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..12\n");
+
+ testall(1, 1.0, 0.0);
+ testall(2, 42.0, nextafterf(42.0, -INFINITY));
+ testall(3, nextafterf(42.0, INFINITY), 42.0);
+ testall(4, -5.0, -5.0);
+ testall(5, -3.0, -4.0);
+ testall(6, 1.0, NAN);
+ testall(7, INFINITY, NAN);
+ testall(8, INFINITY, 1.0);
+ testall(9, -3.0, -INFINITY);
+ testall(10, 3.0, -INFINITY);
+ testall(11, NAN, NAN);
+
+ /* This test isn't strictly required to work by C99. */
+ testall(12, 0.0, -0.0);
+
+ return (0);
+}
diff --git a/lib/msun/tests/ilogb_test.c b/lib/msun/tests/ilogb_test.c
new file mode 100644
index 0000000..a1440c4
--- /dev/null
+++ b/lib/msun/tests/ilogb_test.c
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <assert.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main(void)
+{
+ char buf[128], *end;
+ double d;
+ float f;
+ long double ld;
+ int e, i;
+
+ printf("1..3\n");
+ assert(ilogb(0) == FP_ILOGB0);
+ assert(ilogb(NAN) == FP_ILOGBNAN);
+ assert(ilogb(INFINITY) == INT_MAX);
+ for (e = DBL_MIN_EXP - DBL_MANT_DIG; e < DBL_MAX_EXP; e++) {
+ snprintf(buf, sizeof(buf), "0x1.p%d", e);
+ d = strtod(buf, &end);
+ assert(*end == '\0');
+ i = ilogb(d);
+ assert(i == e);
+ }
+ printf("ok 1 - ilogb\n");
+
+ assert(ilogbf(0) == FP_ILOGB0);
+ assert(ilogbf(NAN) == FP_ILOGBNAN);
+ assert(ilogbf(INFINITY) == INT_MAX);
+ for (e = FLT_MIN_EXP - FLT_MANT_DIG; e < FLT_MAX_EXP; e++) {
+ snprintf(buf, sizeof(buf), "0x1.p%d", e);
+ f = strtof(buf, &end);
+ assert(*end == '\0');
+ i = ilogbf(f);
+ assert(i == e);
+ }
+ printf("ok 2 - ilogbf\n");
+
+ assert(ilogbl(0) == FP_ILOGB0);
+ assert(ilogbl(NAN) == FP_ILOGBNAN);
+ assert(ilogbl(INFINITY) == INT_MAX);
+ for (e = LDBL_MIN_EXP - LDBL_MANT_DIG; e < LDBL_MAX_EXP; e++) {
+ snprintf(buf, sizeof(buf), "0x1.p%d", e);
+ ld = strtold(buf, &end);
+ assert(*end == '\0');
+ i = ilogbl(ld);
+ assert(i == e);
+ }
+ printf("ok 3 - ilogbl\n");
+
+ return (0);
+}
diff --git a/lib/msun/tests/invctrig_test.c b/lib/msun/tests/invctrig_test.c
new file mode 100644
index 0000000..34e78a1
--- /dev/null
+++ b/lib/msun/tests/invctrig_test.c
@@ -0,0 +1,367 @@
+/*-
+ * Copyright (c) 2008-2013 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Tests for casin[h](), cacos[h](), and catan[h]().
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <complex.h>
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "test-utils.h"
+
+#pragma STDC FENV_ACCESS ON
+#pragma STDC CX_LIMITED_RANGE OFF
+
+/*
+ * Test that a function returns the correct value and sets the
+ * exception flags correctly. The exceptmask specifies which
+ * exceptions we should check. We need to be lenient for several
+ * reasons, but mainly because on some architectures it's impossible
+ * to raise FE_OVERFLOW without raising FE_INEXACT.
+ *
+ * These are macros instead of functions so that assert provides more
+ * meaningful error messages.
+ *
+ * XXX The volatile here is to avoid gcc's bogus constant folding and work
+ * around the lack of support for the FENV_ACCESS pragma.
+ */
+#define test_p(func, z, result, exceptmask, excepts, checksign) do { \
+ volatile long double complex _d = z; \
+ debug(" testing %s(%Lg + %Lg I) == %Lg + %Lg I\n", #func, \
+ creall(_d), cimagl(_d), creall(result), cimagl(result)); \
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
+ assert(cfpequal_cs((func)(_d), (result), (checksign))); \
+ assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
+} while (0)
+
+/*
+ * Test within a given tolerance. The tolerance indicates relative error
+ * in ulps.
+ */
+#define test_p_tol(func, z, result, tol) do { \
+ volatile long double complex _d = z; \
+ debug(" testing %s(%Lg + %Lg I) ~= %Lg + %Lg I\n", #func, \
+ creall(_d), cimagl(_d), creall(result), cimagl(result)); \
+ assert(cfpequal_tol((func)(_d), (result), (tol), CS_BOTH)); \
+} while (0)
+
+/* These wrappers apply the identities f(conj(z)) = conj(f(z)). */
+#define test(func, z, result, exceptmask, excepts, checksign) do { \
+ test_p(func, z, result, exceptmask, excepts, checksign); \
+ test_p(func, conjl(z), conjl(result), exceptmask, excepts, checksign); \
+} while (0)
+#define test_tol(func, z, result, tol) do { \
+ test_p_tol(func, z, result, tol); \
+ test_p_tol(func, conjl(z), conjl(result), tol); \
+} while (0)
+
+/* Test the given function in all precisions. */
+#define testall(func, x, result, exceptmask, excepts, checksign) do { \
+ test(func, x, result, exceptmask, excepts, checksign); \
+ test(func##f, x, result, exceptmask, excepts, checksign); \
+} while (0)
+#define testall_odd(func, x, result, exceptmask, excepts, checksign) do { \
+ testall(func, x, result, exceptmask, excepts, checksign); \
+ testall(func, -(x), -result, exceptmask, excepts, checksign); \
+} while (0)
+#define testall_even(func, x, result, exceptmask, excepts, checksign) do { \
+ testall(func, x, result, exceptmask, excepts, checksign); \
+ testall(func, -(x), result, exceptmask, excepts, checksign); \
+} while (0)
+
+/*
+ * Test the given function in all precisions, within a given tolerance.
+ * The tolerance is specified in ulps.
+ */
+#define testall_tol(func, x, result, tol) do { \
+ test_tol(func, x, result, (tol) * DBL_ULP()); \
+ test_tol(func##f, x, result, (tol) * FLT_ULP()); \
+} while (0)
+#define testall_odd_tol(func, x, result, tol) do { \
+ testall_tol(func, x, result, tol); \
+ testall_tol(func, -(x), -result, tol); \
+} while (0)
+#define testall_even_tol(func, x, result, tol) do { \
+ testall_tol(func, x, result, tol); \
+ testall_tol(func, -(x), result, tol); \
+} while (0)
+
+static const long double
+pi = 3.14159265358979323846264338327950280L,
+c3pi = 9.42477796076937971538793014983850839L;
+
+
+/* Tests for 0 */
+void
+test_zero(void)
+{
+ long double complex zero = CMPLXL(0.0, 0.0);
+
+ testall_tol(cacosh, zero, CMPLXL(0.0, pi / 2), 1);
+ testall_tol(cacosh, -zero, CMPLXL(0.0, -pi / 2), 1);
+ testall_tol(cacos, zero, CMPLXL(pi / 2, -0.0), 1);
+ testall_tol(cacos, -zero, CMPLXL(pi / 2, 0.0), 1);
+
+ testall_odd(casinh, zero, zero, ALL_STD_EXCEPT, 0, CS_BOTH);
+ testall_odd(casin, zero, zero, ALL_STD_EXCEPT, 0, CS_BOTH);
+
+ testall_odd(catanh, zero, zero, ALL_STD_EXCEPT, 0, CS_BOTH);
+ testall_odd(catan, zero, zero, ALL_STD_EXCEPT, 0, CS_BOTH);
+}
+
+/*
+ * Tests for NaN inputs.
+ */
+void
+test_nan()
+{
+ long double complex nan_nan = CMPLXL(NAN, NAN);
+ long double complex z;
+
+ /*
+ * IN CACOSH CACOS CASINH CATANH
+ * NaN,NaN NaN,NaN NaN,NaN NaN,NaN NaN,NaN
+ * finite,NaN NaN,NaN* NaN,NaN* NaN,NaN* NaN,NaN*
+ * NaN,finite NaN,NaN* NaN,NaN* NaN,NaN* NaN,NaN*
+ * NaN,Inf Inf,NaN NaN,-Inf ?Inf,NaN ?0,pi/2
+ * +-Inf,NaN Inf,NaN NaN,?Inf +-Inf,NaN +-0,NaN
+ * +-0,NaN NaN,NaN* pi/2,NaN NaN,NaN* +-0,NaN
+ * NaN,0 NaN,NaN* NaN,NaN* NaN,0 NaN,NaN*
+ *
+ * * = raise invalid
+ */
+ z = nan_nan;
+ testall(cacosh, z, nan_nan, ALL_STD_EXCEPT, 0, 0);
+ testall(cacos, z, nan_nan, ALL_STD_EXCEPT, 0, 0);
+ testall(casinh, z, nan_nan, ALL_STD_EXCEPT, 0, 0);
+ testall(casin, z, nan_nan, ALL_STD_EXCEPT, 0, 0);
+ testall(catanh, z, nan_nan, ALL_STD_EXCEPT, 0, 0);
+ testall(catan, z, nan_nan, ALL_STD_EXCEPT, 0, 0);
+
+ z = CMPLXL(0.5, NAN);
+ testall(cacosh, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(cacos, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(casinh, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(casin, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(catanh, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(catan, z, nan_nan, OPT_INVALID, 0, 0);
+
+ z = CMPLXL(NAN, 0.5);
+ testall(cacosh, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(cacos, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(casinh, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(casin, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(catanh, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(catan, z, nan_nan, OPT_INVALID, 0, 0);
+
+ z = CMPLXL(NAN, INFINITY);
+ testall(cacosh, z, CMPLXL(INFINITY, NAN), ALL_STD_EXCEPT, 0, CS_REAL);
+ testall(cacosh, -z, CMPLXL(INFINITY, NAN), ALL_STD_EXCEPT, 0, CS_REAL);
+ testall(cacos, z, CMPLXL(NAN, -INFINITY), ALL_STD_EXCEPT, 0, CS_IMAG);
+ testall(casinh, z, CMPLXL(INFINITY, NAN), ALL_STD_EXCEPT, 0, 0);
+ testall(casin, z, CMPLXL(NAN, INFINITY), ALL_STD_EXCEPT, 0, CS_IMAG);
+ testall_tol(catanh, z, CMPLXL(0.0, pi / 2), 1);
+ testall(catan, z, CMPLXL(NAN, 0.0), ALL_STD_EXCEPT, 0, CS_IMAG);
+
+ z = CMPLXL(INFINITY, NAN);
+ testall_even(cacosh, z, CMPLXL(INFINITY, NAN), ALL_STD_EXCEPT, 0,
+ CS_REAL);
+ testall_even(cacos, z, CMPLXL(NAN, INFINITY), ALL_STD_EXCEPT, 0, 0);
+ testall_odd(casinh, z, CMPLXL(INFINITY, NAN), ALL_STD_EXCEPT, 0,
+ CS_REAL);
+ testall_odd(casin, z, CMPLXL(NAN, INFINITY), ALL_STD_EXCEPT, 0, 0);
+ testall_odd(catanh, z, CMPLXL(0.0, NAN), ALL_STD_EXCEPT, 0, CS_REAL);
+ testall_odd_tol(catan, z, CMPLXL(pi / 2, 0.0), 1);
+
+ z = CMPLXL(0.0, NAN);
+ /* XXX We allow a spurious inexact exception here. */
+ testall_even(cacosh, z, nan_nan, OPT_INVALID & ~FE_INEXACT, 0, 0);
+ testall_even_tol(cacos, z, CMPLXL(pi / 2, NAN), 1);
+ testall_odd(casinh, z, nan_nan, OPT_INVALID, 0, 0);
+ testall_odd(casin, z, CMPLXL(0.0, NAN), ALL_STD_EXCEPT, 0, CS_REAL);
+ testall_odd(catanh, z, CMPLXL(0.0, NAN), OPT_INVALID, 0, CS_REAL);
+ testall_odd(catan, z, nan_nan, OPT_INVALID, 0, 0);
+
+ z = CMPLXL(NAN, 0.0);
+ testall(cacosh, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(cacos, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(casinh, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, 0, CS_IMAG);
+ testall(casin, z, nan_nan, OPT_INVALID, 0, 0);
+ testall(catanh, z, nan_nan, OPT_INVALID, 0, CS_IMAG);
+ testall(catan, z, CMPLXL(NAN, 0.0), ALL_STD_EXCEPT, 0, 0);
+}
+
+void
+test_inf(void)
+{
+ long double complex z;
+
+ /*
+ * IN CACOSH CACOS CASINH CATANH
+ * Inf,Inf Inf,pi/4 pi/4,-Inf Inf,pi/4 0,pi/2
+ * -Inf,Inf Inf,3pi/4 3pi/4,-Inf --- ---
+ * Inf,finite Inf,0 0,-Inf Inf,0 0,pi/2
+ * -Inf,finite Inf,pi pi,-Inf --- ---
+ * finite,Inf Inf,pi/2 pi/2,-Inf Inf,pi/2 0,pi/2
+ */
+ z = CMPLXL(INFINITY, INFINITY);
+ testall_tol(cacosh, z, CMPLXL(INFINITY, pi / 4), 1);
+ testall_tol(cacosh, -z, CMPLXL(INFINITY, -c3pi / 4), 1);
+ testall_tol(cacos, z, CMPLXL(pi / 4, -INFINITY), 1);
+ testall_tol(cacos, -z, CMPLXL(c3pi / 4, INFINITY), 1);
+ testall_odd_tol(casinh, z, CMPLXL(INFINITY, pi / 4), 1);
+ testall_odd_tol(casin, z, CMPLXL(pi / 4, INFINITY), 1);
+ testall_odd_tol(catanh, z, CMPLXL(0, pi / 2), 1);
+ testall_odd_tol(catan, z, CMPLXL(pi / 2, 0), 1);
+
+ z = CMPLXL(INFINITY, 0.5);
+ /* XXX We allow a spurious inexact exception here. */
+ testall(cacosh, z, CMPLXL(INFINITY, 0), OPT_INEXACT, 0, CS_BOTH);
+ testall_tol(cacosh, -z, CMPLXL(INFINITY, -pi), 1);
+ testall(cacos, z, CMPLXL(0, -INFINITY), OPT_INEXACT, 0, CS_BOTH);
+ testall_tol(cacos, -z, CMPLXL(pi, INFINITY), 1);
+ testall_odd(casinh, z, CMPLXL(INFINITY, 0), OPT_INEXACT, 0, CS_BOTH);
+ testall_odd_tol(casin, z, CMPLXL(pi / 2, INFINITY), 1);
+ testall_odd_tol(catanh, z, CMPLXL(0, pi / 2), 1);
+ testall_odd_tol(catan, z, CMPLXL(pi / 2, 0), 1);
+
+ z = CMPLXL(0.5, INFINITY);
+ testall_tol(cacosh, z, CMPLXL(INFINITY, pi / 2), 1);
+ testall_tol(cacosh, -z, CMPLXL(INFINITY, -pi / 2), 1);
+ testall_tol(cacos, z, CMPLXL(pi / 2, -INFINITY), 1);
+ testall_tol(cacos, -z, CMPLXL(pi / 2, INFINITY), 1);
+ testall_odd_tol(casinh, z, CMPLXL(INFINITY, pi / 2), 1);
+ /* XXX We allow a spurious inexact exception here. */
+ testall_odd(casin, z, CMPLXL(0.0, INFINITY), OPT_INEXACT, 0, CS_BOTH);
+ testall_odd_tol(catanh, z, CMPLXL(0, pi / 2), 1);
+ testall_odd_tol(catan, z, CMPLXL(pi / 2, 0), 1);
+}
+
+/* Tests along the real and imaginary axes. */
+void
+test_axes(void)
+{
+ static const long double nums[] = {
+ -2, -1, -0.5, 0.5, 1, 2
+ };
+ long double complex z;
+ int i;
+
+ for (i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
+ /* Real axis */
+ z = CMPLXL(nums[i], 0.0);
+ if (fabsl(nums[i]) <= 1) {
+ testall_tol(cacosh, z, CMPLXL(0.0, acos(nums[i])), 1);
+ testall_tol(cacos, z, CMPLXL(acosl(nums[i]), -0.0), 1);
+ testall_tol(casin, z, CMPLXL(asinl(nums[i]), 0.0), 1);
+ testall_tol(catanh, z, CMPLXL(atanh(nums[i]), 0.0), 1);
+ } else {
+ testall_tol(cacosh, z,
+ CMPLXL(acosh(fabsl(nums[i])),
+ (nums[i] < 0) ? pi : 0), 1);
+ testall_tol(cacos, z,
+ CMPLXL((nums[i] < 0) ? pi : 0,
+ -acosh(fabsl(nums[i]))), 1);
+ testall_tol(casin, z,
+ CMPLXL(copysign(pi / 2, nums[i]),
+ acosh(fabsl(nums[i]))), 1);
+ testall_tol(catanh, z,
+ CMPLXL(atanh(1 / nums[i]), pi / 2), 1);
+ }
+ testall_tol(casinh, z, CMPLXL(asinh(nums[i]), 0.0), 1);
+ testall_tol(catan, z, CMPLXL(atan(nums[i]), 0), 1);
+
+ /* TODO: Test the imaginary axis. */
+ }
+}
+
+void
+test_small(void)
+{
+ /*
+ * z = 0.75 + i 0.25
+ * acos(z) = Pi/4 - i ln(2)/2
+ * asin(z) = Pi/4 + i ln(2)/2
+ * atan(z) = atan(4)/2 + i ln(17/9)/4
+ */
+ complex long double z;
+ complex long double acos_z;
+ complex long double asin_z;
+ complex long double atan_z;
+
+ z = CMPLXL(0.75L, 0.25L);
+ acos_z = CMPLXL(pi / 4, -0.34657359027997265470861606072908828L);
+ asin_z = CMPLXL(pi / 4, 0.34657359027997265470861606072908828L);
+ atan_z = CMPLXL(0.66290883183401623252961960521423782L,
+ 0.15899719167999917436476103600701878L);
+
+ testall_tol(cacos, z, acos_z, 2);
+ testall_odd_tol(casin, z, asin_z, 2);
+ testall_odd_tol(catan, z, atan_z, 2);
+}
+
+/* Test inputs that might cause overflow in a sloppy implementation. */
+void
+test_large(void)
+{
+
+ /* TODO: Write these tests */
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..6\n");
+
+ test_zero();
+ printf("ok 1 - invctrig zero\n");
+
+ test_nan();
+ printf("ok 2 - invctrig nan\n");
+
+ test_inf();
+ printf("ok 3 - invctrig inf\n");
+
+ test_axes();
+ printf("ok 4 - invctrig axes\n");
+
+ test_small();
+ printf("ok 5 - invctrig small\n");
+
+ test_large();
+ printf("ok 6 - invctrig large\n");
+
+ return (0);
+}
diff --git a/lib/msun/tests/logarithm_test.c b/lib/msun/tests/logarithm_test.c
new file mode 100644
index 0000000..18b9ebe
--- /dev/null
+++ b/lib/msun/tests/logarithm_test.c
@@ -0,0 +1,286 @@
+/*-
+ * Copyright (c) 2008-2010 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Tests for corner cases in log*().
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef __i386__
+#include <ieeefp.h>
+#endif
+
+#include "test-utils.h"
+
+#pragma STDC FENV_ACCESS ON
+
+/*
+ * Test that a function returns the correct value and sets the
+ * exception flags correctly. The exceptmask specifies which
+ * exceptions we should check. We need to be lenient for several
+ * reasoons, but mainly because on some architectures it's impossible
+ * to raise FE_OVERFLOW without raising FE_INEXACT.
+ *
+ * These are macros instead of functions so that assert provides more
+ * meaningful error messages.
+ *
+ * XXX The volatile here is to avoid gcc's bogus constant folding and work
+ * around the lack of support for the FENV_ACCESS pragma.
+ */
+#define test(func, x, result, exceptmask, excepts) do { \
+ volatile long double _d = x; \
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
+ assert(fpequal((func)(_d), (result))); \
+ assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
+} while (0)
+
+#define test(func, x, result, exceptmask, excepts) do { \
+ volatile long double _d = x; \
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
+ assert(fpequal((func)(_d), (result))); \
+ assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
+} while (0)
+
+#define test_tol(func, z, result, tol) do { \
+ volatile long double _d = z; \
+ debug(" testing %6s(%15La) ~= % .36Le\n", #func, _d, result); \
+ assert(fpequal_tol((func)(_d), (result), (tol), CS_BOTH)); \
+} while (0)
+
+/* Test all the functions that compute log(x). */
+#define testall0(x, result, exceptmask, excepts) do { \
+ test(log, x, result, exceptmask, excepts); \
+ test(logf, x, result, exceptmask, excepts); \
+ test(logl, x, result, exceptmask, excepts); \
+ test(log2, x, result, exceptmask, excepts); \
+ test(log2f, x, result, exceptmask, excepts); \
+ test(log2l, x, result, exceptmask, excepts); \
+ test(log10, x, result, exceptmask, excepts); \
+ test(log10f, x, result, exceptmask, excepts); \
+ test(log10l, x, result, exceptmask, excepts); \
+} while (0)
+
+/* Test all the functions that compute log(1+x). */
+#define testall1(x, result, exceptmask, excepts) do { \
+ test(log1p, x, result, exceptmask, excepts); \
+ test(log1pf, x, result, exceptmask, excepts); \
+ test(log1pl, x, result, exceptmask, excepts); \
+} while (0)
+
+void
+run_generic_tests(void)
+{
+
+ /* log(1) == 0, no exceptions raised */
+ testall0(1.0, 0.0, ALL_STD_EXCEPT, 0);
+ testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
+ testall1(-0.0, -0.0, ALL_STD_EXCEPT, 0);
+
+ /* log(NaN) == NaN, no exceptions raised */
+ testall0(NAN, NAN, ALL_STD_EXCEPT, 0);
+ testall1(NAN, NAN, ALL_STD_EXCEPT, 0);
+
+ /* log(Inf) == Inf, no exceptions raised */
+ testall0(INFINITY, INFINITY, ALL_STD_EXCEPT, 0);
+ testall1(INFINITY, INFINITY, ALL_STD_EXCEPT, 0);
+
+ /* log(x) == NaN for x < 0, invalid exception raised */
+ testall0(-INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
+ testall1(-INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
+ testall0(-1.0, NAN, ALL_STD_EXCEPT, FE_INVALID);
+ testall1(-1.5, NAN, ALL_STD_EXCEPT, FE_INVALID);
+
+ /* log(0) == -Inf, divide-by-zero exception */
+ testall0(0.0, -INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_DIVBYZERO);
+ testall0(-0.0, -INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_DIVBYZERO);
+ testall1(-1.0, -INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_DIVBYZERO);
+}
+
+void
+run_log2_tests(void)
+{
+ int i;
+
+ /*
+ * We should insist that log2() return exactly the correct
+ * result and not raise an inexact exception for powers of 2.
+ */
+ feclearexcept(FE_ALL_EXCEPT);
+ for (i = FLT_MIN_EXP - FLT_MANT_DIG; i < FLT_MAX_EXP; i++) {
+ assert(log2f(ldexpf(1.0, i)) == i);
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+ }
+ for (i = DBL_MIN_EXP - DBL_MANT_DIG; i < DBL_MAX_EXP; i++) {
+ assert(log2(ldexp(1.0, i)) == i);
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+ }
+ for (i = LDBL_MIN_EXP - LDBL_MANT_DIG; i < LDBL_MAX_EXP; i++) {
+ assert(log2l(ldexpl(1.0, i)) == i);
+#if 0
+ /* XXX This test does not pass yet. */
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+#endif
+ }
+}
+
+void
+run_roundingmode_tests(void)
+{
+
+ /*
+ * Corner cases in other rounding modes.
+ */
+ fesetround(FE_DOWNWARD);
+ /* These are still positive per IEEE 754R */
+#if 0
+ testall0(1.0, 0.0, ALL_STD_EXCEPT, 0);
+#else
+ /* logl, log2l, and log10l don't pass yet. */
+ test(log, 1.0, 0.0, ALL_STD_EXCEPT, 0);
+ test(logf, 1.0, 0.0, ALL_STD_EXCEPT, 0);
+ test(log2, 1.0, 0.0, ALL_STD_EXCEPT, 0);
+ test(log2f, 1.0, 0.0, ALL_STD_EXCEPT, 0);
+ test(log10, 1.0, 0.0, ALL_STD_EXCEPT, 0);
+ test(log10f, 1.0, 0.0, ALL_STD_EXCEPT, 0);
+#endif
+ testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
+ fesetround(FE_TOWARDZERO);
+ testall0(1.0, 0.0, ALL_STD_EXCEPT, 0);
+ testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
+
+ fesetround(FE_UPWARD);
+ testall0(1.0, 0.0, ALL_STD_EXCEPT, 0);
+ testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
+ /* log1p(-0.0) == -0.0 even when rounding upwards */
+ testall1(-0.0, -0.0, ALL_STD_EXCEPT, 0);
+
+ fesetround(FE_TONEAREST);
+}
+
+void
+run_accuracy_tests(void)
+{
+ static const struct {
+ float x;
+ long double log2x;
+ long double logex;
+ long double log10x;
+ } tests[] = {
+ { 0x1p-120 + 0x1p-140,
+ -1.19999998624139449158861798943319717e2L,
+ -8.31776607135195754708796206665656732e1L,
+ -3.61235990655024477716980559136055915e1L,
+ },
+ { 1.0 - 0x1p-20,
+ -1.37586186296463416424364914705656460e-6L,
+ -9.53674771153890007250243736279163253e-7L,
+ -4.14175690642480911859354110516159131e-7L, },
+ { 1.0 + 0x1p-20,
+ 1.37586055084113820105668028340371476e-6L,
+ 9.53673861659188233908415514963336144e-7L,
+ 4.14175295653950611453333571759200697e-7L },
+ { 19.75,
+ 4.30378074817710292442728634194115348e0L,
+ 2.98315349134713087533848129856505779e0L,
+ 1.29556709996247903756734359702926363e0L },
+ { 19.75 * 0x1p100,
+ 1.043037807481771029244272863419411534e2L,
+ 7.229787154734166181706169344438271459e1L,
+ 3.139856666636059855894123306947856631e1L },
+ };
+ int i;
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ test_tol(log2, tests[i].x, tests[i].log2x, DBL_ULP());
+ test_tol(log2f, tests[i].x, tests[i].log2x, FLT_ULP());
+ test_tol(log2l, tests[i].x, tests[i].log2x, LDBL_ULP());
+ test_tol(log, tests[i].x, tests[i].logex, DBL_ULP());
+ test_tol(logf, tests[i].x, tests[i].logex, FLT_ULP());
+ test_tol(logl, tests[i].x, tests[i].logex, LDBL_ULP());
+ test_tol(log10, tests[i].x, tests[i].log10x, DBL_ULP());
+ test_tol(log10f, tests[i].x, tests[i].log10x, FLT_ULP());
+ test_tol(log10l, tests[i].x, tests[i].log10x, LDBL_ULP());
+ if (tests[i].x >= 0.5) {
+ test_tol(log1p, tests[i].x - 1, tests[i].logex,
+ DBL_ULP());
+ test_tol(log1pf, tests[i].x - 1, tests[i].logex,
+ FLT_ULP());
+ test_tol(log1pl, tests[i].x - 1, tests[i].logex,
+ LDBL_ULP());
+ }
+ }
+}
+
+void
+run_log1p_accuracy_tests(void)
+{
+
+ test_tol(log1pf, 0x0.333333p0F,
+ 1.82321546859847114303367992804596800640e-1L, FLT_ULP());
+ test_tol(log1p, 0x0.3333333333333p0,
+ 1.82321556793954589204283870982629267635e-1L, DBL_ULP());
+ test_tol(log1pl, 0x0.33333333333333332p0L,
+ 1.82321556793954626202683007050468762914e-1L, LDBL_ULP());
+
+ test_tol(log1pf, -0x0.333333p0F,
+ -2.23143536413048672940940199918017467652e-1L, FLT_ULP());
+ test_tol(log1p, -0x0.3333333333333p0,
+ -2.23143551314209700255143859052009022937e-1L, DBL_ULP());
+ test_tol(log1pl, -0x0.33333333333333332p0L,
+ -2.23143551314209755752742563153765697950e-1L, LDBL_ULP());
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..5\n");
+
+ run_generic_tests();
+ printf("ok 1 - logarithm\n");
+
+ run_log2_tests();
+ printf("ok 2 - logarithm\n");
+
+ run_roundingmode_tests();
+ printf("ok 3 - logarithm\n");
+
+ run_accuracy_tests();
+ printf("ok 4 - logarithm\n");
+
+ run_log1p_accuracy_tests();
+ printf("ok 5 - logarithm\n");
+
+ return (0);
+}
diff --git a/lib/msun/tests/lrint_test.c b/lib/msun/tests/lrint_test.c
new file mode 100644
index 0000000..ba099aa
--- /dev/null
+++ b/lib/msun/tests/lrint_test.c
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 2005-2008 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Test for lrint(), lrintf(), llrint(), and llrintf().
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <fenv.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef __i386__
+#include <ieeefp.h>
+#endif
+
+/*
+ * XXX The volatile here is to avoid gcc's bogus constant folding and work
+ * around the lack of support for the FENV_ACCESS pragma.
+ */
+#define test(func, x, result, excepts) do { \
+ volatile double _d = x; \
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
+ assert((func)(_d) == (result) || fetestexcept(FE_INVALID)); \
+ assert(fetestexcept(FE_ALL_EXCEPT) == (excepts)); \
+} while (0)
+
+#define testall(x, result, excepts) do { \
+ test(lrint, x, result, excepts); \
+ test(lrintf, x, result, excepts); \
+ test(lrintl, x, result, excepts); \
+ test(llrint, x, result, excepts); \
+ test(llrintf, x, result, excepts); \
+ test(llrintl, x, result, excepts); \
+} while (0)
+
+#define IGNORE 0
+
+#pragma STDC FENV_ACCESS ON
+
+void
+run_tests(void)
+{
+
+ assert(fesetround(FE_DOWNWARD) == 0);
+ testall(0.75, 0, FE_INEXACT);
+ testall(-0.5, -1, FE_INEXACT);
+
+ assert(fesetround(FE_TONEAREST) == 0);
+ testall(0.0, 0, 0);
+ testall(0.25, 0, FE_INEXACT);
+ testall(0.5, 0, FE_INEXACT);
+ testall(-2.5, -2, FE_INEXACT);
+ testall(1.0, 1, 0);
+ testall(0x12345000p0, 0x12345000, 0);
+ testall(0x1234.fp0, 0x1235, FE_INEXACT);
+ testall(INFINITY, IGNORE, FE_INVALID);
+ testall(NAN, IGNORE, FE_INVALID);
+
+#if (LONG_MAX == 0x7fffffffl)
+ assert(fesetround(FE_UPWARD) == 0);
+ test(lrint, 0x7fffffff.8p0, IGNORE, FE_INVALID);
+ test(lrint, -0x80000000.4p0, -0x80000000l, FE_INEXACT);
+
+ assert(fesetround(FE_DOWNWARD) == 0);
+ test(lrint, -0x80000000.8p0, IGNORE, FE_INVALID);
+ test(lrint, 0x80000000.0p0, IGNORE, FE_INVALID);
+ test(lrint, 0x7fffffff.4p0, 0x7fffffffl, FE_INEXACT);
+ test(lrintf, 0x80000000.0p0f, IGNORE, FE_INVALID);
+ test(lrintf, 0x7fffff80.0p0f, 0x7fffff80l, 0);
+
+ assert(fesetround(FE_TOWARDZERO) == 0);
+ test(lrint, 0x7fffffff.8p0, 0x7fffffffl, FE_INEXACT);
+ test(lrint, -0x80000000.8p0, -0x80000000l, FE_INEXACT);
+ test(lrint, 0x80000000.0p0, IGNORE, FE_INVALID);
+ test(lrintf, 0x80000000.0p0f, IGNORE, FE_INVALID);
+ test(lrintf, 0x7fffff80.0p0f, 0x7fffff80l, 0);
+#elif (LONG_MAX == 0x7fffffffffffffffll)
+ assert(fesetround(FE_TONEAREST) == 0);
+ test(lrint, 0x8000000000000000.0p0, IGNORE, FE_INVALID);
+ test(lrintf, 0x8000000000000000.0p0f, IGNORE, FE_INVALID);
+ test(lrint, 0x7ffffffffffffc00.0p0, 0x7ffffffffffffc00l, 0);
+ test(lrintf, 0x7fffff8000000000.0p0f, 0x7fffff8000000000l, 0);
+ test(lrint, -0x8000000000000800.0p0, IGNORE, FE_INVALID);
+ test(lrintf, -0x8000010000000000.0p0f, IGNORE, FE_INVALID);
+ test(lrint, -0x8000000000000000.0p0, -0x8000000000000000l, 0);
+ test(lrintf, -0x8000000000000000.0p0f, -0x8000000000000000l, 0);
+#else
+#error "Unsupported long size"
+#endif
+
+#if (LLONG_MAX == 0x7fffffffffffffffLL)
+ assert(fesetround(FE_TONEAREST) == 0);
+ test(llrint, 0x8000000000000000.0p0, IGNORE, FE_INVALID);
+ test(llrintf, 0x8000000000000000.0p0f, IGNORE, FE_INVALID);
+ test(llrint, 0x7ffffffffffffc00.0p0, 0x7ffffffffffffc00ll, 0);
+ test(llrintf, 0x7fffff8000000000.0p0f, 0x7fffff8000000000ll, 0);
+ test(llrint, -0x8000000000000800.0p0, IGNORE, FE_INVALID);
+ test(llrintf, -0x8000010000000000.0p0f, IGNORE, FE_INVALID);
+ test(llrint, -0x8000000000000000.0p0, -0x8000000000000000ll, 0);
+ test(llrintf, -0x8000000000000000.0p0f, -0x8000000000000000ll, 0);
+#else
+#error "Unsupported long long size"
+#endif
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..1\n");
+
+ run_tests();
+#ifdef __i386__
+ fpsetprec(FP_PE);
+ run_tests();
+#endif
+
+ printf("ok 1 - lrint\n");
+
+ return (0);
+}
diff --git a/lib/msun/tests/nan_test.c b/lib/msun/tests/nan_test.c
new file mode 100644
index 0000000..c12926b
--- /dev/null
+++ b/lib/msun/tests/nan_test.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (C) 2007 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Test for nan(), nanf(), and nanl(). We also test that strtod("nan(...)")
+ * and sscanf("nan(...)", ...) work identically.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <fenv.h>
+#include <float.h>
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void
+testnan(const char *nan_format)
+{
+ char nan_str[128];
+ char *end;
+ long double ald[4];
+ double ad[4];
+ float af[4];
+ int i;
+
+ snprintf(nan_str, sizeof(nan_str), "nan(%s)", nan_format);
+ for (i = 0; i < 4; i++) {
+ /*
+ * x86 has an 80-bit long double stored in 96 bits,
+ * so we need to initialize the memory for the memcmp()
+ * checks below to work.
+ */
+ bzero(&af[i], sizeof(float));
+ bzero(&ad[i], sizeof(double));
+ bzero(&ald[i], sizeof(long double));
+
+ }
+
+ af[0] = nanf(nan_format);
+ assert(isnan(af[0]));
+ af[1] = strtof(nan_str, &end);
+ assert(end == nan_str + strlen(nan_str));
+ assert(sscanf(nan_str, "%e", &af[2]) == 1);
+ assert(memcmp(&af[0], &af[1], sizeof(float)) == 0);
+ assert(memcmp(&af[1], &af[2], sizeof(float)) == 0);
+ if (*nan_format == '\0') {
+ /* nanf("") == strtof("nan") */
+ af[3] = strtof("nan", NULL);
+ assert(memcmp(&af[2], &af[3], sizeof(float)) == 0);
+ }
+
+ ad[0] = nan(nan_format);
+ assert(isnan(ad[0]));
+ ad[1] = strtod(nan_str, &end);
+ assert(end == nan_str + strlen(nan_str));
+ assert(sscanf(nan_str, "%le", &ad[2]) == 1);
+ assert(memcmp(&ad[0], &ad[1], sizeof(double)) == 0);
+ assert(memcmp(&ad[1], &ad[2], sizeof(double)) == 0);
+ if (*nan_format == '\0') {
+ /* nan("") == strtod("nan") */
+ ad[3] = strtod("nan", NULL);
+ assert(memcmp(&ad[2], &ad[3], sizeof(double)) == 0);
+ }
+
+ ald[0] = nanl(nan_format);
+ assert(isnan(ald[0]));
+ ald[1] = strtold(nan_str, &end);
+ assert(end == nan_str + strlen(nan_str));
+ assert(sscanf(nan_str, "%Le", &ald[2]) == 1);
+ assert(memcmp(&ald[0], &ald[1], sizeof(long double)) == 0);
+ assert(memcmp(&ald[1], &ald[2], sizeof(long double)) == 0);
+ if (*nan_format == '\0') {
+ /* nanl("") == strtold("nan") */
+ ald[3] = strtold("nan", NULL);
+ assert(memcmp(&ald[2], &ald[3], sizeof(long double)) == 0);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..1\n");
+
+ /* Die if a signalling NaN is returned */
+ feenableexcept(FE_INVALID);
+
+ testnan("0x1234");
+ testnan("");
+
+ printf("ok 1 - nan\n");
+
+ return (0);
+}
diff --git a/lib/msun/tests/nearbyint_test.c b/lib/msun/tests/nearbyint_test.c
new file mode 100644
index 0000000..602ea2a
--- /dev/null
+++ b/lib/msun/tests/nearbyint_test.c
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 2010 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Tests for nearbyint{,f,l}()
+ *
+ * TODO:
+ * - adapt tests for rint(3)
+ * - tests for harder values (more mantissa bits than float)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <fenv.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "test-utils.h"
+
+static int testnum;
+
+static const int rmodes[] = {
+ FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO,
+};
+
+/* Make sure we're testing the library, not some broken compiler built-ins. */
+double (*libnearbyint)(double) = nearbyint;
+float (*libnearbyintf)(float) = nearbyintf;
+long double (*libnearbyintl)(long double) = nearbyintl;
+#define nearbyintf libnearbyintf
+#define nearbyint libnearbyint
+#define nearbyintl libnearbyintl
+
+static const struct {
+ float in;
+ float out[3]; /* one answer per rounding mode except towardzero */
+} tests[] = {
+/* input output (expected) */
+ { 0.0, { 0.0, 0.0, 0.0 }},
+ { 0.5, { 0.0, 0.0, 1.0 }},
+ { M_PI, { 3.0, 3.0, 4.0 }},
+ { 65536.5, { 65536, 65536, 65537 }},
+ { INFINITY, { INFINITY, INFINITY, INFINITY }},
+ { NAN, { NAN, NAN, NAN }},
+};
+
+static const int ntests = sizeof(tests) / sizeof(tests[0]);
+
+/* Get the appropriate result for the current rounding mode. */
+static float
+get_output(int testindex, int rmodeindex, int negative)
+{
+ double out;
+
+ if (negative) { /* swap downwards and upwards if input is negative */
+ if (rmodeindex == 1)
+ rmodeindex = 2;
+ else if (rmodeindex == 2)
+ rmodeindex = 1;
+ }
+ if (rmodeindex == 3) /* FE_TOWARDZERO uses the value for downwards */
+ rmodeindex = 1;
+ out = tests[testindex].out[rmodeindex];
+ return (negative ? -out : out);
+}
+
+static void
+test_nearby(int testindex)
+{
+ float in, out;
+ int i;
+
+ for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) {
+ fesetround(rmodes[i]);
+ feclearexcept(ALL_STD_EXCEPT);
+
+ in = tests[testindex].in;
+ out = get_output(testindex, i, 0);
+ assert(fpequal(out, libnearbyintf(in)));
+ assert(fpequal(out, nearbyint(in)));
+ assert(fpequal(out, nearbyintl(in)));
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+
+ in = -tests[testindex].in;
+ out = get_output(testindex, i, 1);
+ assert(fpequal(out, nearbyintf(in)));
+ assert(fpequal(out, nearbyint(in)));
+ assert(fpequal(out, nearbyintl(in)));
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+ }
+
+ printf("ok %d\t\t# nearbyint(+%g)\n", testnum++, in);
+}
+
+static void
+test_modf(int testindex)
+{
+ float in, out;
+ float ipartf, ipart_expected;
+ double ipart;
+ long double ipartl;
+ int i;
+
+ for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) {
+ fesetround(rmodes[i]);
+ feclearexcept(ALL_STD_EXCEPT);
+
+ in = tests[testindex].in;
+ ipart_expected = tests[testindex].out[1];
+ out = copysignf(
+ isinf(ipart_expected) ? 0.0 : in - ipart_expected, in);
+ ipartl = ipart = ipartf = 42.0;
+
+ assert(fpequal(out, modff(in, &ipartf)));
+ assert(fpequal(ipart_expected, ipartf));
+ assert(fpequal(out, modf(in, &ipart)));
+ assert(fpequal(ipart_expected, ipart));
+ assert(fpequal(out, modfl(in, &ipartl)));
+ assert(fpequal(ipart_expected, ipartl));
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+
+ in = -in;
+ ipart_expected = -ipart_expected;
+ out = -out;
+ ipartl = ipart = ipartf = 42.0;
+ assert(fpequal(out, modff(in, &ipartf)));
+ assert(fpequal(ipart_expected, ipartf));
+ assert(fpequal(out, modf(in, &ipart)));
+ assert(fpequal(ipart_expected, ipart));
+ assert(fpequal(out, modfl(in, &ipartl)));
+ assert(fpequal(ipart_expected, ipartl));
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+ }
+
+ printf("ok %d\t\t# modf(+%g)\n", testnum++, in);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+
+ printf("1..%d\n", ntests * 2);
+ testnum = 1;
+ for (i = 0; i < ntests; i++) {
+ test_nearby(i);
+ test_modf(i);
+ }
+
+ return (0);
+}
diff --git a/lib/msun/tests/next_test.c b/lib/msun/tests/next_test.c
new file mode 100644
index 0000000..d16fa77
--- /dev/null
+++ b/lib/msun/tests/next_test.c
@@ -0,0 +1,265 @@
+/*-
+ * Copyright (c) 2005 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Test the correctness of nextafter{,f,l} and nexttoward{,f,l}.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __i386__
+#include <ieeefp.h>
+#endif
+
+#include "test-utils.h"
+
+#define test(exp, ans, ex) do { \
+ double __ans = (ans); \
+ feclearexcept(ALL_STD_EXCEPT); \
+ _testl(#exp, __LINE__, (exp), __ans, (ex)); \
+} while (0)
+#define testf(exp, ans, ex) do { \
+ float __ans = (ans); \
+ feclearexcept(ALL_STD_EXCEPT); \
+ _testl(#exp, __LINE__, (exp), __ans, (ex)); \
+} while (0)
+#define testl(exp, ans, ex) do { \
+ long double __ans = (ans); \
+ feclearexcept(ALL_STD_EXCEPT); \
+ _testl(#exp, __LINE__, (exp), __ans, (ex)); \
+} while (0)
+#define testboth(arg1, arg2, ans, ex, prec) do { \
+ test##prec(nextafter##prec((arg1), (arg2)), (ans), (ex)); \
+ test##prec(nexttoward##prec((arg1), (arg2)), (ans), (ex)); \
+} while (0)
+#define testall(arg1, arg2, ans, ex) do { \
+ testboth((arg1), (arg2), (ans), (ex), ); \
+ testboth((arg1), (arg2), (ans), (ex), f); \
+ testboth((arg1), (arg2), (ans), (ex), l); \
+} while (0)
+
+static void _testl(const char *, int, long double, long double, int);
+static double idd(double);
+static float idf(float);
+
+int
+main(int argc, char *argv[])
+{
+ static const int ex_under = FE_UNDERFLOW | FE_INEXACT; /* shorthand */
+ static const int ex_over = FE_OVERFLOW | FE_INEXACT;
+ long double ldbl_small, ldbl_eps, ldbl_max;
+
+ printf("1..5\n");
+
+#ifdef __i386__
+ fpsetprec(FP_PE);
+#endif
+ /*
+ * We can't use a compile-time constant here because gcc on
+ * FreeBSD/i386 assumes long doubles are truncated to the
+ * double format.
+ */
+ ldbl_small = ldexpl(1.0, LDBL_MIN_EXP - LDBL_MANT_DIG);
+ ldbl_eps = LDBL_EPSILON;
+ ldbl_max = ldexpl(1.0 - ldbl_eps / 2, LDBL_MAX_EXP);
+
+ /*
+ * Special cases involving zeroes.
+ */
+#define ztest(prec) \
+ test##prec(copysign##prec(1.0, nextafter##prec(0.0, -0.0)), -1.0, 0); \
+ test##prec(copysign##prec(1.0, nextafter##prec(-0.0, 0.0)), 1.0, 0); \
+ test##prec(copysign##prec(1.0, nexttoward##prec(0.0, -0.0)), -1.0, 0);\
+ test##prec(copysign##prec(1.0, nexttoward##prec(-0.0, 0.0)), 1.0, 0)
+
+ ztest();
+ ztest(f);
+ ztest(l);
+#undef ztest
+
+#define stest(next, eps, prec) \
+ test##prec(next(-0.0, 42.0), eps, ex_under); \
+ test##prec(next(0.0, -42.0), -eps, ex_under); \
+ test##prec(next(0.0, INFINITY), eps, ex_under); \
+ test##prec(next(-0.0, -INFINITY), -eps, ex_under)
+
+ stest(nextafter, 0x1p-1074, );
+ stest(nextafterf, 0x1p-149f, f);
+ stest(nextafterl, ldbl_small, l);
+ stest(nexttoward, 0x1p-1074, );
+ stest(nexttowardf, 0x1p-149f, f);
+ stest(nexttowardl, ldbl_small, l);
+#undef stest
+
+ printf("ok 1 - next\n");
+
+ /*
+ * `x == y' and NaN tests
+ */
+ testall(42.0, 42.0, 42.0, 0);
+ testall(-42.0, -42.0, -42.0, 0);
+ testall(INFINITY, INFINITY, INFINITY, 0);
+ testall(-INFINITY, -INFINITY, -INFINITY, 0);
+ testall(NAN, 42.0, NAN, 0);
+ testall(42.0, NAN, NAN, 0);
+ testall(NAN, NAN, NAN, 0);
+
+ printf("ok 2 - next\n");
+
+ /*
+ * Tests where x is an ordinary normalized number
+ */
+ testboth(1.0, 2.0, 1.0 + DBL_EPSILON, 0, );
+ testboth(1.0, -INFINITY, 1.0 - DBL_EPSILON/2, 0, );
+ testboth(1.0, 2.0, 1.0 + FLT_EPSILON, 0, f);
+ testboth(1.0, -INFINITY, 1.0 - FLT_EPSILON/2, 0, f);
+ testboth(1.0, 2.0, 1.0 + ldbl_eps, 0, l);
+ testboth(1.0, -INFINITY, 1.0 - ldbl_eps/2, 0, l);
+
+ testboth(-1.0, 2.0, -1.0 + DBL_EPSILON/2, 0, );
+ testboth(-1.0, -INFINITY, -1.0 - DBL_EPSILON, 0, );
+ testboth(-1.0, 2.0, -1.0 + FLT_EPSILON/2, 0, f);
+ testboth(-1.0, -INFINITY, -1.0 - FLT_EPSILON, 0, f);
+ testboth(-1.0, 2.0, -1.0 + ldbl_eps/2, 0, l);
+ testboth(-1.0, -INFINITY, -1.0 - ldbl_eps, 0, l);
+
+ /* Cases where nextafter(...) != nexttoward(...) */
+ test(nexttoward(1.0, 1.0 + ldbl_eps), 1.0 + DBL_EPSILON, 0);
+ testf(nexttowardf(1.0, 1.0 + ldbl_eps), 1.0 + FLT_EPSILON, 0);
+ testl(nexttowardl(1.0, 1.0 + ldbl_eps), 1.0 + ldbl_eps, 0);
+
+ printf("ok 3 - next\n");
+
+ /*
+ * Tests at word boundaries, normalization boundaries, etc.
+ */
+ testboth(0x1.87654ffffffffp+0, INFINITY, 0x1.87655p+0, 0, );
+ testboth(0x1.87655p+0, -INFINITY, 0x1.87654ffffffffp+0, 0, );
+ testboth(0x1.fffffffffffffp+0, INFINITY, 0x1p1, 0, );
+ testboth(0x1p1, -INFINITY, 0x1.fffffffffffffp+0, 0, );
+ testboth(0x0.fffffffffffffp-1022, INFINITY, 0x1p-1022, 0, );
+ testboth(0x1p-1022, -INFINITY, 0x0.fffffffffffffp-1022, ex_under, );
+
+ testboth(0x1.fffffep0f, INFINITY, 0x1p1, 0, f);
+ testboth(0x1p1, -INFINITY, 0x1.fffffep0f, 0, f);
+ testboth(0x0.fffffep-126f, INFINITY, 0x1p-126f, 0, f);
+ testboth(0x1p-126f, -INFINITY, 0x0.fffffep-126f, ex_under, f);
+
+#if LDBL_MANT_DIG == 53
+ testboth(0x1.87654ffffffffp+0L, INFINITY, 0x1.87655p+0L, 0, l);
+ testboth(0x1.87655p+0L, -INFINITY, 0x1.87654ffffffffp+0L, 0, l);
+ testboth(0x1.fffffffffffffp+0L, INFINITY, 0x1p1L, 0, l);
+ testboth(0x1p1L, -INFINITY, 0x1.fffffffffffffp+0L, 0, l);
+ testboth(0x0.fffffffffffffp-1022L, INFINITY, 0x1p-1022L, 0, l);
+ testboth(0x1p-1022L, -INFINITY, 0x0.fffffffffffffp-1022L, ex_under, l);
+#elif LDBL_MANT_DIG == 64 && !defined(__i386)
+ testboth(0x1.87654321fffffffep+0L, INFINITY, 0x1.87654322p+0L, 0, l);
+ testboth(0x1.87654322p+0L, -INFINITY, 0x1.87654321fffffffep+0L, 0, l);
+ testboth(0x1.fffffffffffffffep0L, INFINITY, 0x1p1L, 0, l);
+ testboth(0x1p1L, -INFINITY, 0x1.fffffffffffffffep0L, 0, l);
+ testboth(0x0.fffffffffffffffep-16382L, INFINITY, 0x1p-16382L, 0, l);
+ testboth(0x1p-16382L, -INFINITY,
+ 0x0.fffffffffffffffep-16382L, ex_under, l);
+#elif LDBL_MANT_DIG == 113
+ testboth(0x1.876543210987ffffffffffffffffp+0L, INFINITY,
+ 0x1.876543210988p+0, 0, l);
+ testboth(0x1.876543210988p+0L, -INFINITY,
+ 0x1.876543210987ffffffffffffffffp+0L, 0, l);
+ testboth(0x1.ffffffffffffffffffffffffffffp0L, INFINITY, 0x1p1L, 0, l);
+ testboth(0x1p1L, -INFINITY, 0x1.ffffffffffffffffffffffffffffp0L, 0, l);
+ testboth(0x0.ffffffffffffffffffffffffffffp-16382L, INFINITY,
+ 0x1p-16382L, 0, l);
+ testboth(0x1p-16382L, -INFINITY,
+ 0x0.ffffffffffffffffffffffffffffp-16382L, ex_under, l);
+#endif
+
+ printf("ok 4 - next\n");
+
+ /*
+ * Overflow tests
+ */
+ test(idd(nextafter(DBL_MAX, INFINITY)), INFINITY, ex_over);
+ test(idd(nextafter(INFINITY, 0.0)), DBL_MAX, 0);
+ test(idd(nexttoward(DBL_MAX, DBL_MAX * 2.0L)), INFINITY, ex_over);
+#if LDBL_MANT_DIG > 53
+ test(idd(nexttoward(INFINITY, DBL_MAX * 2.0L)), DBL_MAX, 0);
+#endif
+
+ testf(idf(nextafterf(FLT_MAX, INFINITY)), INFINITY, ex_over);
+ testf(idf(nextafterf(INFINITY, 0.0)), FLT_MAX, 0);
+ testf(idf(nexttowardf(FLT_MAX, FLT_MAX * 2.0)), INFINITY, ex_over);
+ testf(idf(nexttowardf(INFINITY, FLT_MAX * 2.0)), FLT_MAX, 0);
+
+ testboth(ldbl_max, INFINITY, INFINITY, ex_over, l);
+ testboth(INFINITY, 0.0, ldbl_max, 0, l);
+
+ printf("ok 5 - next\n");
+
+ return (0);
+}
+
+static void
+_testl(const char *exp, int line, long double actual, long double expected,
+ int except)
+{
+ int actual_except;
+
+ actual_except = fetestexcept(ALL_STD_EXCEPT);
+ if (!fpequal(actual, expected)) {
+ fprintf(stderr, "%d: %s returned %La, expecting %La\n",
+ line, exp, actual, expected);
+ abort();
+ }
+ if (actual_except != except) {
+ fprintf(stderr, "%d: %s raised 0x%x, expecting 0x%x\n",
+ line, exp, actual_except, except);
+ abort();
+ }
+}
+
+/*
+ * The idd() and idf() routines ensure that doubles and floats are
+ * converted to their respective types instead of stored in the FPU
+ * with extra precision.
+ */
+static double
+idd(double x)
+{
+ return (x);
+}
+
+static float
+idf(float x)
+{
+ return (x);
+}
diff --git a/lib/msun/tests/rem_test.c b/lib/msun/tests/rem_test.c
new file mode 100644
index 0000000..36e3476
--- /dev/null
+++ b/lib/msun/tests/rem_test.c
@@ -0,0 +1,207 @@
+/*-
+ * Copyright (c) 2005-2008 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Test for remainder functions: remainder, remainderf, remainderl,
+ * remquo, remquof, and remquol.
+ * Missing tests: fmod, fmodf.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+static void test_invalid(long double, long double);
+static void testl(long double, long double, long double, int);
+static void testd(double, double, double, int);
+static void testf(float, float, float, int);
+
+#define test(x, y, e_r, e_q) do { \
+ testl(x, y, e_r, e_q); \
+ testd(x, y, e_r, e_q); \
+ testf(x, y, e_r, e_q); \
+} while (0)
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..3\n");
+
+ test_invalid(0.0, 0.0);
+ test_invalid(1.0, 0.0);
+ test_invalid(INFINITY, 0.0);
+ test_invalid(INFINITY, 1.0);
+ test_invalid(-INFINITY, 1.0);
+ test_invalid(NAN, 1.0);
+ test_invalid(1.0, NAN);
+
+ test(4, 4, 0, 1);
+ test(0, 3.0, 0, 0);
+ testd(0x1p-1074, 1, 0x1p-1074, 0);
+ testf(0x1p-149, 1, 0x1p-149, 0);
+ test(3.0, 4, -1, 1);
+ test(3.0, -4, -1, -1);
+ testd(275 * 1193040, 275, 0, 1193040);
+ test(4.5 * 7.5, 4.5, -2.25, 8); /* we should get the even one */
+ testf(0x1.9044f6p-1, 0x1.ce662ep-1, -0x1.f109cp-4, 1);
+#if LDBL_MANT_DIG > 53
+ testl(-0x1.23456789abcdefp-2000L, 0x1.fedcba987654321p-2000L,
+ 0x1.b72ea61d950c862p-2001L, -1);
+#endif
+
+ printf("ok 1 - rem\n");
+
+ /*
+ * The actual quotient here is 864062210.50000003..., but
+ * double-precision division gets -8.64062210.5, which rounds
+ * the wrong way. This test ensures that remquo() is smart
+ * enough to get the low-order bit right.
+ */
+ testd(-0x1.98260f22fc6dep-302, 0x1.fb3167c430a13p-332,
+ 0x1.fb3165b82de72p-333, -864062211);
+ /* Even harder cases with greater exponent separation */
+ test(0x1.fp100, 0x1.ep-40, -0x1.cp-41, 143165577);
+ testd(-0x1.abcdefp120, 0x1.87654321p-120,
+ -0x1.69c78ec4p-121, -63816414);
+
+ printf("ok 2 - rem\n");
+
+ test(0x1.66666cp+120, 0x1p+71, 0.0, 1476395008);
+ testd(-0x1.0000000000003p+0, 0x1.0000000000003p+0, -0.0, -1);
+ testl(-0x1.0000000000003p+0, 0x1.0000000000003p+0, -0.0, -1);
+ testd(-0x1.0000000000001p-749, 0x1.4p-1072, 0x1p-1074, -1288490189);
+ testl(-0x1.0000000000001p-749, 0x1.4p-1072, 0x1p-1074, -1288490189);
+
+ printf("ok 3 - rem\n");
+
+ return (0);
+}
+
+static void
+test_invalid(long double x, long double y)
+{
+ int q;
+
+ q = 0xdeadbeef;
+
+ assert(isnan(remainder(x, y)));
+ assert(isnan(remquo(x, y, &q)));
+#ifdef STRICT
+ assert(q == 0xdeadbeef);
+#endif
+
+ assert(isnan(remainderf(x, y)));
+ assert(isnan(remquof(x, y, &q)));
+#ifdef STRICT
+ assert(q == 0xdeadbeef);
+#endif
+
+ assert(isnan(remainderl(x, y)));
+ assert(isnan(remquol(x, y, &q)));
+#ifdef STRICT
+ assert(q == 0xdeadbeef);
+#endif
+}
+
+/* 0x012345 ==> 0x01ffff */
+static inline int
+mask(int x)
+{
+ return ((unsigned)~0 >> (32 - fls(x)));
+}
+
+static void
+testl(long double x, long double y, long double expected_rem, int expected_quo)
+{
+ int q;
+ long double rem;
+
+ q = random();
+ rem = remainderl(x, y);
+ assert(rem == expected_rem);
+ assert(!signbit(rem) == !signbit(expected_rem));
+ rem = remquol(x, y, &q);
+ assert(rem == expected_rem);
+ assert(!signbit(rem) == !signbit(expected_rem));
+ assert((q ^ expected_quo) >= 0); /* sign(q) == sign(expected_quo) */
+ assert((q & 0x7) == (expected_quo & 0x7));
+ if (q != 0) {
+ assert((q > 0) ^ !(expected_quo > 0));
+ q = abs(q);
+ assert(q == (abs(expected_quo) & mask(q)));
+ }
+}
+
+static void
+testd(double x, double y, double expected_rem, int expected_quo)
+{
+ int q;
+ double rem;
+
+ q = random();
+ rem = remainder(x, y);
+ assert(rem == expected_rem);
+ assert(!signbit(rem) == !signbit(expected_rem));
+ rem = remquo(x, y, &q);
+ assert(rem == expected_rem);
+ assert(!signbit(rem) == !signbit(expected_rem));
+ assert((q ^ expected_quo) >= 0); /* sign(q) == sign(expected_quo) */
+ assert((q & 0x7) == (expected_quo & 0x7));
+ if (q != 0) {
+ assert((q > 0) ^ !(expected_quo > 0));
+ q = abs(q);
+ assert(q == (abs(expected_quo) & mask(q)));
+ }
+}
+
+static void
+testf(float x, float y, float expected_rem, int expected_quo)
+{
+ int q;
+ float rem;
+
+ q = random();
+ rem = remainderf(x, y);
+ assert(rem == expected_rem);
+ assert(!signbit(rem) == !signbit(expected_rem));
+ rem = remquof(x, y, &q);
+ assert(rem == expected_rem);
+ assert(!signbit(rem) == !signbit(expected_rem));
+ assert((q ^ expected_quo) >= 0); /* sign(q) == sign(expected_quo) */
+ assert((q & 0x7) == (expected_quo & 0x7));
+ if (q != 0) {
+ assert((q > 0) ^ !(expected_quo > 0));
+ q = abs(q);
+ assert((q & mask(q)) == (abs(expected_quo) & mask(q)));
+ }
+}
diff --git a/lib/msun/tests/trig_test.c b/lib/msun/tests/trig_test.c
new file mode 100644
index 0000000..1dcce1f
--- /dev/null
+++ b/lib/msun/tests/trig_test.c
@@ -0,0 +1,280 @@
+/*-
+ * Copyright (c) 2008 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Tests for corner cases in trigonometric functions. Some accuracy tests
+ * are included as well, but these are very basic sanity checks, not
+ * intended to be comprehensive.
+ *
+ * The program for generating representable numbers near multiples of pi is
+ * available at http://www.cs.berkeley.edu/~wkahan/testpi/ .
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "test-utils.h"
+
+#pragma STDC FENV_ACCESS ON
+
+/*
+ * Test that a function returns the correct value and sets the
+ * exception flags correctly. The exceptmask specifies which
+ * exceptions we should check. We need to be lenient for several
+ * reasons, but mainly because on some architectures it's impossible
+ * to raise FE_OVERFLOW without raising FE_INEXACT.
+ *
+ * These are macros instead of functions so that assert provides more
+ * meaningful error messages.
+ *
+ * XXX The volatile here is to avoid gcc's bogus constant folding and work
+ * around the lack of support for the FENV_ACCESS pragma.
+ */
+#define test(func, x, result, exceptmask, excepts) do { \
+ volatile long double _d = x; \
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
+ assert(fpequal((func)(_d), (result))); \
+ assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
+} while (0)
+
+#define testall(prefix, x, result, exceptmask, excepts) do { \
+ test(prefix, x, (double)result, exceptmask, excepts); \
+ test(prefix##f, x, (float)result, exceptmask, excepts); \
+ test(prefix##l, x, result, exceptmask, excepts); \
+} while (0)
+
+#define testdf(prefix, x, result, exceptmask, excepts) do { \
+ test(prefix, x, (double)result, exceptmask, excepts); \
+ test(prefix##f, x, (float)result, exceptmask, excepts); \
+} while (0)
+
+/*
+ * Test special cases in sin(), cos(), and tan().
+ */
+static void
+run_special_tests(void)
+{
+
+ /* Values at 0 should be exact. */
+ testall(tan, 0.0, 0.0, ALL_STD_EXCEPT, 0);
+ testall(tan, -0.0, -0.0, ALL_STD_EXCEPT, 0);
+ testall(cos, 0.0, 1.0, ALL_STD_EXCEPT, 0);
+ testall(cos, -0.0, 1.0, ALL_STD_EXCEPT, 0);
+ testall(sin, 0.0, 0.0, ALL_STD_EXCEPT, 0);
+ testall(sin, -0.0, -0.0, ALL_STD_EXCEPT, 0);
+
+ /* func(+-Inf) == NaN */
+ testall(tan, INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
+ testall(sin, INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
+ testall(cos, INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
+ testall(tan, -INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
+ testall(sin, -INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
+ testall(cos, -INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
+
+ /* func(NaN) == NaN */
+ testall(tan, NAN, NAN, ALL_STD_EXCEPT, 0);
+ testall(sin, NAN, NAN, ALL_STD_EXCEPT, 0);
+ testall(cos, NAN, NAN, ALL_STD_EXCEPT, 0);
+}
+
+/*
+ * Tests to ensure argument reduction for large arguments is accurate.
+ */
+static void
+run_reduction_tests(void)
+{
+ /* floats very close to odd multiples of pi */
+ static const float f_pi_odd[] = {
+ 85563208.0f,
+ 43998769152.0f,
+ 9.2763667655669323e+25f,
+ 1.5458357838905804e+29f,
+ };
+ /* doubles very close to odd multiples of pi */
+ static const double d_pi_odd[] = {
+ 3.1415926535897931,
+ 91.106186954104004,
+ 642615.9188844458,
+ 3397346.5699258847,
+ 6134899525417045.0,
+ 3.0213551960457761e+43,
+ 1.2646209897993783e+295,
+ 6.2083625380677099e+307,
+ };
+ /* long doubles very close to odd multiples of pi */
+#if LDBL_MANT_DIG == 64
+ static const long double ld_pi_odd[] = {
+ 1.1891886960373841596e+101L,
+ 1.07999475322710967206e+2087L,
+ 6.522151627890431836e+2147L,
+ 8.9368974898260328229e+2484L,
+ 9.2961044110572205863e+2555L,
+ 4.90208421886578286e+3189L,
+ 1.5275546401232615884e+3317L,
+ 1.7227465626338900093e+3565L,
+ 2.4160090594000745334e+3808L,
+ 9.8477555741888350649e+4314L,
+ 1.6061597222105160737e+4326L,
+ };
+#elif LDBL_MANT_DIG == 113
+ static const long double ld_pi_odd[] = {
+ /* XXX */
+ };
+#endif
+
+ int i;
+
+ for (i = 0; i < nitems(f_pi_odd); i++) {
+ assert(fabs(sinf(f_pi_odd[i])) < FLT_EPSILON);
+ assert(cosf(f_pi_odd[i]) == -1.0);
+ assert(fabs(tan(f_pi_odd[i])) < FLT_EPSILON);
+
+ assert(fabs(sinf(-f_pi_odd[i])) < FLT_EPSILON);
+ assert(cosf(-f_pi_odd[i]) == -1.0);
+ assert(fabs(tanf(-f_pi_odd[i])) < FLT_EPSILON);
+
+ assert(fabs(sinf(f_pi_odd[i] * 2)) < FLT_EPSILON);
+ assert(cosf(f_pi_odd[i] * 2) == 1.0);
+ assert(fabs(tanf(f_pi_odd[i] * 2)) < FLT_EPSILON);
+
+ assert(fabs(sinf(-f_pi_odd[i] * 2)) < FLT_EPSILON);
+ assert(cosf(-f_pi_odd[i] * 2) == 1.0);
+ assert(fabs(tanf(-f_pi_odd[i] * 2)) < FLT_EPSILON);
+ }
+
+ for (i = 0; i < nitems(d_pi_odd); i++) {
+ assert(fabs(sin(d_pi_odd[i])) < 2 * DBL_EPSILON);
+ assert(cos(d_pi_odd[i]) == -1.0);
+ assert(fabs(tan(d_pi_odd[i])) < 2 * DBL_EPSILON);
+
+ assert(fabs(sin(-d_pi_odd[i])) < 2 * DBL_EPSILON);
+ assert(cos(-d_pi_odd[i]) == -1.0);
+ assert(fabs(tan(-d_pi_odd[i])) < 2 * DBL_EPSILON);
+
+ assert(fabs(sin(d_pi_odd[i] * 2)) < 2 * DBL_EPSILON);
+ assert(cos(d_pi_odd[i] * 2) == 1.0);
+ assert(fabs(tan(d_pi_odd[i] * 2)) < 2 * DBL_EPSILON);
+
+ assert(fabs(sin(-d_pi_odd[i] * 2)) < 2 * DBL_EPSILON);
+ assert(cos(-d_pi_odd[i] * 2) == 1.0);
+ assert(fabs(tan(-d_pi_odd[i] * 2)) < 2 * DBL_EPSILON);
+ }
+
+#if LDBL_MANT_DIG > 53
+ for (i = 0; i < nitems(ld_pi_odd); i++) {
+ assert(fabsl(sinl(ld_pi_odd[i])) < LDBL_EPSILON);
+ assert(cosl(ld_pi_odd[i]) == -1.0);
+ assert(fabsl(tanl(ld_pi_odd[i])) < LDBL_EPSILON);
+
+ assert(fabsl(sinl(-ld_pi_odd[i])) < LDBL_EPSILON);
+ assert(cosl(-ld_pi_odd[i]) == -1.0);
+ assert(fabsl(tanl(-ld_pi_odd[i])) < LDBL_EPSILON);
+
+ assert(fabsl(sinl(ld_pi_odd[i] * 2)) < LDBL_EPSILON);
+ assert(cosl(ld_pi_odd[i] * 2) == 1.0);
+ assert(fabsl(tanl(ld_pi_odd[i] * 2)) < LDBL_EPSILON);
+
+ assert(fabsl(sinl(-ld_pi_odd[i] * 2)) < LDBL_EPSILON);
+ assert(cosl(-ld_pi_odd[i] * 2) == 1.0);
+ assert(fabsl(tanl(-ld_pi_odd[i] * 2)) < LDBL_EPSILON);
+ }
+#endif
+}
+
+/*
+ * Tests the accuracy of these functions over the primary range.
+ */
+static void
+run_accuracy_tests(void)
+{
+
+ /* For small args, sin(x) = tan(x) = x, and cos(x) = 1. */
+ testall(sin, 0xd.50ee515fe4aea16p-114L, 0xd.50ee515fe4aea16p-114L,
+ ALL_STD_EXCEPT, FE_INEXACT);
+ testall(tan, 0xd.50ee515fe4aea16p-114L, 0xd.50ee515fe4aea16p-114L,
+ ALL_STD_EXCEPT, FE_INEXACT);
+ testall(cos, 0xd.50ee515fe4aea16p-114L, 1.0,
+ ALL_STD_EXCEPT, FE_INEXACT);
+
+ /*
+ * These tests should pass for f32, d64, and ld80 as long as
+ * the error is <= 0.75 ulp (round to nearest)
+ */
+#if LDBL_MANT_DIG <= 64
+#define testacc testall
+#else
+#define testacc testdf
+#endif
+ testacc(sin, 0.17255452780841205174L, 0.17169949801444412683L,
+ ALL_STD_EXCEPT, FE_INEXACT);
+ testacc(sin, -0.75431944555904520893L, -0.68479288156557286353L,
+ ALL_STD_EXCEPT, FE_INEXACT);
+ testacc(cos, 0.70556358769838947292L, 0.76124620693117771850L,
+ ALL_STD_EXCEPT, FE_INEXACT);
+ testacc(cos, -0.34061437849088045332L, 0.94254960031831729956L,
+ ALL_STD_EXCEPT, FE_INEXACT);
+ testacc(tan, -0.15862817413325692897L, -0.15997221861309522115L,
+ ALL_STD_EXCEPT, FE_INEXACT);
+ testacc(tan, 0.38374784931303813530L, 0.40376500259976759951L,
+ ALL_STD_EXCEPT, FE_INEXACT);
+
+ /*
+ * XXX missing:
+ * - tests for ld128
+ * - tests for other rounding modes (probably won't pass for now)
+ * - tests for large numbers that get reduced to hi+lo with lo!=0
+ */
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..3\n");
+
+ run_special_tests();
+ printf("ok 1 - trig\n");
+
+#ifndef __i386__
+ run_reduction_tests();
+#endif
+ printf("ok 2 - trig\n");
+
+#ifndef __i386__
+ run_accuracy_tests();
+#endif
+ printf("ok 3 - trig\n");
+
+ return (0);
+}
OpenPOWER on IntegriCloud