aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.codacy.yml5
-rw-r--r--.github/workflows/windows.yml4
-rw-r--r--CMakeLists.txt471
-rw-r--r--src/CMakeLists.txt26
-rw-r--r--src/protocol/pair1/CMakeLists.txt13
-rw-r--r--src/protocol/pair1/pair.c1
-rw-r--r--src/protocol/pair1/pair1_test.c607
-rw-r--r--src/protocol/reqrep0/CMakeLists.txt32
-rw-r--r--src/protocol/reqrep0/reqrep_test.c300
-rw-r--r--src/supplemental/base64/CMakeLists.txt1
-rw-r--r--src/supplemental/base64/base64_test.c106
-rw-r--r--src/supplemental/sha1/CMakeLists.txt10
-rw-r--r--src/supplemental/sha1/sha1_test.c (renamed from tests/sha1.c)61
-rw-r--r--src/transport/inproc/CMakeLists.txt12
-rw-r--r--tests/CMakeLists.txt143
-rw-r--r--tests/acutest.h1650
-rw-r--r--tests/aio.c377
-rw-r--r--tests/base64.c84
-rw-r--r--tests/bufsz.c190
-rw-r--r--tests/pair1.c541
-rw-r--r--tests/platform.c201
-rw-r--r--tests/reqrep.c289
-rw-r--r--tests/sock.c1139
-rw-r--r--tests/stubs.h18
-rw-r--r--tests/testutil.c310
-rw-r--r--tests/testutil.h49
26 files changed, 4506 insertions, 2134 deletions
diff --git a/.codacy.yml b/.codacy.yml
new file mode 100644
index 00000000..cce28d36
--- /dev/null
+++ b/.codacy.yml
@@ -0,0 +1,5 @@
+exclude_paths:
+ - tests/acutest.h
+ - tests/convey.c
+ - tests/convey.h
+ - .circleci/** \ No newline at end of file
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 12ff1282..03054037 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -16,5 +16,7 @@ jobs:
run: cmake --build build
- name: Test
- run: ctest -C Debug --output-on-failure
+ run: |
+ cd build
+ ctest -C Debug --output-on-failure
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5c8132b8..31e2efcb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,9 +1,9 @@
#
+# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
# Copyright (c) 2012 Martin Sustrik All rights reserved.
# Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
# Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved.
# Copyright 2016 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com>
-# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -25,73 +25,73 @@
# IN THE SOFTWARE.
#
-cmake_minimum_required (VERSION 3.1)
+cmake_minimum_required(VERSION 3.1)
-project (nng C)
-include (CheckFunctionExists)
-include (CheckSymbolExists)
-include (CheckStructHasMember)
-include (CheckLibraryExists)
-include (CheckCSourceCompiles)
-include (CheckCCompilerFlag)
-include (CMakeDependentOption)
-include (GNUInstallDirs)
-include (TestBigEndian)
-include (FindUnixCommands)
+project(nng C)
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+include(CheckStructHasMember)
+include(CheckLibraryExists)
+include(CheckCSourceCompiles)
+include(CheckCCompilerFlag)
+include(CMakeDependentOption)
+include(GNUInstallDirs)
+include(TestBigEndian)
+include(FindUnixCommands)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
if (POLICY CMP0042)
# Newer cmake on MacOS should use @rpath
- cmake_policy (SET CMP0042 NEW)
+ cmake_policy(SET CMP0042 NEW)
endif ()
if (POLICY CMP0028)
# Double colon targets are only alias or imports.
- cmake_policy (SET CMP0028 NEW)
+ cmake_policy(SET CMP0028 NEW)
endif ()
set(CMAKE_C_STANDARD 99)
-set (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
-list (FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" isSystemDir)
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" isSystemDir)
if ("${isSystemDir}" STREQUAL "-1")
- set (CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif ("${isSystemDir}" STREQUAL "-1")
-set (NNG_DESCRIPTION "High-Performance Scalability Protocols NextGen")
-set (ISSUE_REPORT_MSG "Please consider opening an issue at https://github.com/nanomsg/nng")
+set(NNG_DESCRIPTION "High-Performance Scalability Protocols NextGen")
+set(ISSUE_REPORT_MSG "Please consider opening an issue at https://github.com/nanomsg/nng")
# Determine library versions.
-set (NNG_ABI_SOVERSION 1)
-set (NNG_ABI_VERSION "1.1.0")
+set(NNG_ABI_SOVERSION 1)
+set(NNG_ABI_VERSION "1.1.0")
# Determine package version.
-find_package (Git QUIET)
+find_package(Git QUIET)
if (GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
# Working off a git repo, using git versioning
# Get version from last tag
- execute_process (
- COMMAND "${GIT_EXECUTABLE}" describe --always# | sed -e "s:v::"
- WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
- OUTPUT_VARIABLE NNG_PACKAGE_VERSION
- OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(
+ COMMAND "${GIT_EXECUTABLE}" describe --always# | sed -e "s:v::"
+ WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
+ OUTPUT_VARIABLE NNG_PACKAGE_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
# If the sources have been changed locally, add -dirty to the version.
- execute_process (
- COMMAND "${GIT_EXECUTABLE}" diff --quiet
- WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
- RESULT_VARIABLE res)
+ execute_process(
+ COMMAND "${GIT_EXECUTABLE}" diff --quiet
+ WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
+ RESULT_VARIABLE res)
if (res EQUAL 1)
- set (NNG_PACKAGE_VERSION "${NNG_PACKAGE_VERSION}-dirty")
- endif()
+ set(NNG_PACKAGE_VERSION "${NNG_PACKAGE_VERSION}-dirty")
+ endif ()
else ()
- set (NNG_PACKAGE_VERSION "Unknown")
-endif()
+ set(NNG_PACKAGE_VERSION "Unknown")
+endif ()
if ("${NNG_PACKAGE_VERSION}" MATCHES "v[0-9]")
string(SUBSTRING "${NNG_PACKAGE_VERSION}" 1 -1 NNG_PACKAGE_VERSION)
-endif()
+endif ()
string(REGEX REPLACE "([0-9]+).[0-9]+.+" "\\1" NNG_VERSION_MAJOR "${NNG_PACKAGE_VERSION}")
string(REGEX REPLACE "[0-9]+.([0-9]+).[0-9].+" "\\1" NNG_VERSION_MINOR "${NNG_PACKAGE_VERSION}")
@@ -102,20 +102,20 @@ string(REGEX REPLACE "[0-9]+.[0-9]+.([0-9]+).*" "\\1" NNG_VERSION_PATCH "${NNG_P
option(BUILD_SHARED_LIBS "Build shared library" ${BUILD_SHARED_LIBS})
if (CMAKE_CROSSCOMPILING)
- set (NNG_NATIVE_BUILD OFF)
-else()
- set (NNG_NATIVE_BUILD ON)
-endif()
+ set(NNG_NATIVE_BUILD OFF)
+else ()
+ set(NNG_NATIVE_BUILD ON)
+endif ()
# We only build command line tools and tests if we are not in a
# cross-compile situation. Cross-compiling users who still want to
# build these must enable them explicitly.
-option (NNG_TESTS "Build and run tests" ${NNG_NATIVE_BUILD})
-option (NNG_TOOLS "Build extra tools" ${NNG_NATIVE_BUILD})
-option (NNG_ENABLE_NNGCAT "Enable building nngcat utility." ${NNG_TOOLS})
-option (NNG_ENABLE_COVERAGE "Enable coverage reporting." OFF)
+option(NNG_TESTS "Build and run tests" ${NNG_NATIVE_BUILD})
+option(NNG_TOOLS "Build extra tools" ${NNG_NATIVE_BUILD})
+option(NNG_ENABLE_NNGCAT "Enable building nngcat utility." ${NNG_TOOLS})
+option(NNG_ENABLE_COVERAGE "Enable coverage reporting." OFF)
# Enable access to private APIs for our own use.
-add_definitions (-DNNG_PRIVATE)
+add_definitions(-DNNG_PRIVATE)
# We can use rlimit to configure the stack size for systems
# that have too small defaults. This is not used for Windows,
@@ -123,288 +123,379 @@ add_definitions (-DNNG_PRIVATE)
# by with a smallish stack, but application callbacks might require
# larger values if using aio completion callbacks.)
if (NOT WIN32)
- option (NNG_SETSTACKSIZE "Use rlimit for thread stack size" OFF)
+ option(NNG_SETSTACKSIZE "Use rlimit for thread stack size" OFF)
if (NNG_SETSTACKSIZE)
add_definitions(-DNNG_SETSTACKSIZE)
- endif()
+ endif ()
mark_as_advanced(NNG_SETSTACKSIZE)
-endif()
+endif ()
-option (NNG_ENABLE_TLS "Enable TLS protocol (requires mbedTLS)" OFF)
+option(NNG_ENABLE_TLS "Enable TLS protocol (requires mbedTLS)" OFF)
if (NNG_ENABLE_TLS)
add_definitions(-DNNG_SUPP_TLS)
set(NNG_SUPP_TLS ON)
-endif()
+endif ()
-option (NNG_ENABLE_STATS "Enable statistics" ON)
+option(NNG_ENABLE_STATS "Enable statistics" ON)
if (NNG_ENABLE_STATS)
add_definitions(-DNNG_ENABLE_STATS)
-endif()
+endif ()
mark_as_advanced(NNG_ENABLE_STATS)
if (NNG_RESOLV_CONCURRENCY)
add_definitions(-DNNG_RESOLV_CONCURRENCY=${NNG_RESOLV_CONCURRENCY})
-endif()
+endif ()
mark_as_advanced(NNG_RESOLV_CONCURRENCY)
if (NNG_NUM_TASKQ_THREADS)
add_definitions(-DNNG_NUM_TASKQ_THREADS=${NNG_NUM_TASKQ_THREADS})
-endif()
+endif ()
mark_as_advanced(NNG_NUM_TASKQ_THREADS)
# Platform checks.
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- set(NNG_WARN_FLAGS "-Wall -Wextra -fno-omit-frame-pointer")
+ set(NNG_WARN_FLAGS "-Wall -Wextra -fno-omit-frame-pointer")
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(NNG_WARN_FLAGS "-Wall -Wextra -fno-omit-frame-pointer")
elseif (CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
set(NNG_WARN_FLAGS "-Wall -Wextra -fno-omit-frame-pointer")
-endif()
+endif ()
-include (CheckSanitizer)
+include(CheckSanitizer)
CheckSanitizer()
if (NOT NNG_SANITIZER STREQUAL "none")
- set (NNG_SANITIZER_FLAGS "-fsanitize=${NNG_SANITIZER}")
-endif()
+ set(NNG_SANITIZER_FLAGS "-fsanitize=${NNG_SANITIZER}")
+endif ()
if (NNG_ENABLE_COVERAGE)
# NB: This only works for GCC and Clang 3.0 and newer. If your stuff
# is older than that, you will need to find something newer. For
# correct reporting, we always turn off all optimizations.
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- set(NNG_COVERAGE_FLAGS "-g -O0 --coverage")
+ set(NNG_COVERAGE_FLAGS "-g -O0 --coverage")
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
- set(NNG_COVERAGE_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+ set(NNG_COVERAGE_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
elseif (CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
- set(NNG_COVERAGE_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
- else()
+ set(NNG_COVERAGE_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+ else ()
message(FATAL_ERROR "Unable to enable coverage for your compiler.")
- endif()
-endif()
+ endif ()
+endif ()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${NNG_WARN_FLAGS} ${NNG_COVERAGE_FLAGS} ${NNG_SANITIZER_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${NNG_WARN_FLAGS} ${NNG_COVERAGE_FLAGS} ${NNG_SANITIZER_FLAGS}")
TEST_BIG_ENDIAN(NNG_BIG_ENDIAN)
if (NNG_BIG_ENDIAN)
- add_definitions (-DNNG_BIG_ENDIAN)
-else()
- add_definitions (-DNNG_LITTLE_ENDIAN)
-endif()
+ add_definitions(-DNNG_BIG_ENDIAN)
+else ()
+ add_definitions(-DNNG_LITTLE_ENDIAN)
+endif ()
# If the compiler is not on Windows, does it support hiding the
# symbols by default? For shared libraries we would like to do this.
if (NOT WIN32 AND NOT CYGWIN)
check_c_compiler_flag(-fvisibility=hidden NNG_HIDDEN_VISIBILITY)
if (NNG_HIDDEN_VISIBILITY)
- add_definitions (-DNNG_HIDDEN_VISIBILITY)
- endif()
-endif()
+ add_definitions(-DNNG_HIDDEN_VISIBILITY)
+ endif ()
+endif ()
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
- add_definitions (-DNNG_PLATFORM_POSIX)
- add_definitions (-DNNG_PLATFORM_LINUX)
- add_definitions (-DNNG_USE_EVENTFD)
+ add_definitions(-DNNG_PLATFORM_POSIX)
+ add_definitions(-DNNG_PLATFORM_LINUX)
+ add_definitions(-DNNG_USE_EVENTFD)
# Windows subsystem for Linux -- smells like Linux, but it has
# some differences (SO_REUSEADDR for one).
if (CMAKE_SYSTEM_VERSION MATCHES "Microsoft")
- add_definitions (-DNNG_PLATFORM_WSL)
- endif()
+ add_definitions(-DNNG_PLATFORM_WSL)
+ endif ()
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "Android")
- add_definitions (-DNNG_PLATFORM_POSIX)
- add_definitions (-DNNG_PLATFORM_LINUX)
- add_definitions (-DNNG_PLATFORM_ANDROID)
- add_definitions (-DNNG_USE_EVENTFD)
+ add_definitions(-DNNG_PLATFORM_POSIX)
+ add_definitions(-DNNG_PLATFORM_LINUX)
+ add_definitions(-DNNG_PLATFORM_ANDROID)
+ add_definitions(-DNNG_USE_EVENTFD)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
- add_definitions (-DNNG_PLATFORM_POSIX)
- add_definitions (-DNNG_PLATFORM_DARWIN)
+ add_definitions(-DNNG_PLATFORM_POSIX)
+ add_definitions(-DNNG_PLATFORM_DARWIN)
# macOS 10.12 and later have getentropy, but the older releases
# have ARC4_RANDOM, and that is sufficient to our needs.
- add_definitions (-DNNG_USE_ARC4RANDOM)
-
- # macOS added some of CLOCK_MONOTONIC, but the implementation is
- # broken and unreliable, so don't use it.
- add_definitions (-DNNG_USE_CLOCKID=CLOCK_REALTIME)
+ add_definitions(-DNNG_USE_ARC4RANDOM)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
- add_definitions (-DNNG_PLATFORM_POSIX)
- add_definitions (-DNNG_PLATFORM_FREEBSD)
+ add_definitions(-DNNG_PLATFORM_POSIX)
+ add_definitions(-DNNG_PLATFORM_FREEBSD)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
- add_definitions (-DNNG_PLATFORM_POSIX)
- add_definitions (-DNNG_PLATFORM_NETBSD)
+ add_definitions(-DNNG_PLATFORM_POSIX)
+ add_definitions(-DNNG_PLATFORM_NETBSD)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
- add_definitions (-DNNG_PLATFORM_POSIX)
- add_definitions (-DNNG_PLATFORM_OPENBSD)
+ add_definitions(-DNNG_PLATFORM_POSIX)
+ add_definitions(-DNNG_PLATFORM_OPENBSD)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "SunOS")
- add_definitions (-DNNG_PLATFORM_POSIX)
- add_definitions (-DNNG_PLATFORM_SUNOS)
+ add_definitions(-DNNG_PLATFORM_POSIX)
+ add_definitions(-DNNG_PLATFORM_SUNOS)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
- add_definitions (-DNNG_PLATFORM_WINDOWS)
- add_definitions (-D_CRT_SECURE_NO_WARNINGS)
- add_definitions (-D_CRT_RAND_S)
+ add_definitions(-DNNG_PLATFORM_WINDOWS)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+ add_definitions(-D_CRT_RAND_S)
set(NNG_PLATFORM_WINDOWS ON)
# Target Windows Vista and later
- add_definitions (-D_WIN32_WINNT=0x0600)
- list (APPEND CMAKE_REQUIRED_DEFINITIONS -D_WIN32_WINNT=0x0600)
+ add_definitions(-D_WIN32_WINNT=0x0600)
+ list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_WIN32_WINNT=0x0600)
elseif (CMAKE_SYSTEM_NAME MATCHES "QNX")
- add_definitions (-DNNG_PLATFORM_POSIX)
- add_definitions (-D__EXT_BSD)
- add_definitions (-D_QNX_SOURCE)
- add_definitions (-DNNG_PLATFORM_QNX)
+ add_definitions(-DNNG_PLATFORM_POSIX)
+ add_definitions(-D__EXT_BSD)
+ add_definitions(-D_QNX_SOURCE)
+ add_definitions(-DNNG_PLATFORM_QNX)
set(NNG_PLATFORM_POSIX ON)
else ()
- message (AUTHOR_WARNING "WARNING: This platform may not be supported: ${CMAKE_SYSTEM_NAME}")
- message (AUTHOR_WARNING "${ISSUE_REPORT_MSG}")
+ message(AUTHOR_WARNING "WARNING: This platform may not be supported: ${CMAKE_SYSTEM_NAME}")
+ message(AUTHOR_WARNING "${ISSUE_REPORT_MSG}")
# blithely hope for POSIX to work
- add_definitions (-DNNG_PLATFORM_POSIX)
+ add_definitions(-DNNG_PLATFORM_POSIX)
endif ()
-macro (nng_check_func SYM DEF)
- check_function_exists (${SYM} ${DEF})
+macro(nng_check_func SYM DEF)
+ check_function_exists(${SYM} ${DEF})
if (${DEF})
- add_definitions (-D${DEF}=1)
+ add_definitions(-D${DEF}=1)
endif ()
-endmacro (nng_check_func)
+endmacro(nng_check_func)
-macro (nng_check_sym SYM HDR DEF)
- check_symbol_exists (${SYM} ${HDR} ${DEF})
+macro(nng_check_sym SYM HDR DEF)
+ check_symbol_exists(${SYM} ${HDR} ${DEF})
if (${DEF})
- add_definitions (-D${DEF}=1)
+ add_definitions(-D${DEF}=1)
endif ()
-endmacro (nng_check_sym)
+endmacro(nng_check_sym)
-macro (nng_check_lib LIB SYM DEF)
- check_library_exists (${LIB} ${SYM} "" ${DEF})
+macro(nng_check_lib LIB SYM DEF)
+ check_library_exists(${LIB} ${SYM} "" ${DEF})
if (${DEF})
- add_definitions (-D${DEF}=1)
+ add_definitions(-D${DEF}=1)
list(APPEND NNG_LIBS ${LIB})
endif ()
-endmacro (nng_check_lib)
+endmacro(nng_check_lib)
-macro (nng_check_struct_member STR MEM HDR DEF)
- check_struct_has_member ("struct ${STR}" ${MEM} ${HDR} ${DEF})
+macro(nng_check_struct_member STR MEM HDR DEF)
+ check_struct_has_member("struct ${STR}" ${MEM} ${HDR} ${DEF})
if (${DEF})
- add_definitions (-D${DEF}=1)
+ add_definitions(-D${DEF}=1)
endif ()
-endmacro (nng_check_struct_member)
+endmacro(nng_check_struct_member)
if (WIN32)
# Windows is a special snowflake.
list(APPEND NNG_LIBS ws2_32 mswsock advapi32)
- nng_check_sym (InitializeConditionVariable windows.h NNG_HAVE_CONDVAR)
- nng_check_sym (snprintf stdio.h NNG_HAVE_SNPRINTF)
+ nng_check_sym(InitializeConditionVariable windows.h NNG_HAVE_CONDVAR)
+ nng_check_sym(snprintf stdio.h NNG_HAVE_SNPRINTF)
if (NOT NNG_HAVE_CONDVAR OR NOT NNG_HAVE_SNPRINTF)
- message (FATAL_ERROR
- "Modern Windows API support is missing. "
- "Versions of Windows prior to Vista are not supported. "
- "Further, the 32-bit MinGW environment is not supported. "
- "Ensure you have at least Windows Vista or newer, and are "
- "using either Visual Studio 2013 or newer or MinGW-W64.")
- endif()
+ message(FATAL_ERROR
+ "Modern Windows API support is missing. "
+ "Versions of Windows prior to Vista are not supported. "
+ "Further, the 32-bit MinGW environment is not supported. "
+ "Ensure you have at least Windows Vista or newer, and are "
+ "using either Visual Studio 2013 or newer or MinGW-W64.")
+ endif ()
else ()
# Unconditionally declare the following feature test macros. These are
# needed for some platforms (glibc and SunOS/illumos) and are harmless
# on the others.
- add_definitions (-D_GNU_SOURCE)
- add_definitions (-D_REENTRANT)
- add_definitions (-D_THREAD_SAFE)
- add_definitions (-D_POSIX_PTHREAD_SEMANTICS)
+ add_definitions(-D_GNU_SOURCE)
+ add_definitions(-D_REENTRANT)
+ add_definitions(-D_THREAD_SAFE)
+ add_definitions(-D_POSIX_PTHREAD_SEMANTICS)
list(APPEND NNG_PKGS Threads)
find_package(Threads REQUIRED)
- nng_check_func (lockf NNG_HAVE_LOCKF)
- nng_check_func (flock NNG_HAVE_FLOCK)
+ nng_check_func(lockf NNG_HAVE_LOCKF)
+ nng_check_func(flock NNG_HAVE_FLOCK)
- nng_check_lib (rt clock_gettime NNG_HAVE_CLOCK_GETTIME)
- nng_check_lib (pthread sem_wait NNG_HAVE_SEMAPHORE_PTHREAD)
- nng_check_lib (pthread pthread_atfork NNG_HAVE_PTHREAD_ATFORK_PTHREAD)
- nng_check_lib (nsl gethostbyname NNG_HAVE_LIBNSL)
- nng_check_lib (socket socket NNG_HAVE_LIBSOCKET)
+ nng_check_lib(rt clock_gettime NNG_HAVE_CLOCK_GETTIME)
+ nng_check_lib(pthread sem_wait NNG_HAVE_SEMAPHORE_PTHREAD)
+ nng_check_lib(pthread pthread_atfork NNG_HAVE_PTHREAD_ATFORK_PTHREAD)
+ nng_check_lib(nsl gethostbyname NNG_HAVE_LIBNSL)
+ nng_check_lib(socket socket NNG_HAVE_LIBSOCKET)
- nng_check_sym (AF_UNIX sys/socket.h NNG_HAVE_UNIX_SOCKETS)
- nng_check_sym (backtrace_symbols_fd execinfo.h NNG_HAVE_BACKTRACE)
+ nng_check_sym(AF_UNIX sys/socket.h NNG_HAVE_UNIX_SOCKETS)
+ nng_check_sym(backtrace_symbols_fd execinfo.h NNG_HAVE_BACKTRACE)
nng_check_struct_member(msghdr msg_control sys/socket.h NNG_HAVE_MSG_CONTROL)
- nng_check_sym (eventfd sys/eventfd.h NNG_HAVE_EVENTFD)
- nng_check_sym (kqueue sys/event.h NNG_HAVE_KQUEUE)
- nng_check_sym (port_create port.h NNG_HAVE_PORT_CREATE)
- nng_check_sym (epoll_create sys/epoll.h NNG_HAVE_EPOLL)
- nng_check_sym (epoll_create1 sys/epoll.h NNG_HAVE_EPOLL_CREATE1)
- nng_check_sym (getpeereid unistd.h NNG_HAVE_GETPEEREID)
- nng_check_sym (SO_PEERCRED sys/socket.h NNG_HAVE_SOPEERCRED)
- nng_check_struct_member (sockpeercred uid sys/socket.h NNG_HAVE_SOCKPEERCRED)
- nng_check_sym (LOCAL_PEERCRED sys/un.h NNG_HAVE_LOCALPEERCRED)
- nng_check_sym (getpeerucred ucred.h NNG_HAVE_GETPEERUCRED)
- nng_check_sym (atomic_flag_test_and_set stdatomic.h NNG_HAVE_STDATOMIC)
+ nng_check_sym(eventfd sys/eventfd.h NNG_HAVE_EVENTFD)
+ nng_check_sym(kqueue sys/event.h NNG_HAVE_KQUEUE)
+ nng_check_sym(port_create port.h NNG_HAVE_PORT_CREATE)
+ nng_check_sym(epoll_create sys/epoll.h NNG_HAVE_EPOLL)
+ nng_check_sym(epoll_create1 sys/epoll.h NNG_HAVE_EPOLL_CREATE1)
+ nng_check_sym(getpeereid unistd.h NNG_HAVE_GETPEEREID)
+ nng_check_sym(SO_PEERCRED sys/socket.h NNG_HAVE_SOPEERCRED)
+ nng_check_struct_member(sockpeercred uid sys/socket.h NNG_HAVE_SOCKPEERCRED)
+ nng_check_sym(LOCAL_PEERCRED sys/un.h NNG_HAVE_LOCALPEERCRED)
+ nng_check_sym(getpeerucred ucred.h NNG_HAVE_GETPEERUCRED)
+ nng_check_sym(atomic_flag_test_and_set stdatomic.h NNG_HAVE_STDATOMIC)
endif ()
-nng_check_sym (strlcat string.h NNG_HAVE_STRLCAT)
-nng_check_sym (strlcpy string.h NNG_HAVE_STRLCPY)
-nng_check_sym (strnlen string.h NNG_HAVE_STRNLEN)
-nng_check_sym (strcasecmp string.h NNG_HAVE_STRCASECMP)
-nng_check_sym (strncasecmp string.h NNG_HAVE_STRNCASECMP)
+nng_check_sym(strlcat string.h NNG_HAVE_STRLCAT)
+nng_check_sym(strlcpy string.h NNG_HAVE_STRLCPY)
+nng_check_sym(strnlen string.h NNG_HAVE_STRNLEN)
+nng_check_sym(strcasecmp string.h NNG_HAVE_STRCASECMP)
+nng_check_sym(strncasecmp string.h NNG_HAVE_STRNCASECMP)
# Set a static symbol. We do this for testing, so that tests can
# be skipped if they would rely on symbols that might not be exported.
# For example, idhash depends on private symbols, so don't test it
# when using a shared library on Windows because the symbols won't
# resolve.
-if (NOT(BUILD_SHARED_LIBS))
- set (NNG_STATIC_LIB ON)
+if (NOT (BUILD_SHARED_LIBS))
+ set(NNG_STATIC_LIB ON)
message(STATUS "Building static libs")
-endif()
+endif ()
+
+# In order to facilitate testing, we want to add a library that includes
+# our common test code. We do this before iterating everywhere else so
+# that we can locate our tests inside the directories where we want.
+if (NNG_TESTS)
+ enable_testing()
+ set(all_tests, "")
+
+
+ macro(nng_test NAME)
+ add_executable(${NAME} ${NAME}.c ${ARGN})
+ target_link_libraries(${NAME} ${PROJECT_NAME}_testlib)
+ target_include_directories(${NAME} PRIVATE
+ ${PROJECT_SOURCE_DIR}/tests
+ ${PROJECT_SOURCE_DIR}/src
+ ${PROJECT_SOURCE_DIR}/include)
+ add_test(NAME ${NAME} COMMAND ${NAME} -t)
+ set_tests_properties(${NAME} PROPERTIES TIMEOUT 180)
+ endmacro()
+
+ function(nng_sources_testlib)
+ foreach (f ${ARGN})
+ target_sources(${PROJECT_NAME}_testlib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
+ endforeach ()
+ endfunction()
+
+ function(nng_headers_testlib)
+ foreach (f ${ARGN})
+ target_sources(${PROJECT_NAME}_testlib PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
+ endforeach ()
+ endfunction()
+
+ function(nng_defines_testlib)
+ target_compile_definitions(${PROJECT_NAME}_testlib PRIVATE ${ARGN})
+ endfunction()
+
+else ()
+ function(nng_test NAME)
+ endfunction()
-add_subdirectory (src)
+ function(nng_sources_testlib)
+ endfunction()
-foreach(_PKG IN ITEMS ${NNG_PKGS})
- find_package(${_PKG} REQUIRED)
+ function(nng_headers_testlib)
+ endfunction()
+
+ function(nng_defines_testlib)
+ endfunction()
+endif ()
+
+function(nng_sources)
+ foreach (f ${ARGN})
+ target_sources(${PROJECT_NAME}_testlib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
+ endforeach ()
+ nng_sources_testlib(${ARGN})
+endfunction()
+
+function(nng_headers)
+ foreach (f ${ARGN})
+ target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
+ endforeach ()
+ nng_headers_testlib(${ARGN})
+endfunction()
+
+function(nng_defines)
+ target_compile_definitions(${PROJECT_NAME} PRIVATE ${ARGN})
+ nng_defines_testlib(${ARGN})
+endfunction()
+
+# nng_sources_if adds the sources unconditionally to the test library,
+# but conditionally to the production library. This allows us to get
+# full test coverage while allowing a minimized delivery.
+function(nng_sources_if COND)
+ if (${COND})
+ foreach (f ${ARGN})
+ target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
+ endforeach ()
+ endif ()
+ nng_sources_testlib(${ARGN})
+endfunction()
+
+function(nng_headers_if COND)
+ if (COND)
+ foreach (f ${ARGN})
+ target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
+ endforeach ()
+ endif ()
+ nng_headers_testlib(${ARGN})
+endfunction()
+
+function(nng_defines_if COND)
+ if (${COND})
+ # Revisit this one
+ target_compile_definitions(${PROJECT_NAME} PUBLIC ${ARGN})
+ endif ()
+ nng_defines_testlib(${ARGN})
+endfunction()
+
+add_subdirectory(src)
+
+foreach (_PKG IN ITEMS ${NNG_PKGS})
+ find_package(${_PKG} REQUIRED)
endforeach ()
add_definitions(${NNG_DEFS})
if (NNG_TESTS)
- enable_testing()
- set(all_tests, "")
- add_subdirectory (tests)
- add_subdirectory (perf)
-endif()
+ add_subdirectory(tests)
+ add_subdirectory(perf)
+endif ()
# Build the tools
if (NNG_ENABLE_NNGCAT)
- add_subdirectory (tools/nngcat)
+ add_subdirectory(tools/nngcat)
endif ()
-add_subdirectory (docs/man)
-
-set (CPACK_PACKAGE_NAME ${PROJECT_NAME})
-set (CPACK_PACKAGE_VERSION ${NNG_PACKAGE_VERSION})
-set (CPACK_PACKAGE_CONTACT "nanomsg@freelists.org")
-set (CPACK_PACKAGE_VENDOR "nanomsg.org")
-set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "nanomsg next generation library")
-set (CPACK_SOURCE_GENERATOR "TBZ2;TGZ;ZIP")
-set (CPACK_SOURCE_IGNORE_FILES "/build/;/.git/;~$;${CPACK_SOURCE_IGNORE_FILES}")
-set (CPACK_SOURCE_PACKAGE_FILE_NAME
- "${PROJECT_NAME}-v${NNG_PACKAGE_VERSION}-src")
-set (CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt)
-set (CPACK_PACKAGE_INSTALL_DIRECTORY "nng")
-set (CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-v${NNG_PACKAGE_VERSION}")
+add_subdirectory(docs/man)
+
+set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
+set(CPACK_PACKAGE_VERSION ${NNG_PACKAGE_VERSION})
+set(CPACK_PACKAGE_CONTACT "nanomsg@freelists.org")
+set(CPACK_PACKAGE_VENDOR "nanomsg.org")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "nanomsg next generation library")
+set(CPACK_SOURCE_GENERATOR "TBZ2;TGZ;ZIP")
+set(CPACK_SOURCE_IGNORE_FILES "/build/;/.git/;~$;${CPACK_SOURCE_IGNORE_FILES}")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME
+ "${PROJECT_NAME}-v${NNG_PACKAGE_VERSION}-src")
+set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt)
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "nng")
+set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-v${NNG_PACKAGE_VERSION}")
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
-include (CPack)
+include(CPack)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cce1d478..e8d171c9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -24,9 +24,22 @@
# IN THE SOFTWARE.
#
+add_library (${PROJECT_NAME}
+ nng.c
+ ${PROJECT_SOURCE_DIR}/include/nng/nng.h)
+
+if (NNG_TESTS)
+ add_library(${PROJECT_NAME}_testlib STATIC
+ nng.c
+ ${PROJECT_SOURCE_DIR}/tests/testutil.c
+ ${PROJECT_SOURCE_DIR}/tests/testutil.h
+ ${PROJECT_SOURCE_DIR}/include/nng/nng.h)
+endif()
+
+
+#nng.c
+#${PROJECT_SOURCE_DIR}/include/nng/nng.h
set (NNG_SRCS
- nng.c
- ${PROJECT_SOURCE_DIR}/include/nng/nng.h
core/defs.h
@@ -202,7 +215,14 @@ foreach(_PKG IN ITEMS ${NNG_PKGS})
endforeach ()
# Library
-add_library (${PROJECT_NAME} ${NNG_SRCS})
+target_sources(${PROJECT_NAME} PRIVATE ${NNG_SRCS})
+
+if (NNG_TESTS)
+ target_sources(${PROJECT_NAME}_testlib PRIVATE ${NNG_SRCS})
+ target_link_libraries (${PROJECT_NAME}_testlib PUBLIC ${NNG_LIBS})
+ target_compile_definitions(${PROJECT_NAME}_testlib PUBLIC NNG_STATIC_LIB NNG_TEST_LIB)
+ target_include_directories (${PROJECT_NAME}_testlib PRIVATE ${PROJECT_SOURCE_DIR}/include)
+endif()
# When building shared libraries we prefer to suppress default symbol
# visibility, so that only the symbols that should be exposed in the
diff --git a/src/protocol/pair1/CMakeLists.txt b/src/protocol/pair1/CMakeLists.txt
index cbcb2bc2..3f92c585 100644
--- a/src/protocol/pair1/CMakeLists.txt
+++ b/src/protocol/pair1/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2018 Staysail Systems, Inc. <info@staystail.tech>
+# Copyright 2019 Staysail Systems, Inc. <info@staystail.tech>
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
#
# This software is supplied under the terms of the MIT License, a
@@ -12,10 +12,7 @@
option (NNG_PROTO_PAIR1 "Enable PAIRv1 protocol." ON)
mark_as_advanced(NNG_PROTO_PAIR1)
-if (NNG_PROTO_PAIR1)
- set(_DEFS -DNNG_HAVE_PAIR1)
- set(_SRCS protocol/pair1/pair.c ${PROJECT_SOURCE_DIR}/include/nng/protocol/pair1/pair.h)
-
- set(NNG_DEFS ${NNG_DEFS} ${_DEFS} PARENT_SCOPE)
- set(NNG_SRCS ${NNG_SRCS} ${_SRCS} PARENT_SCOPE)
-endif()
+nng_sources_if(NNG_PROTO_PAIR1 pair.c)
+nng_headers_if(NNG_PROTO_PAIR1 nng/protocol/pair1/pair.h)
+nng_defines_if(NNG_PROTO_PAIR1 NNG_HAVE_PAIR1)
+nng_test(pair1_test) \ No newline at end of file
diff --git a/src/protocol/pair1/pair.c b/src/protocol/pair1/pair.c
index 451122ea..7adb8bd8 100644
--- a/src/protocol/pair1/pair.c
+++ b/src/protocol/pair1/pair.c
@@ -12,7 +12,6 @@
#include <string.h>
#include "core/nng_impl.h"
-
#include "nng/protocol/pair1/pair.h"
// Pair protocol. The PAIRv1 protocol is a simple 1:1 messaging pattern,
diff --git a/src/protocol/pair1/pair1_test.c b/src/protocol/pair1/pair1_test.c
new file mode 100644
index 00000000..3a78bb18
--- /dev/null
+++ b/src/protocol/pair1/pair1_test.c
@@ -0,0 +1,607 @@
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include <string.h>
+
+#include <nng/nng.h>
+#include <nng/protocol/pair1/pair.h>
+
+#include <testutil.h>
+
+#include <acutest.h>
+
+#define SECOND 1000
+
+#define APPEND_STR(m, s) TEST_CHECK(nng_msg_append(m, s, strlen(s)) == 0)
+#define CHECK_STR(m, s) \
+ TEST_CHECK(nng_msg_len(m) == strlen(s)); \
+ TEST_CHECK(memcmp(nng_msg_body(m), s, strlen(s)) == 0)
+
+void
+test_mono_cooked(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ nng_msg * msg;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&c1) == 0);
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_append(msg, "ALPHA", strlen("ALPHA") + 1) == 0);
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ TEST_CHECK(nng_msg_len(msg) == strlen("ALPHA") + 1);
+ TEST_CHECK(strcmp(nng_msg_body(msg), "ALPHA") == 0);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_append(msg, "BETA", strlen("BETA") + 1) == 0);
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c1, &msg, 0) == 0);
+ TEST_CHECK(nng_msg_len(msg) == strlen("BETA") + 1);
+ TEST_CHECK(strcmp(nng_msg_body(msg), "BETA") == 0);
+
+ nng_msg_free(msg);
+ TEST_CHECK(nng_close(c1) == 0);
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_mono_faithful(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ nng_socket c2;
+ nng_msg * msg;
+ const char *addr = "inproc://pair1_mono_faithful";
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&c1) == 0);
+ TEST_CHECK(nng_pair1_open(&c2) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, SECOND / 4) == 0);
+ TEST_CHECK(nng_setopt_ms(c1, NNG_OPT_SENDTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(c2, NNG_OPT_SENDTIMEO, SECOND) == 0);
+
+ TEST_CHECK(nng_listen(s1, addr, NULL, 0) == 0);
+ TEST_CHECK(nng_dial(c1, addr, NULL, 0) == 0);
+ testutil_sleep(100);
+ TEST_CHECK(nng_dial(c2, addr, NULL, 0) == 0);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "ONE");
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ CHECK_STR(msg, "ONE");
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "TWO");
+ TEST_CHECK(nng_sendmsg(c2, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(c1) == 0);
+ TEST_CHECK(nng_close(c2) == 0);
+}
+
+void
+test_mono_back_pressure(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ int i;
+ int rv;
+ nng_msg * msg;
+ nng_duration to = 100;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&c1) == 0);
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_RECVBUF, 1) == 0);
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_SENDBUF, 1) == 0);
+ TEST_CHECK(nng_setopt_int(c1, NNG_OPT_RECVBUF, 1) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, to) == 0);
+
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+
+ // We choose to allow some buffering. In reality the
+ // buffer size is just 1, and we will fail after 2.
+ for (i = 0, rv = 0; i < 10; i++) {
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ if ((rv = nng_sendmsg(s1, msg, 0)) != 0) {
+ nng_msg_free(msg);
+ break;
+ }
+ }
+ TEST_CHECK(rv == NNG_ETIMEDOUT);
+ TEST_CHECK(i < 10);
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(c1) == 0);
+}
+
+void
+test_mono_raw_exchange(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+
+ nng_msg *msg;
+ uint32_t hops;
+
+ TEST_CHECK(nng_pair1_open_raw(&s1) == 0);
+ TEST_CHECK(nng_pair1_open_raw(&c1) == 0);
+
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(c1, NNG_OPT_RECVTIMEO, SECOND) == 0);
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+
+ nng_pipe p = NNG_PIPE_INITIALIZER;
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "GAMMA");
+ TEST_CHECK(nng_msg_header_append_u32(msg, 1) == 0);
+ TEST_CHECK(nng_msg_header_len(msg) == sizeof(uint32_t));
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ p = nng_msg_get_pipe(msg);
+ TEST_CHECK(nng_pipe_id(p) > 0);
+
+ CHECK_STR(msg, "GAMMA");
+ TEST_CHECK(nng_msg_header_len(msg) == sizeof(uint32_t));
+ TEST_CHECK(nng_msg_header_trim_u32(msg, &hops) == 0);
+ TEST_CHECK(hops == 2);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "EPSILON");
+ TEST_CHECK(nng_msg_header_append_u32(msg, 1) == 0);
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c1, &msg, 0) == 0);
+ CHECK_STR(msg, "EPSILON");
+ TEST_CHECK(nng_msg_header_len(msg) == sizeof(uint32_t));
+ TEST_CHECK(nng_msg_header_trim_u32(msg, &hops) == 0);
+ p = nng_msg_get_pipe(msg);
+ TEST_CHECK(nng_pipe_id(p) > 0);
+
+ TEST_CHECK(hops == 2);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(c1) == 0);
+}
+
+void
+test_mono_raw_header(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ nng_msg * msg;
+ uint32_t v;
+
+ TEST_CHECK(nng_pair1_open_raw(&s1) == 0);
+ TEST_CHECK(nng_pair1_open_raw(&c1) == 0);
+
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, SECOND / 5) == 0);
+ TEST_CHECK(nng_setopt_ms(c1, NNG_OPT_RECVTIMEO, SECOND / 5) == 0);
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+
+ // Missing bits in the header
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
+
+ // Valid header works
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_append_u32(msg, 0xFEEDFACE) == 0);
+ TEST_CHECK(nng_msg_header_append_u32(msg, 1) == 0);
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ TEST_CHECK(nng_msg_trim_u32(msg, &v) == 0);
+ TEST_CHECK(v == 0xFEEDFACE);
+ nng_msg_free(msg);
+
+ // Header with reserved bits set dropped
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_header_append_u32(msg, 0xDEAD0000) == 0);
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
+
+ // With the same bits clear it works
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_append_u32(msg, 0xFEEDFACE) == 0);
+ TEST_CHECK(nng_msg_header_append_u32(msg, 1) == 0);
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ TEST_CHECK(nng_msg_trim_u32(msg, &v) == 0);
+ TEST_CHECK(v == 0xFEEDFACE);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(c1) == 0);
+}
+
+void
+test_poly_best_effort(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ nng_msg * msg;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&c1) == 0);
+
+ TEST_CHECK(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == 0);
+
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_RECVBUF, 1) == 0);
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_SENDBUF, 1) == 0);
+ TEST_CHECK(nng_setopt_int(c1, NNG_OPT_RECVBUF, 1) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, SECOND) == 0);
+
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+
+ for (int i = 0; i < 10; i++) {
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ }
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(c1) == 0);
+}
+
+void
+test_poly_cooked(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ nng_socket c2;
+ nng_msg * msg;
+ bool v;
+ nng_pipe p1;
+ nng_pipe p2;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&c1) == 0);
+ TEST_CHECK(nng_pair1_open(&c2) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(c1, NNG_OPT_SENDTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(c2, NNG_OPT_SENDTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, SECOND / 10) == 0);
+ TEST_CHECK(nng_setopt_ms(c1, NNG_OPT_RECVTIMEO, SECOND / 10) == 0);
+ TEST_CHECK(nng_setopt_ms(c2, NNG_OPT_RECVTIMEO, SECOND / 10) == 0);
+
+ TEST_CHECK(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
+ TEST_CHECK(v == false);
+
+ TEST_CHECK(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == 0);
+ TEST_CHECK(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
+ TEST_CHECK(v == true);
+
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+ TEST_CHECK(testutil_marry(s1, c2) == 0);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "ONE");
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ CHECK_STR(msg, "ONE");
+ p1 = nng_msg_get_pipe(msg);
+ TEST_CHECK(nng_pipe_id(p1) > 0);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "TWO");
+ TEST_CHECK(nng_sendmsg(c2, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ CHECK_STR(msg, "TWO");
+ p2 = nng_msg_get_pipe(msg);
+ TEST_CHECK(nng_pipe_id(p2) > 0);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_pipe_id(p1) != nng_pipe_id(p2));
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+
+ nng_msg_set_pipe(msg, p1);
+ APPEND_STR(msg, "UNO");
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c1, &msg, 0) == 0);
+ CHECK_STR(msg, "UNO");
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ nng_msg_set_pipe(msg, p2);
+ APPEND_STR(msg, "DOS");
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c2, &msg, 0) == 0);
+ CHECK_STR(msg, "DOS");
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_close(c1) == 0);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ nng_msg_set_pipe(msg, p1);
+ APPEND_STR(msg, "EIN");
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c2, &msg, 0) == NNG_ETIMEDOUT);
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(c2) == 0);
+}
+
+void
+test_poly_late(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ bool v;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&c1) == 0);
+
+ TEST_CHECK(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
+ TEST_CHECK(v == false);
+
+ TEST_CHECK(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == 0);
+ TEST_CHECK(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
+ TEST_CHECK(v == true);
+
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+
+ TEST_CHECK(
+ nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == NNG_ESTATE);
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(c1) == 0);
+}
+
+void
+test_poly_default(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ nng_socket c2;
+ nng_msg * msg;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&c1) == 0);
+ TEST_CHECK(nng_pair1_open(&c2) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(c1, NNG_OPT_SENDTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(c2, NNG_OPT_SENDTIMEO, SECOND) == 0);
+
+ TEST_CHECK(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == 0);
+
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+ TEST_CHECK(testutil_marry(s1, c2) == 0);
+
+ // This assumes poly picks the first suitor. Applications
+ // should not make the same assumption.
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "YES");
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c1, &msg, 0) == 0);
+ CHECK_STR(msg, "YES");
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_close(c1) == 0);
+ testutil_sleep(10);
+
+ // Verify that the other pipe is chosen as the next suitor.
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "AGAIN");
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c2, &msg, 0) == 0);
+ CHECK_STR(msg, "AGAIN");
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(c2) == 0);
+}
+
+void
+test_poly_raw(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ nng_socket c2;
+ nng_msg * msg;
+ bool v;
+ uint32_t hops;
+ nng_pipe p1;
+ nng_pipe p2;
+
+ TEST_CHECK(nng_pair1_open_raw(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&c1) == 0);
+ TEST_CHECK(nng_pair1_open(&c2) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, SECOND / 5) == 0);
+ TEST_CHECK(nng_setopt_ms(c1, NNG_OPT_RECVTIMEO, SECOND / 5) == 0);
+ TEST_CHECK(nng_setopt_ms(c2, NNG_OPT_RECVTIMEO, SECOND / 5) == 0);
+
+ TEST_CHECK(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
+ TEST_CHECK(v == 0);
+
+ TEST_CHECK(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == 0);
+ TEST_CHECK(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
+ TEST_CHECK(v == true);
+
+ v = false;
+ TEST_CHECK(nng_getopt_bool(s1, NNG_OPT_RAW, &v) == 0);
+ TEST_CHECK(v == true);
+
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+ TEST_CHECK(testutil_marry(s1, c2) == 0);
+
+ // send/recv works
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "ONE");
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ CHECK_STR(msg, "ONE");
+ p1 = nng_msg_get_pipe(msg);
+ TEST_CHECK(nng_pipe_id(p1) > 0);
+ TEST_CHECK(nng_msg_header_trim_u32(msg, &hops) == 0);
+ TEST_CHECK(hops == 1);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "TWO");
+ TEST_CHECK(nng_sendmsg(c2, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ CHECK_STR(msg, "TWO");
+ p2 = nng_msg_get_pipe(msg);
+ TEST_CHECK(nng_pipe_id(p2) > 0);
+ TEST_CHECK(nng_msg_header_trim_u32(msg, &hops) == 0);
+ TEST_CHECK(hops == 1);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_pipe_id(p1) != nng_pipe_id(p2));
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ nng_msg_set_pipe(msg, p1);
+ APPEND_STR(msg, "UNO");
+ TEST_CHECK(nng_msg_header_append_u32(msg, 1) == 0);
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c1, &msg, 0) == 0);
+ CHECK_STR(msg, "UNO");
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ nng_msg_set_pipe(msg, p2);
+ APPEND_STR(msg, "DOS");
+ TEST_CHECK(nng_msg_header_append_u32(msg, 1) == 0);
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c2, &msg, 0) == 0);
+ CHECK_STR(msg, "DOS");
+ nng_msg_free(msg);
+
+ // Verify closing the pipe stops any of its traffic
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ APPEND_STR(msg, "ONE");
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ CHECK_STR(msg, "ONE");
+ p1 = nng_msg_get_pipe(msg);
+ TEST_CHECK(nng_pipe_id(p1) > 0);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_close(c1) == 0);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ nng_msg_set_pipe(msg, p1);
+ APPEND_STR(msg, "EIN");
+ TEST_CHECK(nng_msg_header_append_u32(msg, 1) == 0);
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(c2, &msg, 0) == NNG_ETIMEDOUT);
+}
+
+void
+test_raw(void)
+{
+ nng_socket s1;
+ bool raw;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_getopt_bool(s1, NNG_OPT_RAW, &raw) == 0);
+ TEST_CHECK(raw == false);
+ TEST_CHECK(nng_setopt_bool(s1, NNG_OPT_RAW, true) == NNG_EREADONLY);
+ TEST_CHECK(nng_close(s1) == 0);
+
+ TEST_CHECK(nng_pair1_open_raw(&s1) == 0);
+ TEST_CHECK(nng_getopt_bool(s1, NNG_OPT_RAW, &raw) == 0);
+ TEST_CHECK(raw == true);
+ TEST_CHECK(nng_setopt_bool(s1, NNG_OPT_RAW, false) == NNG_EREADONLY);
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_ttl(void)
+{
+ nng_socket s1;
+ nng_socket c1;
+ nng_msg * msg;
+ uint32_t val;
+ int ttl;
+
+ TEST_CHECK(nng_pair1_open_raw(&s1) == 0);
+ TEST_CHECK(nng_pair1_open_raw(&c1) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, SECOND / 5) == 0);
+ TEST_CHECK(nng_setopt_ms(c1, NNG_OPT_RECVTIMEO, SECOND / 5) == 0);
+
+ // cannot set insane TTLs
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_MAXTTL, 0) == NNG_EINVAL);
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_MAXTTL, 1000) == NNG_EINVAL);
+ ttl = 8;
+ TEST_CHECK(nng_setopt(s1, NNG_OPT_MAXTTL, &ttl, 1) == NNG_EINVAL);
+ TEST_CHECK(nng_setopt_bool(s1, NNG_OPT_MAXTTL, true) == NNG_EBADTYPE);
+
+ TEST_CHECK(testutil_marry(s1, c1) == 0);
+
+ // Let's check enforcement of TTL
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_MAXTTL, 4) == 0);
+ TEST_CHECK(nng_getopt_int(s1, NNG_OPT_MAXTTL, &ttl) == 0);
+ TEST_CHECK(ttl == 4);
+
+ // Bad TTL bounces
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_header_append_u32(msg, 4) == 0);
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
+
+ // Good TTL passes
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_append_u32(msg, 0xFEEDFACE) == 0);
+ TEST_CHECK(nng_msg_header_append_u32(msg, 3) == 0);
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ TEST_CHECK(nng_msg_trim_u32(msg, &val) == 0);
+ TEST_CHECK(val == 0xFEEDFACE);
+ TEST_CHECK(nng_msg_header_trim_u32(msg, &val) == 0);
+ TEST_CHECK(val == 4);
+ nng_msg_free(msg);
+
+ // Large TTL passes
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_MAXTTL, 0xff) == 0);
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_append_u32(msg, 1234) == 0);
+ TEST_CHECK(nng_msg_header_append_u32(msg, 0xfe) == 0);
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == 0);
+ TEST_CHECK(nng_msg_trim_u32(msg, &val) == 0);
+ TEST_CHECK(val == 1234);
+ TEST_CHECK(nng_msg_header_trim_u32(msg, &val) == 0);
+ TEST_CHECK(val == 0xff);
+ nng_msg_free(msg);
+
+ // Max TTL fails
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_MAXTTL, 0xff) == 0);
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_header_append_u32(msg, 0xff) == 0);
+ TEST_CHECK(nng_sendmsg(c1, msg, 0) == 0);
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(c1) == 0);
+}
+
+TEST_LIST = {
+ { "pair1 monogamous cooked", test_mono_cooked },
+ { "pair1 monogamous faithful", test_mono_faithful },
+ { "pair1 monogamous back pressure", test_mono_back_pressure },
+ { "pair1 monogamous raw exchange", test_mono_raw_exchange },
+ { "pair1 monogamous raw header", test_mono_raw_header },
+ { "pair1 polyamorous best effort", test_poly_best_effort },
+ { "pair1 polyamorous cooked", test_poly_cooked },
+ { "pair1 polyamorous late", test_poly_late },
+ { "pair1 polyamorous default", test_poly_default },
+ { "pair1 polyamorous raw", test_poly_raw },
+ { "pair1 raw", test_raw },
+ { "pair1 ttl", test_ttl },
+
+ { NULL, NULL },
+};
diff --git a/src/protocol/reqrep0/CMakeLists.txt b/src/protocol/reqrep0/CMakeLists.txt
index bae31433..4778f4ea 100644
--- a/src/protocol/reqrep0/CMakeLists.txt
+++ b/src/protocol/reqrep0/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
#
# This software is supplied under the terms of the MIT License, a
@@ -9,30 +9,18 @@
#
# Req/Rep protocol
-option (NNG_PROTO_REQ0 "Enable REQv0 protocol." ON)
+option(NNG_PROTO_REQ0 "Enable REQv0 protocol." ON)
mark_as_advanced(NNG_PROTO_REQ0)
-option (NNG_PROTO_REP0 "Enable REPv0 protocol." ON)
+option(NNG_PROTO_REP0 "Enable REPv0 protocol." ON)
mark_as_advanced(NNG_PROTO_REP0)
-set(_DEFS)
-set(_SRCS)
+nng_sources_if(NNG_PROTO_REQ0 req.c xreq.c)
+nng_headers_if(NNG_PROTO_REQ0 nng/protocol/reqrep0/req.h)
+nng_defines_if(NNG_PROTO_REQ0 NNG_HAVE_REQ0)
-if (NNG_PROTO_REQ0)
- list(APPEND _DEFS -DNNG_HAVE_REQ0)
- list(APPEND _SRCS
- protocol/reqrep0/req.c protocol/reqrep0/xreq.c
- ${PROJECT_SOURCE_DIR}/include/nng/protocol/reqrep0/req.h)
-
-endif()
+nng_sources_if(NNG_PROTO_REP0 rep.c xrep.c)
+nng_headers_if(NNG_PROTO_REP0 nng/protocol/reqrep0/rep.h)
+nng_defines_if(NNG_PROTO_REP0 NNG_HAVE_REP0)
-if (NNG_PROTO_REP0)
- list(APPEND _DEFS -DNNG_HAVE_REP0)
- list(APPEND _SRCS
- protocol/reqrep0/rep.c protocol/reqrep0/xrep.c
- ${PROJECT_SOURCE_DIR}/include/nng/protocol/reqrep0/rep.h)
-
-endif()
-
-set(NNG_DEFS ${NNG_DEFS} ${_DEFS} PARENT_SCOPE)
-set(NNG_SRCS ${NNG_SRCS} ${_SRCS} PARENT_SCOPE)
+nng_test(reqrep_test)
diff --git a/src/protocol/reqrep0/reqrep_test.c b/src/protocol/reqrep0/reqrep_test.c
new file mode 100644
index 00000000..564cf158
--- /dev/null
+++ b/src/protocol/reqrep0/reqrep_test.c
@@ -0,0 +1,300 @@
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include <string.h>
+
+#include <nng/nng.h>
+#include <nng/protocol/reqrep0/rep.h>
+#include <nng/protocol/reqrep0/req.h>
+
+#include <acutest.h>
+#include <testutil.h>
+
+#ifndef NNI_PROTO
+#define NNI_PROTO(x, y) (((x) << 4u) | (y))
+#endif
+
+void
+test_req_rep_identity(void)
+{
+ nng_socket s;
+ int p;
+ char * n;
+
+ TEST_CHECK(nng_req0_open(&s) == 0);
+ TEST_CHECK(nng_getopt_int(s, NNG_OPT_PROTO, &p) == 0);
+ TEST_CHECK(p == NNI_PROTO(3u, 0u)); // 48
+ TEST_CHECK(nng_getopt_int(s, NNG_OPT_PEER, &p) == 0);
+ TEST_CHECK(p == NNI_PROTO(3u, 1u)); // 49
+ TEST_CHECK(nng_getopt_string(s, NNG_OPT_PROTONAME, &n) == 0);
+ TEST_CHECK(strcmp(n, "req") == 0);
+ TEST_CHECK(nng_getopt_string(s, NNG_OPT_PEERNAME, &n) == 0);
+ TEST_CHECK(strcmp(n, "rep") == 0);
+ TEST_CHECK(nng_close(s) == 0);
+
+ TEST_CHECK(nng_rep0_open(&s) == 0);
+ TEST_CHECK(nng_getopt_int(s, NNG_OPT_PROTO, &p) == 0);
+ TEST_CHECK(p == NNI_PROTO(3u, 1u)); // 49
+ TEST_CHECK(nng_getopt_int(s, NNG_OPT_PEER, &p) == 0);
+ TEST_CHECK(p == NNI_PROTO(3u, 0u)); // 48
+ TEST_CHECK(nng_getopt_string(s, NNG_OPT_PROTONAME, &n) == 0);
+ TEST_CHECK(strcmp(n, "rep") == 0);
+ TEST_CHECK(nng_getopt_string(s, NNG_OPT_PEERNAME, &n) == 0);
+ TEST_CHECK(strcmp(n, "req") == 0);
+ TEST_CHECK(nng_close(s) == 0);
+}
+
+void
+test_resend_option(void)
+{
+ nng_socket req;
+ bool b;
+ size_t sz = sizeof(b);
+ const char *opt = NNG_OPT_REQ_RESENDTIME;
+
+ TEST_CHECK(nng_req0_open(&req) == 0);
+
+ TEST_CHECK(nng_setopt_ms(req, opt, 10) == 0);
+ TEST_CHECK(nng_setopt(req, opt, "", 1) == NNG_EINVAL);
+ TEST_CHECK(nng_getopt(req, opt, &b, &sz) == NNG_EINVAL);
+ TEST_CHECK(nng_setopt_bool(req, opt, true) == NNG_EBADTYPE);
+ TEST_CHECK(nng_getopt_bool(req, opt, &b) == NNG_EBADTYPE);
+
+ TEST_CHECK(nng_close(req) == 0);
+}
+
+void
+test_req_recv_bad_state(void)
+{
+ nng_socket req;
+ nng_msg * msg = NULL;
+
+ TEST_CHECK(nng_req0_open(&req) == 0);
+ TEST_CHECK(nng_recvmsg(req, &msg, 0) == NNG_ESTATE);
+ TEST_CHECK(msg == NULL);
+ TEST_CHECK(nng_close(req) == 0);
+}
+
+void
+test_rep_send_bad_state(void)
+{
+ nng_socket rep;
+ nng_msg * msg = NULL;
+
+ TEST_CHECK(nng_rep0_open(&rep) == 0);
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_sendmsg(rep, msg, 0) == NNG_ESTATE);
+ nng_msg_free(msg);
+ TEST_CHECK(nng_close(rep) == 0);
+}
+
+#define SECOND 1000
+
+void
+test_req_rep_exchange(void)
+{
+ nng_socket req;
+ nng_socket rep;
+ nng_msg * msg = NULL;
+
+ TEST_CHECK(nng_req0_open(&req) == 0);
+ TEST_CHECK(nng_rep0_open(&rep) == 0);
+
+ TEST_CHECK(nng_setopt_ms(req, NNG_OPT_RECVTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(rep, NNG_OPT_RECVTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(req, NNG_OPT_SENDTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(rep, NNG_OPT_SENDTIMEO, SECOND) == 0);
+
+ TEST_CHECK(testutil_marry(rep, req) == 0);
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_msg_append(msg, "ping", 5) == 0);
+ TEST_CHECK(nng_msg_len(msg) == 5);
+ TEST_CHECK(strcmp(nng_msg_body(msg), "ping") == 0);
+ TEST_CHECK(nng_sendmsg(req, msg, 0) == 0);
+ msg = NULL;
+ TEST_CHECK(nng_recvmsg(rep, &msg, 0) == 0);
+ TEST_CHECK(msg != NULL);
+ TEST_CHECK(nng_msg_len(msg) == 5);
+ TEST_CHECK(strcmp(nng_msg_body(msg), "ping") == 0);
+ nng_msg_trim(msg, 5);
+ TEST_CHECK(nng_msg_append(msg, "pong", 5) == 0);
+ TEST_CHECK(nng_sendmsg(rep, msg, 0) == 0);
+ msg = NULL;
+ TEST_CHECK(nng_recvmsg(req, &msg, 0) == 0);
+ TEST_CHECK(msg != NULL);
+ TEST_CHECK(nng_msg_len(msg) == 5);
+ TEST_CHECK(strcmp(nng_msg_body(msg), "pong") == 0);
+ nng_msg_free(msg);
+
+ TEST_CHECK(nng_close(req) == 0);
+ TEST_CHECK(nng_close(rep) == 0);
+}
+
+void
+test_req_cancel(void)
+{
+ nng_msg * abc;
+ nng_msg * def;
+ nng_msg * cmd;
+ nng_duration retry = SECOND;
+ nng_socket req;
+ nng_socket rep;
+
+ TEST_CHECK(nng_rep_open(&rep) == 0);
+ TEST_CHECK(nng_req_open(&req) == 0);
+
+ TEST_CHECK(nng_setopt_ms(req, NNG_OPT_RECVTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(rep, NNG_OPT_RECVTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(req, NNG_OPT_SENDTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(rep, NNG_OPT_SENDTIMEO, SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(req, NNG_OPT_REQ_RESENDTIME, retry) == 0);
+ TEST_CHECK(nng_setopt_int(req, NNG_OPT_SENDBUF, 16) == 0);
+
+ TEST_CHECK(nng_msg_alloc(&abc, 0) == 0);
+ TEST_CHECK(nng_msg_append(abc, "abc", 4) == 0);
+ TEST_CHECK(nng_msg_alloc(&def, 0) == 0);
+ TEST_CHECK(nng_msg_append(def, "def", 4) == 0);
+
+ TEST_CHECK(testutil_marry(rep, req) == 0);
+
+ // Send req #1 (abc).
+ TEST_CHECK(nng_sendmsg(req, abc, 0) == 0);
+
+ // Sleep a bit. This is so that we ensure that our request gets
+ // to the far side. (If we cancel too fast, then our outgoing send
+ // will be canceled before it gets to the peer.)
+ testutil_sleep(100);
+
+ // Send the next next request ("def"). Note that
+ // the REP side server will have already buffered the receive
+ // request, and should simply be waiting for us to reply to abc.
+ TEST_CHECK(nng_sendmsg(req, def, 0) == 0);
+
+ // Receive the first request (should be abc) on the REP server.
+ TEST_CHECK(nng_recvmsg(rep, &cmd, 0) == 0);
+ TEST_ASSERT(cmd != NULL);
+ TEST_CHECK(nng_msg_len(cmd) == 4);
+ TEST_CHECK(strcmp(nng_msg_body(cmd), "abc") == 0);
+
+ // REP sends the reply to first command. This will be discarded
+ // by the REQ socket.
+ TEST_CHECK(nng_sendmsg(rep, cmd, 0) == 0);
+
+ // Now get the next command from the REP; should be "def".
+ TEST_CHECK(nng_recvmsg(rep, &cmd, 0) == 0);
+ TEST_ASSERT(cmd != NULL);
+ TEST_CHECK(nng_msg_len(cmd) == 4);
+ TEST_CHECK(strcmp(nng_msg_body(cmd), "def") == 0);
+ TEST_MSG("Received body was %s", nng_msg_body(cmd));
+
+ // And send it back to REQ.
+ TEST_CHECK(nng_sendmsg(rep, cmd, 0) == 0);
+
+ // Try a req command. This should give back "def"
+ TEST_CHECK(nng_recvmsg(req, &cmd, 0) == 0);
+ TEST_CHECK(nng_msg_len(cmd) == 4);
+ TEST_CHECK(strcmp(nng_msg_body(cmd), "def") == 0);
+ nng_msg_free(cmd);
+
+ TEST_CHECK(nng_close(req) == 0);
+ TEST_CHECK(nng_close(rep) == 0);
+}
+
+void
+test_req_cancel_abort_recv(void)
+{
+
+ nng_msg * abc;
+ nng_msg * def;
+ nng_msg * cmd;
+ nng_aio * aio;
+ nng_duration retry = SECOND * 10; // 10s (kind of never)
+ nng_socket req;
+ nng_socket rep;
+
+ TEST_CHECK(nng_rep_open(&rep) == 0);
+ TEST_CHECK(nng_req_open(&req) == 0);
+ TEST_CHECK(nng_aio_alloc(&aio, NULL, NULL) == 0);
+
+ TEST_CHECK(nng_setopt_ms(req, NNG_OPT_REQ_RESENDTIME, retry) == 0);
+ TEST_CHECK(nng_setopt_int(req, NNG_OPT_SENDBUF, 16) == 0);
+ TEST_CHECK(nng_setopt_ms(req, NNG_OPT_RECVTIMEO, 5 * SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(rep, NNG_OPT_RECVTIMEO, 5 * SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(req, NNG_OPT_SENDTIMEO, 5 * SECOND) == 0);
+ TEST_CHECK(nng_setopt_ms(rep, NNG_OPT_SENDTIMEO, 5 * SECOND) == 0);
+
+ TEST_CHECK(nng_msg_alloc(&abc, 0) == 0);
+ TEST_CHECK(nng_msg_append(abc, "abc", 4) == 0);
+ TEST_CHECK(nng_msg_alloc(&def, 0) == 0);
+ TEST_CHECK(nng_msg_append(def, "def", 4) == 0);
+
+ TEST_CHECK(testutil_marry(rep, req) == 0);
+
+ // Send req #1 (abc).
+ TEST_CHECK(nng_sendmsg(req, abc, 0) == 0);
+
+ // Wait for it to get ot the other side.
+ testutil_sleep(100);
+
+ nng_aio_set_timeout(aio, 5 * SECOND);
+ nng_recv_aio(req, aio);
+
+ // Give time for this recv to post properly.
+ testutil_sleep(100);
+
+ // Send the next next request ("def"). Note that
+ // the REP side server will have already buffered the receive
+ // request, and should simply be waiting for us to reply to
+ // abc.
+ TEST_CHECK(nng_sendmsg(req, def, 0) == 0);
+
+ // Our pending I/O should have been canceled.
+ nng_aio_wait(aio);
+ TEST_CHECK(nng_aio_result(aio) == NNG_ECANCELED);
+
+ // Receive the first request (should be abc) on the REP server.
+ TEST_CHECK(nng_recvmsg(rep, &cmd, 0) == 0);
+ TEST_CHECK(nng_msg_len(cmd) == 4);
+ TEST_CHECK(strcmp(nng_msg_body(cmd), "abc") == 0);
+
+ // REP sends the reply to first command. This will be
+ // discarded by the REQ socket.
+ TEST_CHECK(nng_sendmsg(rep, cmd, 0) == 0);
+
+ // Now get the next command from the REP; should be "def".
+ TEST_CHECK(nng_recvmsg(rep, &cmd, 0) == 0);
+ TEST_CHECK(nng_msg_len(cmd) == 4);
+ TEST_CHECK(strcmp(nng_msg_body(cmd), "def") == 0);
+
+ // And send it back to REQ.
+ TEST_CHECK(nng_sendmsg(rep, cmd, 0) == 0);
+
+ // Try a req command. This should give back "def"
+ TEST_CHECK(nng_recvmsg(req, &cmd, 0) == 0);
+ TEST_CHECK(nng_msg_len(cmd) == 4);
+ TEST_CHECK(strcmp(nng_msg_body(cmd), "def") == 0);
+ nng_msg_free(cmd);
+
+ nng_aio_free(aio);
+ TEST_CHECK(nng_close(req) == 0);
+ TEST_CHECK(nng_close(rep) == 0);
+}
+
+TEST_LIST = {
+ { "req rep identity", test_req_rep_identity },
+ { "resend option", test_resend_option },
+ { "req recv bad state", test_req_recv_bad_state },
+ { "rep send bad state", test_rep_send_bad_state },
+ { "req rep exchange", test_req_rep_exchange },
+ { "req cancel", test_req_cancel },
+ { "req cancel abort recv", test_req_cancel_abort_recv },
+ { NULL, NULL },
+};
diff --git a/src/supplemental/base64/CMakeLists.txt b/src/supplemental/base64/CMakeLists.txt
index 83740c83..b4c92e6a 100644
--- a/src/supplemental/base64/CMakeLists.txt
+++ b/src/supplemental/base64/CMakeLists.txt
@@ -12,5 +12,6 @@ if (NNG_SUPP_BASE64)
set(_SRCS
supplemental/base64/base64.c
supplemental/base64/base64.h)
+ nng_test(base64_test)
set(NNG_SRCS ${NNG_SRCS} ${_SRCS} PARENT_SCOPE)
endif()
diff --git a/src/supplemental/base64/base64_test.c b/src/supplemental/base64/base64_test.c
new file mode 100644
index 00000000..2c79a243
--- /dev/null
+++ b/src/supplemental/base64/base64_test.c
@@ -0,0 +1,106 @@
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include <string.h>
+
+#include <nng/nng.h>
+
+#include "base64.h"
+
+#include <acutest.h>
+
+typedef struct {
+ char *decoded;
+ char *encoded;
+} test_case;
+
+static test_case cases[] = {
+ { "", "" },
+ { "f", "Zg==" },
+ { "fo", "Zm8=" },
+ { "foo", "Zm9v" },
+ { "foob", "Zm9vYg==" },
+ { "fooba", "Zm9vYmE=" },
+ { "foobar", "Zm9vYmFy" },
+ { NULL, NULL },
+};
+
+void
+test_encode(void)
+{
+ int i;
+ void *dec;
+
+ for (i = 0; (dec = cases[i].decoded) != NULL; i++) {
+ char buf[1024];
+ char name[8];
+ int rv;
+
+ (void) snprintf(name, sizeof(name), "%d", i);
+ TEST_CASE(name);
+ rv = nni_base64_encode(dec, strlen(dec), buf, 1024);
+ TEST_CHECK(rv >= 0);
+ TEST_CHECK(rv == (int) strlen(cases[i].encoded));
+ buf[rv] = 0;
+ TEST_CHECK(strcmp(buf, cases[i].encoded) == 0);
+ }
+}
+
+void
+test_decode(void)
+{
+ int i;
+ void *enc;
+
+ for (i = 0; (enc = cases[i].encoded) != NULL; i++) {
+ char buf[1024];
+ char name[8];
+ int rv;
+
+ (void) snprintf(name, sizeof(name), "%d", i);
+ TEST_CASE(name);
+
+ rv = nni_base64_decode(enc, strlen(enc), (void *) buf, 1024);
+ TEST_CHECK(rv >= 0);
+ TEST_CHECK(rv == (int) strlen(cases[i].decoded));
+ buf[rv] = 0;
+ TEST_CHECK(strcmp(buf, cases[i].decoded) == 0);
+ }
+}
+
+void
+test_overflow(void)
+{
+ char tmp[1024];
+ for (int i = 1; cases[i].decoded != NULL; i++) {
+ void *enc = cases[i].encoded;
+ void *dec = cases[i].decoded;
+ void *buf = tmp;
+
+ char name[8];
+ (void) snprintf(name, sizeof(name), "%d", i);
+ TEST_CASE(name);
+
+ TEST_CHECK(nni_base64_encode(
+ dec, strlen(dec), buf, strlen(enc) - 1) == -1);
+ TEST_CHECK(nni_base64_encode(dec, strlen(dec), buf, 0) == -1);
+
+ TEST_CHECK(nni_base64_decode(
+ enc, strlen(enc), buf, strlen(dec) - 1) == -1);
+ TEST_CHECK(nni_base64_encode(enc, strlen(enc), buf, 0) == -1);
+ }
+}
+
+TEST_LIST = {
+ { "encode", test_encode },
+ { "decode", test_decode },
+ { "overflow", test_overflow },
+ { NULL, NULL },
+};
diff --git a/src/supplemental/sha1/CMakeLists.txt b/src/supplemental/sha1/CMakeLists.txt
index 370dc7c2..de301b08 100644
--- a/src/supplemental/sha1/CMakeLists.txt
+++ b/src/supplemental/sha1/CMakeLists.txt
@@ -1,6 +1,6 @@
#
+# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2017 Capitar IT Group BV <info@capitar.com>
-# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
@@ -8,9 +8,5 @@
# found online at https://opensource.org/licenses/MIT.
#
-if (NNG_SUPP_SHA1)
- set(_SRCS
- supplemental/sha1/sha1.c
- supplemental/sha1/sha1.h)
- set(NNG_SRCS ${NNG_SRCS} ${_SRCS} PARENT_SCOPE)
-endif()
+nng_sources_if(NNG_SUPP_SHA1 sha1.c sha1.h)
+nng_test(sha1_test)
diff --git a/tests/sha1.c b/src/supplemental/sha1/sha1_test.c
index 6877e89e..505175b0 100644
--- a/tests/sha1.c
+++ b/src/supplemental/sha1/sha1_test.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -13,8 +13,10 @@
#include <nng/nng.h>
-#include "convey.h"
-#include "supplemental/sha1/sha1.h"
+#include <acutest.h>
+
+#include "sha1.h"
+
// The following test vectors are from RFC 3174.
#define TEST1 "abc"
@@ -36,26 +38,35 @@ char *resultarray[4] = {
"DE A3 56 A2 CD DD 90 C7 A7 EC ED C5 EB B5 63 93 4F 46 04 52"
};
-TestMain("SHA1 Verification", {
- Convey("SHA1 Works", {
- for (int i = 0; i < 4; i++) {
- nni_sha1_ctx ctx;
- size_t slen = strlen(testarray[i]);
- uint8_t digest[20];
- char strout[20 * 3 + 1];
- memset(digest, 0, sizeof(digest));
- nni_sha1_init(&ctx);
- for (int j = 0; j < repeatcount[i]; j++) {
- nni_sha1_update(
- &ctx, (uint8_t *) testarray[i], slen);
- }
- nni_sha1_final(&ctx, digest);
- for (int j = 0; j < 20; j++) {
- snprintf(
- strout + j * 3, 4, "%02X ", digest[j]);
- }
- strout[20 * 3 - 1] = '\0';
- So(strcmp(strout, resultarray[i]) == 0);
+void
+test_sha1(void)
+{
+
+ for (int i = 0; i < 4; i++) {
+ nni_sha1_ctx ctx;
+ size_t slen = strlen(testarray[i]);
+ uint8_t digest[20];
+ char strout[20 * 3 + 1];
+ char name[8];
+
+ snprintf(name, sizeof(name), "%d", i);
+ TEST_CASE(name);
+
+ memset(digest, 0, sizeof(digest));
+ nni_sha1_init(&ctx);
+ for (int j = 0; j < repeatcount[i]; j++) {
+ nni_sha1_update(&ctx, (uint8_t *) testarray[i], slen);
+ }
+ nni_sha1_final(&ctx, digest);
+ for (int j = 0; j < 20; j++) {
+ snprintf(strout + j * 3, 4, "%02X ", digest[j]);
}
- });
-})
+ strout[20 * 3 - 1] = '\0';
+ TEST_CHECK(strcmp(strout, resultarray[i]) == 0);
+ }
+}
+
+TEST_LIST = {
+ { "sha1", test_sha1 },
+ { NULL, NULL },
+};
diff --git a/src/transport/inproc/CMakeLists.txt b/src/transport/inproc/CMakeLists.txt
index bab4cd7e..3249649e 100644
--- a/src/transport/inproc/CMakeLists.txt
+++ b/src/transport/inproc/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
#
# This software is supplied under the terms of the MIT License, a
@@ -12,10 +12,6 @@
option (NNG_TRANSPORT_INPROC "Enable inproc transport." ON)
mark_as_advanced(NNG_TRANSPORT_INPROC)
-if (NNG_TRANSPORT_INPROC)
- set(_SRCS transport/inproc/inproc.c ${PROJECT_SOURCE_DIR}/include/nng/transport/inproc/inproc.h)
- set(_DEFS -DNNG_TRANSPORT_INPROC)
-
- set(NNG_SRCS ${NNG_SRCS} ${_SRCS} PARENT_SCOPE)
- set(NNG_DEFS ${NNG_DEFS} ${_DEFS} PARENT_SCOPE)
-endif()
+nng_sources_if(NNG_TRANSPORT_INPROC inproc.c)
+nng_headers_if(NNG_TRANSPORT_INPROC nng/transport/inproc/inproc.h)
+nng_defines_if(NNG_TRANSPORT_INPROC NNG_TRANSPORT_INPROC)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 60bfed2e..984859bd 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
# Copyright (c) 2012 Martin Sustrik All rights reserved.
# Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
@@ -40,107 +40,109 @@ include_directories(AFTER SYSTEM ${PROJECT_SOURCE_DIR}/src)
if (NOT WIN32)
find_package(Threads)
set(THRLIB Threads::Threads)
-endif()
+endif ()
if (NNG_TESTS)
nng_check_sym(nl_langinfo langinfo.h NNG_HAVE_LANGINFO)
if (NOT NNG_SANITIZER STREQUAL "none")
set(TIMEOUT_FACTOR 2)
- else()
- set (TIMEOUT_FACTOR 1)
- endif()
- set (NNG_TEST_PORT 13000)
- macro (add_nng_test NAME TIMEOUT)
- add_executable (${NAME} ${NAME}.c convey.c)
- target_link_libraries (${NAME} ${PROJECT_NAME} ${THRLIB})
- add_test (NAME ${NAME} COMMAND ${NAME} -v -p TEST_PORT=${NNG_TEST_PORT})
- math (EXPR TIMEOUT ${TIMEOUT}*${TIMEOUT_FACTOR})
- set_tests_properties (${NAME} PROPERTIES TIMEOUT ${TIMEOUT})
- math (EXPR NNG_TEST_PORT "${NNG_TEST_PORT}+20")
- endmacro (add_nng_test)
+ else ()
+ set(TIMEOUT_FACTOR 1)
+ endif ()
+ set(NNG_TEST_PORT 13000)
+ macro(add_nng_test NAME TIMEOUT)
+ add_executable(${NAME} ${NAME}.c convey.c)
+ target_link_libraries(${NAME} ${PROJECT_NAME} ${THRLIB})
+ add_test(NAME ${NAME} COMMAND ${NAME} -v -p TEST_PORT=${NNG_TEST_PORT})
+ math(EXPR TIMEOUT ${TIMEOUT}*${TIMEOUT_FACTOR})
+ set_tests_properties(${NAME} PROPERTIES TIMEOUT ${TIMEOUT})
+ math(EXPR NNG_TEST_PORT "${NNG_TEST_PORT}+20")
+ endmacro(add_nng_test)
# Compatibility tests are only added if all of the legacy protocols
# are present. It's not worth trying to figure out which of these
# should work and which shouldn't.
if (NNG_PROTO_BUS0 AND
- NNG_PROTO_PAIR0 AND
- NNG_PROTO_REQ0 AND
- NNG_PROTO_REP0 AND
- NNG_PROTO_PUB0 AND
- NNG_PROTO_SUB0 AND
- NNG_PROTO_PUSH0 AND
- NNG_PROTO_PULL0)
-
- macro (add_nng_compat_test NAME TIMEOUT)
- add_executable (${NAME} ${NAME}.c compat_testutil.c)
- target_link_libraries (${NAME} ${PROJECT_NAME})
+ NNG_PROTO_PAIR0 AND
+ NNG_PROTO_REQ0 AND
+ NNG_PROTO_REP0 AND
+ NNG_PROTO_PUB0 AND
+ NNG_PROTO_SUB0 AND
+ NNG_PROTO_PUSH0 AND
+ NNG_PROTO_PULL0)
+
+ macro(add_nng_compat_test NAME TIMEOUT)
+ add_executable(${NAME} ${NAME}.c compat_testutil.c)
+ target_link_libraries(${NAME} ${PROJECT_NAME})
target_include_directories(${NAME} PUBLIC
- ${PROJECT_SOURCE_DIR}/src/compat)
+ ${PROJECT_SOURCE_DIR}/src/compat)
- add_test (NAME ${NAME} COMMAND ${NAME} ${NNG_TEST_PORT})
- set_tests_properties (${NAME} PROPERTIES TIMEOUT ${TIMEOUT})
- math (EXPR NNG_TEST_PORT "${NNG_TEST_PORT}+20")
- endmacro (add_nng_compat_test)
+ add_test(NAME ${NAME} COMMAND ${NAME} ${NNG_TEST_PORT})
+ set_tests_properties(${NAME} PROPERTIES TIMEOUT ${TIMEOUT})
+ math(EXPR NNG_TEST_PORT "${NNG_TEST_PORT}+20")
+ endmacro(add_nng_compat_test)
else ()
- macro (add_nng_compat_test NAME TIMEOUT)
- endmacro (add_nng_compat_test)
- message (STATUS "Compatibility tests disabled (unconfigured protocols)")
+ macro(add_nng_compat_test NAME TIMEOUT)
+ endmacro(add_nng_compat_test)
+ message(STATUS "Compatibility tests disabled (unconfigured protocols)")
endif ()
- macro (add_nng_cpp_test NAME TIMEOUT)
+ macro(add_nng_cpp_test NAME TIMEOUT)
if (NOT NNG_ENABLE_COVERAGE)
- enable_language (CXX)
- add_executable (${NAME} ${NAME}.cc)
- target_link_libraries (${NAME} ${PROJECT_NAME})
- add_test (NAME ${NAME} COMMAND ${NAME} ${TEST_PORT})
- set_tests_properties (${NAME} PROPERTIES TIMEOUT ${TIMEOUT})
- math (EXPR TEST_PORT "${NNG_TEST_PORT}+20")
- endif()
- endmacro (add_nng_cpp_test)
-
- macro (add_nng_test1 NAME TIMEOUT COND1)
+ enable_language(CXX)
+ add_executable(${NAME} ${NAME}.cc)
+ target_link_libraries(${NAME} ${PROJECT_NAME})
+ add_test(NAME ${NAME} COMMAND ${NAME} ${TEST_PORT})
+ set_tests_properties(${NAME} PROPERTIES TIMEOUT ${TIMEOUT})
+ math(EXPR TEST_PORT "${NNG_TEST_PORT}+20")
+ endif ()
+ endmacro(add_nng_cpp_test)
+
+ macro(add_nng_test1 NAME TIMEOUT COND1)
if (${COND1})
add_nng_test(${NAME} ${TIMEOUT})
- else()
- message (STATUS "Test ${NAME} disabled (unconfigured)")
- endif()
+ else ()
+ message(STATUS "Test ${NAME} disabled (unconfigured)")
+ endif ()
endmacro()
- macro (add_nng_test2 NAME TIMEOUT COND1 COND2)
+ macro(add_nng_test2 NAME TIMEOUT COND1 COND2)
if (${COND1} AND ${COND2})
add_nng_test(${NAME} ${TIMEOUT})
- else()
- message (STATUS "Test ${NAME} disabled (unconfigured)")
- endif()
+ else ()
+ message(STATUS "Test ${NAME} disabled (unconfigured)")
+ endif ()
endmacro()
- macro (add_nng_test3 NAME TIMEOUT COND1 COND2 COND3)
+ macro(add_nng_test3 NAME TIMEOUT COND1 COND2 COND3)
if (${COND1} AND ${COND2} AND ${COND3})
add_nng_test(${NAME} ${TIMEOUT} ON)
- else()
- message (STATUS "Test ${NAME} disabled (unconfigured)")
- endif()
+ else ()
+ message(STATUS "Test ${NAME} disabled (unconfigured)")
+ endif ()
endmacro()
else ()
- macro (add_nng_test NAME TIMEOUT)
- endmacro (add_nng_test)
- macro (add_nng_compat_test NAME TIMEOUT)
- endmacro (add_nng_compat_test)
- macro (add_nng_cpp_test NAME TIMEOUT)
- endmacro (add_nng_cpp_test)
- macro (add_nng_test1 NAME TIMEOUT COND1)
+ macro(add_nng_test NAME TIMEOUT)
+ endmacro(add_nng_test)
+ macro(add_nng_compat_test NAME TIMEOUT)
+ endmacro(add_nng_compat_test)
+ macro(add_nng_cpp_test NAME TIMEOUT)
+ endmacro(add_nng_cpp_test)
+ macro(add_nng_test1 NAME TIMEOUT COND1)
endmacro(add_nng_test1)
- macro (add_nng_test2 NAME TIMEOUT COND1 COND2)
+ macro(add_nng_test2 NAME TIMEOUT COND1 COND2)
endmacro(add_nng_test2)
- macro (add_nng_test3 NAME TIMEOUT COND1 COND2 COND3)
+ macro(add_nng_test3 NAME TIMEOUT COND1 COND2 COND3)
endmacro(add_nng_test3)
endif ()
-add_nng_test(aio 5)
-add_nng_test2(base64 5 NNG_STATIC_LIB NNG_SUPP_BASE64)
-add_nng_test1(bufsz 5 NNG_PROTO_PAIR0)
+nng_test(aio)
+nng_test(bufsz)
+nng_test(platform)
+nng_test(sock)
+
add_nng_test(device 5)
add_nng_test(errors 2)
add_nng_test1(files 5 NNG_STATIC_LIB)
@@ -158,15 +160,12 @@ add_nng_test(multistress 60)
add_nng_test(nonblock 60)
add_nng_test(options 5)
add_nng_test(pipe 5)
-add_nng_test(platform 5)
add_nng_test(pollfd 5)
add_nng_test(pubsubpollfd 5)
add_nng_test(reconnect 5)
add_nng_test1(resolv 10 NNG_STATIC_LIB)
add_nng_test(scalability 20 ON)
add_nng_test(set_recvmaxsize 2)
-add_nng_test2(sha1 5 NNG_STATIC_LIB NNG_SUPP_SHA1)
-add_nng_test(sock 5)
add_nng_test1(stats 5 NNG_ENABLE_STATS)
add_nng_test1(synch 5 NNG_STATIC_LIB)
add_nng_test2(tls 60 NNG_STATIC_LIB NNG_TRANSPORT_TLS)
@@ -184,18 +183,16 @@ add_nng_test1(zt 60 NNG_TRANSPORT_ZEROTIER)
add_nng_test1(bus 5 NNG_PROTO_BUS0)
add_nng_test2(pipeline 5 NNG_PROTO_PULL0 NNG_PROTO_PUSH0)
-add_nng_test1(pair1 5 NNG_PROTO_PAIR1)
add_nng_test2(pubsub 5 NNG_PROTO_PUB0 NNG_PROTO_SUB0)
add_nng_test2(reqctx 5 NNG_PROTO_REQ0 NNG_PROTO_REP0)
add_nng_test2(reqpoll 5 NNG_PROTO_REQ0 NNG_PROTO_REP0)
-add_nng_test2(reqrep 5 NNG_PROTO_REQ0 NNG_PROTO_REP0)
add_nng_test2(reqstress 60 NNG_PROTO_REQ0 NNG_PROTO_REP0)
add_nng_test2(respondpoll 5 NNG_PROTO_SURVEYOR0 NNG_PROTO_RESPONDENT0)
add_nng_test2(survey 5 NNG_PROTO_SURVEYOR0 NNG_PROTO_RESPONDENT0)
add_nng_test2(surveyctx 5 NNG_PROTO_SURVEYOR0 NNG_PROTO_RESPONDENT0)
add_nng_test2(surveypoll 5 NNG_PROTO_SURVEYOR0 NNG_PROTO_RESPONDENT0)
-# compatbility tests
+# compatibility tests
# We only support these if ALL the legacy protocols are supported. This
# is because we don't want to make modifications to partially enable some
# of these tests. Folks minimizing the library probably don't care too
diff --git a/tests/acutest.h b/tests/acutest.h
new file mode 100644
index 00000000..26d961e7
--- /dev/null
+++ b/tests/acutest.h
@@ -0,0 +1,1650 @@
+/*
+ * Acutest -- Another C/C++ Unit Test facility
+ * <http://github.com/mity/acutest>
+ *
+ * Copyright (c) 2013-2019 Martin Mitas
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef ACUTEST_H__
+#define ACUTEST_H__
+
+
+/************************
+ *** Public interface ***
+ ************************/
+
+/* By default, "acutest.h" provides the main program entry point (function
+ * main()). However, if the test suite is composed of multiple source files
+ * which include "acutest.h", then this causes a problem of multiple main()
+ * definitions. To avoid this problem, #define macro TEST_NO_MAIN in all
+ * compilation units but one.
+ */
+
+/* Macro to specify list of unit tests in the suite.
+ * The unit test implementation MUST provide list of unit tests it implements
+ * with this macro:
+ *
+ * TEST_LIST = {
+ * { "test1_name", test1_func_ptr },
+ * { "test2_name", test2_func_ptr },
+ * ...
+ * { 0 }
+ * };
+ *
+ * The list specifies names of each test (must be unique) and pointer to
+ * a function implementing it. The function does not take any arguments
+ * and has no return values, i.e. every test function has to be compatible
+ * with this prototype:
+ *
+ * void test_func(void);
+ */
+#define TEST_LIST const struct test__ test_list__[]
+
+
+/* Macros for testing whether an unit test succeeds or fails. These macros
+ * can be used arbitrarily in functions implementing the unit tests.
+ *
+ * If any condition fails throughout execution of a test, the test fails.
+ *
+ * TEST_CHECK takes only one argument (the condition), TEST_CHECK_ allows
+ * also to specify an error message to print out if the condition fails.
+ * (It expects printf-like format string and its parameters). The macros
+ * return non-zero (condition passes) or 0 (condition fails).
+ *
+ * That can be useful when more conditions should be checked only if some
+ * preceding condition passes, as illustrated in this code snippet:
+ *
+ * SomeStruct* ptr = allocate_some_struct();
+ * if(TEST_CHECK(ptr != NULL)) {
+ * TEST_CHECK(ptr->member1 < 100);
+ * TEST_CHECK(ptr->member2 > 200);
+ * }
+ */
+#define TEST_CHECK_(cond,...) test_check__((cond), __FILE__, __LINE__, __VA_ARGS__)
+#define TEST_CHECK(cond) test_check__((cond), __FILE__, __LINE__, "%s", #cond)
+
+
+/* These macros are the same as TEST_CHECK_ and TEST_CHECK except that if the
+ * condition fails, the currently executed unit test is immediately aborted.
+ *
+ * That is done either by calling abort() if the unit test is executed as a
+ * child process; or via longjmp() if the unit test is executed within the
+ * main Acutest process.
+ *
+ * As a side effect of such abortion, your unit tests may cause memory leaks,
+ * unflushed file descriptors, and other fenomena caused by the abortion.
+ *
+ * Therefore you should not use these as a general replacement for TEST_CHECK.
+ * Use it with some caution, especially if your test causes some other side
+ * effects to the outside world (e.g. communicating with some server, inserting
+ * into a database etc.).
+ */
+#define TEST_ASSERT_(cond,...) \
+ do { \
+ if (!test_check__((cond), __FILE__, __LINE__, __VA_ARGS__)) \
+ test_abort__(); \
+ } while(0)
+#define TEST_ASSERT(cond) \
+ do { \
+ if (!test_check__((cond), __FILE__, __LINE__, "%s", #cond)) \
+ test_abort__(); \
+ } while(0)
+
+
+#ifdef __cplusplus
+/* Macros to verify that the code (the 1st argument) throws exception of given
+ * type (the 2nd argument). (Note these macros are only available in C++.)
+ *
+ * TEST_EXCEPTION_ is like TEST_EXCEPTION but accepts custom printf-like
+ * message.
+ *
+ * For example:
+ *
+ * TEST_EXCEPTION(function_that_throw(), ExpectedExceptionType);
+ *
+ * If the function_that_throw() throws ExpectedExceptionType, the check passes.
+ * If the function throws anything incompatible with ExpectedExceptionType
+ * (or if it does not thrown an exception at all), the check fails.
+ */
+#define TEST_EXCEPTION(code, exctype) \
+ do { \
+ bool exc_ok__ = false; \
+ const char *msg__ = NULL; \
+ try { \
+ code; \
+ msg__ = "No exception thrown."; \
+ } catch(exctype const&) { \
+ exc_ok__= true; \
+ } catch(...) { \
+ msg__ = "Unexpected exception thrown."; \
+ } \
+ test_check__(exc_ok__, __FILE__, __LINE__, #code " throws " #exctype); \
+ if(msg__ != NULL) \
+ test_message__("%s", msg__); \
+ } while(0)
+#define TEST_EXCEPTION_(code, exctype, ...) \
+ do { \
+ bool exc_ok__ = false; \
+ const char *msg__ = NULL; \
+ try { \
+ code; \
+ msg__ = "No exception thrown."; \
+ } catch(exctype const&) { \
+ exc_ok__= true; \
+ } catch(...) { \
+ msg__ = "Unexpected exception thrown."; \
+ } \
+ test_check__(exc_ok__, __FILE__, __LINE__, __VA_ARGS__); \
+ if(msg__ != NULL) \
+ test_message__("%s", msg__); \
+ } while(0)
+#endif /* #ifdef __cplusplus */
+
+
+/* Sometimes it is useful to split execution of more complex unit tests to some
+ * smaller parts and associate those parts with some names.
+ *
+ * This is especially handy if the given unit test is implemented as a loop
+ * over some vector of multiple testing inputs. Using these macros allow to use
+ * sort of subtitle for each iteration of the loop (e.g. outputting the input
+ * itself or a name associated to it), so that if any TEST_CHECK condition
+ * fails in the loop, it can be easily seen which iteration triggers the
+ * failure, without the need to manually output the iteration-specific data in
+ * every single TEST_CHECK inside the loop body.
+ *
+ * TEST_CASE allows to specify only single string as the name of the case,
+ * TEST_CASE_ provides all the power of printf-like string formatting.
+ *
+ * Note that the test cases cannot be nested. Starting a new test case ends
+ * implicitly the previous one. To end the test case explicitly (e.g. to end
+ * the last test case after exiting the loop), you may use TEST_CASE(NULL).
+ */
+#define TEST_CASE_(...) test_case__(__VA_ARGS__)
+#define TEST_CASE(name) test_case__("%s", name)
+
+
+/* printf-like macro for outputting an extra information about a failure.
+ *
+ * Intended use is to output some computed output versus the expected value,
+ * e.g. like this:
+ *
+ * if(!TEST_CHECK(produced == expected)) {
+ * TEST_MSG("Expected: %d", expected);
+ * TEST_MSG("Produced: %d", produced);
+ * }
+ *
+ * Note the message is only written down if the most recent use of any checking
+ * macro (like e.g. TEST_CHECK or TEST_EXCEPTION) in the current test failed.
+ * This means the above is equivalent to just this:
+ *
+ * TEST_CHECK(produced == expected);
+ * TEST_MSG("Expected: %d", expected);
+ * TEST_MSG("Produced: %d", produced);
+ *
+ * The macro can deal with multi-line output fairly well. It also automatically
+ * adds a final new-line if there is none present.
+ */
+#define TEST_MSG(...) test_message__(__VA_ARGS__)
+
+
+/* Maximal output per TEST_MSG call. Longer messages are cut.
+ * You may define another limit prior including "acutest.h"
+ */
+#ifndef TEST_MSG_MAXSIZE
+ #define TEST_MSG_MAXSIZE 1024
+#endif
+
+
+/* Macro for dumping a block of memory.
+ *
+ * Its intended use is very similar to what TEST_MSG is for, but instead of
+ * generating any printf-like message, this is for dumping raw block of a
+ * memory in a hexadecimal form:
+ *
+ * TEST_CHECK(size_produced == size_expected && memcmp(addr_produced, addr_expected, size_produced) == 0);
+ * TEST_DUMP("Expected:", addr_expected, size_expected);
+ * TEST_DUMP("Produced:", addr_produced, size_produced);
+ */
+#define TEST_DUMP(title, addr, size) test_dump__(title, addr, size)
+
+/* Maximal output per TEST_DUMP call (in bytes to dump). Longer blocks are cut.
+ * You may define another limit prior including "acutest.h"
+ */
+#ifndef TEST_DUMP_MAXSIZE
+ #define TEST_DUMP_MAXSIZE 1024
+#endif
+
+
+/**********************
+ *** Implementation ***
+ **********************/
+
+/* The unit test files should not rely on anything below. */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+
+#if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__)
+ #define ACUTEST_UNIX__ 1
+ #include <errno.h>
+ #include <libgen.h>
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ #include <signal.h>
+ #include <time.h>
+
+ #if defined CLOCK_PROCESS_CPUTIME_ID && defined CLOCK_MONOTONIC
+ #define ACUTEST_HAS_POSIX_TIMER__ 1
+ #endif
+#endif
+
+#if defined(__gnu_linux__)
+ #define ACUTEST_LINUX__ 1
+ #include <fcntl.h>
+ #include <sys/stat.h>
+#endif
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
+ #define ACUTEST_WIN__ 1
+ #include <windows.h>
+ #include <io.h>
+#endif
+
+#ifdef __cplusplus
+ #include <exception>
+#endif
+
+
+/* Note our global private identifiers end with '__' to mitigate risk of clash
+ * with the unit tests implementation. */
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+struct test__ {
+ const char* name;
+ void (*func)(void);
+};
+
+struct test_detail__ {
+ unsigned char flags;
+ double duration;
+};
+
+enum {
+ TEST_FLAG_RUN__ = 1 << 0,
+ TEST_FLAG_SUCCESS__ = 1 << 1,
+ TEST_FLAG_FAILURE__ = 1 << 2,
+};
+
+extern const struct test__ test_list__[];
+
+int test_check__(int cond, const char* file, int line, const char* fmt, ...);
+void test_case__(const char* fmt, ...);
+void test_message__(const char* fmt, ...);
+void test_dump__(const char* title, const void* addr, size_t size);
+void test_abort__(void);
+
+
+#ifndef TEST_NO_MAIN
+
+static char* test_argv0__ = NULL;
+static size_t test_list_size__ = 0;
+static struct test_detail__ *test_details__ = NULL;
+static size_t test_count__ = 0;
+static int test_no_exec__ = -1;
+static int test_no_summary__ = 0;
+static int test_tap__ = 0;
+static int test_skip_mode__ = 0;
+static int test_worker__ = 0;
+static int test_worker_index__ = 0;
+static int test_cond_failed__ = 0;
+static FILE *test_xml_output__ = NULL;
+
+static int test_stat_failed_units__ = 0;
+static int test_stat_run_units__ = 0;
+
+static const struct test__* test_current_unit__ = NULL;
+static int test_current_index__ = 0;
+static char test_case_name__[64] = "";
+static int test_current_already_logged__ = 0;
+static int test_case_current_already_logged__ = 0;
+static int test_verbose_level__ = 2;
+static int test_current_failures__ = 0;
+static int test_colorize__ = 0;
+static int test_timer__ = 0;
+
+static int test_abort_has_jmp_buf__ = 0;
+static jmp_buf test_abort_jmp_buf__;
+
+#if defined ACUTEST_WIN__
+ typedef LARGE_INTEGER test_timer_type__;
+ static LARGE_INTEGER test_timer_freq__;
+ static test_timer_type__ test_timer_start__;
+ static test_timer_type__ test_timer_end__;
+
+ static void
+ test_timer_init__(void)
+ {
+ QueryPerformanceFrequency(&test_timer_freq__);
+ }
+
+ static void
+ test_timer_get_time__(LARGE_INTEGER* ts)
+ {
+ QueryPerformanceCounter(ts);
+ }
+
+ static double
+ test_timer_diff__(LARGE_INTEGER start, LARGE_INTEGER end)
+ {
+ double duration = (double)(end.QuadPart - start.QuadPart);
+ duration /= (double)test_timer_freq__.QuadPart;
+ return duration;
+ }
+
+ static void
+ test_timer_print_diff__(void)
+ {
+ printf("%.6lf secs", test_timer_diff__(test_timer_start__, test_timer_end__));
+ }
+#elif defined ACUTEST_HAS_POSIX_TIMER__
+ static clockid_t test_timer_id__;
+ typedef struct timespec test_timer_type__;
+ static test_timer_type__ test_timer_start__;
+ static test_timer_type__ test_timer_end__;
+
+ static void
+ test_timer_init__(void)
+ {
+ if(test_timer__ == 1)
+ #ifdef CLOCK_MONOTONIC_RAWxx
+ /* linux specific; not subject of NTP adjustments or adjtime() */
+ test_timer_id__ = CLOCK_MONOTONIC_RAW;
+ #else
+ test_timer_id__ = CLOCK_MONOTONIC;
+ #endif
+ else if(test_timer__ == 2)
+ test_timer_id__ = CLOCK_PROCESS_CPUTIME_ID;
+ }
+
+ static void
+ test_timer_get_time__(struct timespec* ts)
+ {
+ clock_gettime(test_timer_id__, ts);
+ }
+
+ static double
+ test_timer_diff__(struct timespec start, struct timespec end)
+ {
+ double endns;
+ double startns;
+
+ endns = end.tv_sec;
+ endns *= 10e9;
+ endns += end.tv_nsec;
+
+ startns = start.tv_sec;
+ startns *= 10e9;
+ startns += start.tv_nsec;
+
+ return ((endns - startns)/ 10e9);
+ }
+
+ static void
+ test_timer_print_diff__(void)
+ {
+ printf("%.6lf secs",
+ test_timer_diff__(test_timer_start__, test_timer_end__));
+ }
+#else
+ typedef int test_timer_type__;
+ static test_timer_type__ test_timer_start__;
+ static test_timer_type__ test_timer_end__;
+
+ void
+ test_timer_init__(void)
+ {}
+
+ static void
+ test_timer_get_time__(int* ts)
+ {
+ (void) ts;
+ }
+
+ static double
+ test_timer_diff__(int start, int end)
+ {
+ (void) start;
+ (void) end;
+ return 0.0;
+ }
+
+ static void
+ test_timer_print_diff__(void)
+ {}
+#endif
+
+#define TEST_COLOR_DEFAULT__ 0
+#define TEST_COLOR_GREEN__ 1
+#define TEST_COLOR_RED__ 2
+#define TEST_COLOR_DEFAULT_INTENSIVE__ 3
+#define TEST_COLOR_GREEN_INTENSIVE__ 4
+#define TEST_COLOR_RED_INTENSIVE__ 5
+
+static int
+test_print_in_color__(int color, const char* fmt, ...)
+{
+ va_list args;
+ char buffer[256];
+ int n;
+
+ va_start(args, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, args);
+ va_end(args);
+ buffer[sizeof(buffer)-1] = '\0';
+
+ if(!test_colorize__) {
+ return printf("%s", buffer);
+ }
+
+#if defined ACUTEST_UNIX__
+ {
+ const char* col_str;
+ switch(color) {
+ case TEST_COLOR_GREEN__: col_str = "\033[0;32m"; break;
+ case TEST_COLOR_RED__: col_str = "\033[0;31m"; break;
+ case TEST_COLOR_GREEN_INTENSIVE__: col_str = "\033[1;32m"; break;
+ case TEST_COLOR_RED_INTENSIVE__: col_str = "\033[1;31m"; break;
+ case TEST_COLOR_DEFAULT_INTENSIVE__: col_str = "\033[1m"; break;
+ default: col_str = "\033[0m"; break;
+ }
+ printf("%s", col_str);
+ n = printf("%s", buffer);
+ printf("\033[0m");
+ return n;
+ }
+#elif defined ACUTEST_WIN__
+ {
+ HANDLE h;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ WORD attr;
+
+ h = GetStdHandle(STD_OUTPUT_HANDLE);
+ GetConsoleScreenBufferInfo(h, &info);
+
+ switch(color) {
+ case TEST_COLOR_GREEN__: attr = FOREGROUND_GREEN; break;
+ case TEST_COLOR_RED__: attr = FOREGROUND_RED; break;
+ case TEST_COLOR_GREEN_INTENSIVE__: attr = FOREGROUND_GREEN | FOREGROUND_INTENSITY; break;
+ case TEST_COLOR_RED_INTENSIVE__: attr = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
+ case TEST_COLOR_DEFAULT_INTENSIVE__: attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; break;
+ default: attr = 0; break;
+ }
+ if(attr != 0)
+ SetConsoleTextAttribute(h, attr);
+ n = printf("%s", buffer);
+ SetConsoleTextAttribute(h, info.wAttributes);
+ return n;
+ }
+#else
+ n = printf("%s", buffer);
+ return n;
+#endif
+}
+
+static void
+test_begin_test_line__(const struct test__* test)
+{
+ if(!test_tap__) {
+ if(test_verbose_level__ >= 3) {
+ test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Test %s:\n", test->name);
+ test_current_already_logged__++;
+ } else if(test_verbose_level__ >= 1) {
+ int n;
+ char spaces[48];
+
+ n = test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Test %s... ", test->name);
+ memset(spaces, ' ', sizeof(spaces));
+ if(n < (int) sizeof(spaces))
+ printf("%.*s", (int) sizeof(spaces) - n, spaces);
+ } else {
+ test_current_already_logged__ = 1;
+ }
+ }
+}
+
+static void
+test_finish_test_line__(int result)
+{
+ if(test_tap__) {
+ const char* str = (result == 0) ? "ok" : "not ok";
+
+ printf("%s %u - %s\n", str, test_current_index__ + 1, test_current_unit__->name);
+
+ if(result == 0 && test_timer__) {
+ printf("# Duration: ");
+ test_timer_print_diff__();
+ printf("\n");
+ }
+ } else {
+ int color = (result == 0) ? TEST_COLOR_GREEN_INTENSIVE__ : TEST_COLOR_RED_INTENSIVE__;
+ const char* str = (result == 0) ? "OK" : "FAILED";
+ printf("[ ");
+ test_print_in_color__(color, str);
+ printf(" ]");
+
+ if(result == 0 && test_timer__) {
+ printf(" ");
+ test_timer_print_diff__();
+ }
+
+ printf("\n");
+ }
+}
+
+static void
+test_line_indent__(int level)
+{
+ static const char spaces[] = " ";
+ int n = level * 2;
+
+ if(test_tap__ && n > 0) {
+ n--;
+ printf("#");
+ }
+
+ while(n > 16) {
+ printf("%s", spaces);
+ n -= 16;
+ }
+ printf("%.*s", n, spaces);
+}
+
+int
+test_check__(int cond, const char* file, int line, const char* fmt, ...)
+{
+ const char *result_str;
+ int result_color;
+ int verbose_level;
+
+ if(cond) {
+ result_str = "ok";
+ result_color = TEST_COLOR_GREEN__;
+ verbose_level = 3;
+ } else {
+ if(!test_current_already_logged__ && test_current_unit__ != NULL)
+ test_finish_test_line__(-1);
+
+ result_str = "failed";
+ result_color = TEST_COLOR_RED__;
+ verbose_level = 2;
+ test_current_failures__++;
+ test_current_already_logged__++;
+ }
+
+ if(test_verbose_level__ >= verbose_level) {
+ va_list args;
+
+ if(!test_case_current_already_logged__ && test_case_name__[0]) {
+ test_line_indent__(1);
+ test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Case %s:\n", test_case_name__);
+ test_current_already_logged__++;
+ test_case_current_already_logged__++;
+ }
+
+ test_line_indent__(test_case_name__[0] ? 2 : 1);
+ if(file != NULL) {
+ if(test_verbose_level__ < 3) {
+#ifdef ACUTEST_WIN__
+ const char* lastsep1 = strrchr(file, '\\');
+ const char* lastsep2 = strrchr(file, '/');
+ if(lastsep1 == NULL)
+ lastsep1 = file-1;
+ if(lastsep2 == NULL)
+ lastsep2 = file-1;
+ file = (lastsep1 > lastsep2 ? lastsep1 : lastsep2) + 1;
+#else
+ const char* lastsep = strrchr(file, '/');
+ if(lastsep != NULL)
+ file = lastsep+1;
+#endif
+ }
+ printf("%s:%d: Check ", file, line);
+ }
+
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+
+ printf("... ");
+ test_print_in_color__(result_color, result_str);
+ printf("\n");
+ test_current_already_logged__++;
+ }
+
+ test_cond_failed__ = (cond == 0);
+ return !test_cond_failed__;
+}
+
+void
+test_case__(const char* fmt, ...)
+{
+ va_list args;
+
+ if(test_verbose_level__ < 2)
+ return;
+
+ if(test_case_name__[0]) {
+ test_case_current_already_logged__ = 0;
+ test_case_name__[0] = '\0';
+ }
+
+ if(fmt == NULL)
+ return;
+
+ va_start(args, fmt);
+ vsnprintf(test_case_name__, sizeof(test_case_name__) - 1, fmt, args);
+ va_end(args);
+ test_case_name__[sizeof(test_case_name__) - 1] = '\0';
+
+ if(test_verbose_level__ >= 3) {
+ test_line_indent__(1);
+ test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Case %s:\n", test_case_name__);
+ test_current_already_logged__++;
+ test_case_current_already_logged__++;
+ }
+}
+
+void
+test_message__(const char* fmt, ...)
+{
+ char buffer[TEST_MSG_MAXSIZE];
+ char* line_beg;
+ char* line_end;
+ va_list args;
+
+ if(test_verbose_level__ < 2)
+ return;
+
+ /* We allow extra message only when something is already wrong in the
+ * current test. */
+ if(test_current_unit__ == NULL || !test_cond_failed__)
+ return;
+
+ va_start(args, fmt);
+ vsnprintf(buffer, TEST_MSG_MAXSIZE, fmt, args);
+ va_end(args);
+ buffer[TEST_MSG_MAXSIZE-1] = '\0';
+
+ line_beg = buffer;
+ while(1) {
+ line_end = strchr(line_beg, '\n');
+ if(line_end == NULL)
+ break;
+ test_line_indent__(test_case_name__[0] ? 3 : 2);
+ printf("%.*s\n", (int)(line_end - line_beg), line_beg);
+ line_beg = line_end + 1;
+ }
+ if(line_beg[0] != '\0') {
+ test_line_indent__(test_case_name__[0] ? 3 : 2);
+ printf("%s\n", line_beg);
+ }
+}
+
+void
+test_dump__(const char* title, const void* addr, size_t size)
+{
+ static const size_t BYTES_PER_LINE = 16;
+ size_t line_beg;
+ size_t truncate = 0;
+
+ if(test_verbose_level__ < 2)
+ return;
+
+ /* We allow extra message only when something is already wrong in the
+ * current test. */
+ if(test_current_unit__ == NULL || !test_cond_failed__)
+ return;
+
+ if(size > TEST_DUMP_MAXSIZE) {
+ truncate = size - TEST_DUMP_MAXSIZE;
+ size = TEST_DUMP_MAXSIZE;
+ }
+
+ test_line_indent__(test_case_name__[0] ? 3 : 2);
+ printf((title[strlen(title)-1] == ':') ? "%s\n" : "%s:\n", title);
+
+ for(line_beg = 0; line_beg < size; line_beg += BYTES_PER_LINE) {
+ size_t line_end = line_beg + BYTES_PER_LINE;
+ size_t off;
+
+ test_line_indent__(test_case_name__[0] ? 4 : 3);
+ printf("%08lx: ", (unsigned long)line_beg);
+ for(off = line_beg; off < line_end; off++) {
+ if(off < size)
+ printf(" %02x", ((unsigned char*)addr)[off]);
+ else
+ printf(" ");
+ }
+
+ printf(" ");
+ for(off = line_beg; off < line_end; off++) {
+ unsigned char byte = ((unsigned char*)addr)[off];
+ if(off < size)
+ printf("%c", (iscntrl(byte) ? '.' : byte));
+ else
+ break;
+ }
+
+ printf("\n");
+ }
+
+ if(truncate > 0) {
+ test_line_indent__(test_case_name__[0] ? 4 : 3);
+ printf(" ... (and more %u bytes)\n", (unsigned) truncate);
+ }
+}
+
+void
+test_abort__(void)
+{
+ if(test_abort_has_jmp_buf__)
+ longjmp(test_abort_jmp_buf__, 1);
+ else
+ abort();
+}
+
+static void
+test_list_names__(void)
+{
+ const struct test__* test;
+
+ printf("Unit tests:\n");
+ for(test = &test_list__[0]; test->func != NULL; test++)
+ printf(" %s\n", test->name);
+}
+
+static void
+test_remember__(int i)
+{
+ if(test_details__[i].flags & TEST_FLAG_RUN__)
+ return;
+
+ test_details__[i].flags |= TEST_FLAG_RUN__;
+ test_count__++;
+}
+
+static void
+test_set_success__(int i, int success)
+{
+ test_details__[i].flags |= success ? TEST_FLAG_SUCCESS__ : TEST_FLAG_FAILURE__;
+}
+
+static void
+test_set_duration__(int i, double duration)
+{
+ test_details__[i].duration = duration;
+}
+
+static int
+test_name_contains_word__(const char* name, const char* pattern)
+{
+ static const char word_delim[] = " \t-_.";
+ const char* substr;
+ size_t pattern_len;
+ int starts_on_word_boundary;
+ int ends_on_word_boundary;
+
+ pattern_len = strlen(pattern);
+
+ substr = strstr(name, pattern);
+ while(substr != NULL) {
+ starts_on_word_boundary = (substr == name || strchr(word_delim, substr[-1]) != NULL);
+ ends_on_word_boundary = (substr[pattern_len] == '\0' || strchr(word_delim, substr[pattern_len]) != NULL);
+
+ if(starts_on_word_boundary && ends_on_word_boundary)
+ return 1;
+
+ substr = strstr(substr+1, pattern);
+ }
+
+ return 0;
+}
+
+static int
+test_lookup__(const char* pattern)
+{
+ int i;
+ int n = 0;
+
+ /* Try exact match. */
+ for(i = 0; i < (int) test_list_size__; i++) {
+ if(strcmp(test_list__[i].name, pattern) == 0) {
+ test_remember__(i);
+ n++;
+ break;
+ }
+ }
+ if(n > 0)
+ return n;
+
+ /* Try word match. */
+ for(i = 0; i < (int) test_list_size__; i++) {
+ if(test_name_contains_word__(test_list__[i].name, pattern)) {
+ test_remember__(i);
+ n++;
+ }
+ }
+ if(n > 0)
+ return n;
+
+ /* Try relaxed match. */
+ for(i = 0; i < (int) test_list_size__; i++) {
+ if(strstr(test_list__[i].name, pattern) != NULL) {
+ test_remember__(i);
+ n++;
+ }
+ }
+
+ return n;
+}
+
+
+/* Called if anything goes bad in Acutest, or if the unit test ends in other
+ * way then by normal returning from its function (e.g. exception or some
+ * abnormal child process termination). */
+static void
+test_error__(const char* fmt, ...)
+{
+ va_list args;
+
+ if(test_verbose_level__ == 0)
+ return;
+
+ if(test_verbose_level__ <= 2 && !test_current_already_logged__ && test_current_unit__ != NULL) {
+ if(test_tap__) {
+ test_finish_test_line__(-1);
+ } else {
+ printf("[ ");
+ test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "FAILED");
+ printf(" ]\n");
+ }
+ }
+
+ if(test_verbose_level__ >= 2) {
+ test_line_indent__(1);
+ if(test_verbose_level__ >= 3)
+ test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "ERROR: ");
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ printf("\n");
+ }
+
+ if(test_verbose_level__ >= 3) {
+ printf("\n");
+ }
+}
+
+/* Call directly the given test unit function. */
+static int
+test_do_run__(const struct test__* test, int index)
+{
+ test_current_unit__ = test;
+ test_current_index__ = index;
+ test_current_failures__ = 0;
+ test_current_already_logged__ = 0;
+ test_cond_failed__ = 0;
+
+ test_begin_test_line__(test);
+
+#ifdef __cplusplus
+ try {
+#endif
+
+ /* This is good to do for case the test unit e.g. crashes. */
+ fflush(stdout);
+ fflush(stderr);
+
+ if(!test_worker__) {
+ test_abort_has_jmp_buf__ = 1;
+ if(setjmp(test_abort_jmp_buf__) != 0)
+ goto aborted;
+ }
+
+ test_timer_get_time__(&test_timer_start__);
+ test->func();
+aborted:
+ test_abort_has_jmp_buf__ = 0;
+ test_timer_get_time__(&test_timer_end__);
+
+ if(test_verbose_level__ >= 3) {
+ test_line_indent__(1);
+ if(test_current_failures__ == 0) {
+ test_print_in_color__(TEST_COLOR_GREEN_INTENSIVE__, "SUCCESS: ");
+ printf("All conditions have passed.\n");
+
+ if(test_timer__) {
+ test_line_indent__(1);
+ printf("Duration: ");
+ test_timer_print_diff__();
+ printf("\n");
+ }
+ } else {
+ test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "FAILED: ");
+ printf("%d condition%s %s failed.\n",
+ test_current_failures__,
+ (test_current_failures__ == 1) ? "" : "s",
+ (test_current_failures__ == 1) ? "has" : "have");
+ }
+ printf("\n");
+ } else if(test_verbose_level__ >= 1 && test_current_failures__ == 0) {
+ test_finish_test_line__(0);
+ }
+
+ test_case__(NULL);
+ test_current_unit__ = NULL;
+ return (test_current_failures__ == 0) ? 0 : -1;
+
+#ifdef __cplusplus
+ } catch(std::exception& e) {
+ const char* what = e.what();
+ test_check__(0, NULL, 0, "Threw std::exception");
+ if(what != NULL)
+ test_message__("std::exception::what(): %s", what);
+ return -1;
+ } catch(...) {
+ test_check__(0, NULL, 0, "Threw an exception");
+ return -1;
+ }
+#endif
+}
+
+/* Trigger the unit test. If possible (and not suppressed) it starts a child
+ * process who calls test_do_run__(), otherwise it calls test_do_run__()
+ * directly. */
+static void
+test_run__(const struct test__* test, int index, int master_index)
+{
+ int failed = 1;
+ test_timer_type__ start, end;
+
+ test_current_unit__ = test;
+ test_current_already_logged__ = 0;
+ test_timer_get_time__(&start);
+
+ if(!test_no_exec__) {
+
+#if defined(ACUTEST_UNIX__)
+
+ pid_t pid;
+ int exit_code;
+
+ /* Make sure the child starts with empty I/O buffers. */
+ fflush(stdout);
+ fflush(stderr);
+
+ pid = fork();
+ if(pid == (pid_t)-1) {
+ test_error__("Cannot fork. %s [%d]", strerror(errno), errno);
+ failed = 1;
+ } else if(pid == 0) {
+ /* Child: Do the test. */
+ test_worker__ = 1;
+ failed = (test_do_run__(test, index) != 0);
+ exit(failed ? 1 : 0);
+ } else {
+ /* Parent: Wait until child terminates and analyze its exit code. */
+ waitpid(pid, &exit_code, 0);
+ if(WIFEXITED(exit_code)) {
+ switch(WEXITSTATUS(exit_code)) {
+ case 0: failed = 0; break; /* test has passed. */
+ case 1: /* noop */ break; /* "normal" failure. */
+ default: test_error__("Unexpected exit code [%d]", WEXITSTATUS(exit_code));
+ }
+ } else if(WIFSIGNALED(exit_code)) {
+ char tmp[32];
+ const char* signame;
+ switch(WTERMSIG(exit_code)) {
+ case SIGINT: signame = "SIGINT"; break;
+ case SIGHUP: signame = "SIGHUP"; break;
+ case SIGQUIT: signame = "SIGQUIT"; break;
+ case SIGABRT: signame = "SIGABRT"; break;
+ case SIGKILL: signame = "SIGKILL"; break;
+ case SIGSEGV: signame = "SIGSEGV"; break;
+ case SIGILL: signame = "SIGILL"; break;
+ case SIGTERM: signame = "SIGTERM"; break;
+ default: sprintf(tmp, "signal %d", WTERMSIG(exit_code)); signame = tmp; break;
+ }
+ test_error__("Test interrupted by %s", signame);
+ } else {
+ test_error__("Test ended in an unexpected way [%d]", exit_code);
+ }
+ }
+
+#elif defined(ACUTEST_WIN__)
+
+ char buffer[512] = {0};
+ STARTUPINFOA startupInfo;
+ PROCESS_INFORMATION processInfo;
+ DWORD exitCode;
+
+ /* Windows has no fork(). So we propagate all info into the child
+ * through a command line arguments. */
+ _snprintf(buffer, sizeof(buffer)-1,
+ "%s --worker=%d %s --no-exec --no-summary %s --verbose=%d --color=%s -- \"%s\"",
+ test_argv0__, index, test_timer__ ? "--timer" : "",
+ test_tap__ ? "--tap" : "", test_verbose_level__,
+ test_colorize__ ? "always" : "never",
+ test->name);
+ memset(&startupInfo, 0, sizeof(startupInfo));
+ startupInfo.cb = sizeof(STARTUPINFO);
+ if(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) {
+ WaitForSingleObject(processInfo.hProcess, INFINITE);
+ GetExitCodeProcess(processInfo.hProcess, &exitCode);
+ CloseHandle(processInfo.hThread);
+ CloseHandle(processInfo.hProcess);
+ failed = (exitCode != 0);
+ } else {
+ test_error__("Cannot create unit test subprocess [%ld].", GetLastError());
+ failed = 1;
+ }
+
+#else
+
+ /* A platform where we don't know how to run child process. */
+ failed = (test_do_run__(test, index) != 0);
+
+#endif
+
+ } else {
+ /* Child processes suppressed through --no-exec. */
+ failed = (test_do_run__(test, index) != 0);
+ }
+ test_timer_get_time__(&end);
+
+ test_current_unit__ = NULL;
+
+ test_stat_run_units__++;
+ if(failed)
+ test_stat_failed_units__++;
+
+ test_set_success__(master_index, !failed);
+ test_set_duration__(master_index, test_timer_diff__(start, end));
+}
+
+#if defined(ACUTEST_WIN__)
+/* Callback for SEH events. */
+static LONG CALLBACK
+test_seh_exception_filter__(EXCEPTION_POINTERS *ptrs)
+{
+ test_check__(0, NULL, 0, "Unhandled SEH exception");
+ test_message__("Exception code: 0x%08lx", ptrs->ExceptionRecord->ExceptionCode);
+ test_message__("Exception address: 0x%p", ptrs->ExceptionRecord->ExceptionAddress);
+
+ fflush(stdout);
+ fflush(stderr);
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+#endif
+
+
+#define TEST_CMDLINE_OPTFLAG_OPTIONALARG__ 0x0001
+#define TEST_CMDLINE_OPTFLAG_REQUIREDARG__ 0x0002
+
+#define TEST_CMDLINE_OPTID_NONE__ 0
+#define TEST_CMDLINE_OPTID_UNKNOWN__ (-0x7fffffff + 0)
+#define TEST_CMDLINE_OPTID_MISSINGARG__ (-0x7fffffff + 1)
+#define TEST_CMDLINE_OPTID_BOGUSARG__ (-0x7fffffff + 2)
+
+typedef struct TEST_CMDLINE_OPTION__ {
+ char shortname;
+ const char* longname;
+ int id;
+ unsigned flags;
+} TEST_CMDLINE_OPTION__;
+
+static int
+test_cmdline_handle_short_opt_group__(const TEST_CMDLINE_OPTION__* options,
+ const char* arggroup,
+ int (*callback)(int /*optval*/, const char* /*arg*/))
+{
+ const TEST_CMDLINE_OPTION__* opt;
+ int i;
+ int ret = 0;
+
+ for(i = 0; arggroup[i] != '\0'; i++) {
+ for(opt = options; opt->id != 0; opt++) {
+ if(arggroup[i] == opt->shortname)
+ break;
+ }
+
+ if(opt->id != 0 && !(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG__)) {
+ ret = callback(opt->id, NULL);
+ } else {
+ /* Unknown option. */
+ char badoptname[3];
+ badoptname[0] = '-';
+ badoptname[1] = arggroup[i];
+ badoptname[2] = '\0';
+ ret = callback((opt->id != 0 ? TEST_CMDLINE_OPTID_MISSINGARG__ : TEST_CMDLINE_OPTID_UNKNOWN__),
+ badoptname);
+ }
+
+ if(ret != 0)
+ break;
+ }
+
+ return ret;
+}
+
+#define TEST_CMDLINE_AUXBUF_SIZE__ 32
+
+static int
+test_cmdline_read__(const TEST_CMDLINE_OPTION__* options, int argc, char** argv,
+ int (*callback)(int /*optval*/, const char* /*arg*/))
+{
+
+ const TEST_CMDLINE_OPTION__* opt;
+ char auxbuf[TEST_CMDLINE_AUXBUF_SIZE__+1];
+ int after_doubledash = 0;
+ int i = 1;
+ int ret = 0;
+
+ auxbuf[TEST_CMDLINE_AUXBUF_SIZE__] = '\0';
+
+ while(i < argc) {
+ if(after_doubledash || strcmp(argv[i], "-") == 0) {
+ /* Non-option argument. */
+ ret = callback(TEST_CMDLINE_OPTID_NONE__, argv[i]);
+ } else if(strcmp(argv[i], "--") == 0) {
+ /* End of options. All the remaining members are non-option arguments. */
+ after_doubledash = 1;
+ } else if(argv[i][0] != '-') {
+ /* Non-option argument. */
+ ret = callback(TEST_CMDLINE_OPTID_NONE__, argv[i]);
+ } else {
+ for(opt = options; opt->id != 0; opt++) {
+ if(opt->longname != NULL && strncmp(argv[i], "--", 2) == 0) {
+ size_t len = strlen(opt->longname);
+ if(strncmp(argv[i]+2, opt->longname, len) == 0) {
+ /* Regular long option. */
+ if(argv[i][2+len] == '\0') {
+ /* with no argument provided. */
+ if(!(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG__))
+ ret = callback(opt->id, NULL);
+ else
+ ret = callback(TEST_CMDLINE_OPTID_MISSINGARG__, argv[i]);
+ break;
+ } else if(argv[i][2+len] == '=') {
+ /* with an argument provided. */
+ if(opt->flags & (TEST_CMDLINE_OPTFLAG_OPTIONALARG__ | TEST_CMDLINE_OPTFLAG_REQUIREDARG__)) {
+ ret = callback(opt->id, argv[i]+2+len+1);
+ } else {
+ sprintf(auxbuf, "--%s", opt->longname);
+ ret = callback(TEST_CMDLINE_OPTID_BOGUSARG__, auxbuf);
+ }
+ break;
+ } else {
+ continue;
+ }
+ }
+ } else if(opt->shortname != '\0' && argv[i][0] == '-') {
+ if(argv[i][1] == opt->shortname) {
+ /* Regular short option. */
+ if(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG__) {
+ if(argv[i][2] != '\0')
+ ret = callback(opt->id, argv[i]+2);
+ else if(i+1 < argc)
+ ret = callback(opt->id, argv[++i]);
+ else
+ ret = callback(TEST_CMDLINE_OPTID_MISSINGARG__, argv[i]);
+ break;
+ } else {
+ ret = callback(opt->id, NULL);
+
+ /* There might be more (argument-less) short options
+ * grouped together. */
+ if(ret == 0 && argv[i][2] != '\0')
+ ret = test_cmdline_handle_short_opt_group__(options, argv[i]+2, callback);
+ break;
+ }
+ }
+ }
+ }
+
+ if(opt->id == 0) { /* still not handled? */
+ if(argv[i][0] != '-') {
+ /* Non-option argument. */
+ ret = callback(TEST_CMDLINE_OPTID_NONE__, argv[i]);
+ } else {
+ /* Unknown option. */
+ char* badoptname = argv[i];
+
+ if(strncmp(badoptname, "--", 2) == 0) {
+ /* Strip any argument from the long option. */
+ char* assignment = strchr(badoptname, '=');
+ if(assignment != NULL) {
+ size_t len = assignment - badoptname;
+ if(len > TEST_CMDLINE_AUXBUF_SIZE__)
+ len = TEST_CMDLINE_AUXBUF_SIZE__;
+ strncpy(auxbuf, badoptname, len);
+ auxbuf[len] = '\0';
+ badoptname = auxbuf;
+ }
+ }
+
+ ret = callback(TEST_CMDLINE_OPTID_UNKNOWN__, badoptname);
+ }
+ }
+ }
+
+ if(ret != 0)
+ return ret;
+ i++;
+ }
+
+ return ret;
+}
+
+static void
+test_help__(void)
+{
+ printf("Usage: %s [options] [test...]\n", test_argv0__);
+ printf("\n");
+ printf("Run the specified unit tests; or if the option '--skip' is used, run all\n");
+ printf("tests in the suite but those listed. By default, if no tests are specified\n");
+ printf("on the command line, all unit tests in the suite are run.\n");
+ printf("\n");
+ printf("Options:\n");
+ printf(" -s, --skip Execute all unit tests but the listed ones\n");
+ printf(" --exec[=WHEN] If supported, execute unit tests as child processes\n");
+ printf(" (WHEN is one of 'auto', 'always', 'never')\n");
+#if defined ACUTEST_WIN__
+ printf(" -t, --timer Measure test duration\n");
+#elif defined ACUTEST_HAS_POSIX_TIMER__
+ printf(" -t, --timer Measure test duration (real time)\n");
+ printf(" --timer=TIMER Measure test duration, using given timer\n");
+ printf(" (TIMER is one of 'real', 'cpu')\n");
+#endif
+ printf(" -E, --no-exec Same as --exec=never\n");
+ printf(" --no-summary Suppress printing of test results summary\n");
+ printf(" --tap Produce TAP-compliant output\n");
+ printf(" (See https://testanything.org/)\n");
+ printf(" -x, --xml-output=FILE Enable XUnit output to the given file\n");
+ printf(" -l, --list List unit tests in the suite and exit\n");
+ printf(" -v, --verbose Make output more verbose\n");
+ printf(" --verbose=LEVEL Set verbose level to LEVEL:\n");
+ printf(" 0 ... Be silent\n");
+ printf(" 1 ... Output one line per test (and summary)\n");
+ printf(" 2 ... As 1 and failed conditions (this is default)\n");
+ printf(" 3 ... As 1 and all conditions (and extended summary)\n");
+ printf(" --color[=WHEN] Enable colorized output\n");
+ printf(" (WHEN is one of 'auto', 'always', 'never')\n");
+ printf(" --no-color Same as --color=never\n");
+ printf(" -h, --help Display this help and exit\n");
+
+ if(test_list_size__ < 16) {
+ printf("\n");
+ test_list_names__();
+ }
+}
+
+static const TEST_CMDLINE_OPTION__ test_cmdline_options__[] = {
+ { 's', "skip", 's', 0 },
+ { 0, "exec", 'e', TEST_CMDLINE_OPTFLAG_OPTIONALARG__ },
+ { 'E', "no-exec", 'E', 0 },
+#if defined ACUTEST_WIN__
+ { 't', "timer", 't', 0 },
+#elif defined ACUTEST_HAS_POSIX_TIMER__
+ { 't', "timer", 't', TEST_CMDLINE_OPTFLAG_OPTIONALARG__ },
+#endif
+ { 0, "no-summary", 'S', 0 },
+ { 0, "tap", 'T', 0 },
+ { 'l', "list", 'l', 0 },
+ { 'v', "verbose", 'v', TEST_CMDLINE_OPTFLAG_OPTIONALARG__ },
+ { 0, "color", 'c', TEST_CMDLINE_OPTFLAG_OPTIONALARG__ },
+ { 0, "no-color", 'C', 0 },
+ { 'h', "help", 'h', 0 },
+ { 0, "worker", 'w', TEST_CMDLINE_OPTFLAG_REQUIREDARG__ }, /* internal */
+ { 'x', "xml-output", 'x', TEST_CMDLINE_OPTFLAG_REQUIREDARG__ },
+ { 0, NULL, 0, 0 }
+};
+
+static int
+test_cmdline_callback__(int id, const char* arg)
+{
+ switch(id) {
+ case 's':
+ test_skip_mode__ = 1;
+ break;
+
+ case 'e':
+ if(arg == NULL || strcmp(arg, "always") == 0) {
+ test_no_exec__ = 0;
+ } else if(strcmp(arg, "never") == 0) {
+ test_no_exec__ = 1;
+ } else if(strcmp(arg, "auto") == 0) {
+ /*noop*/
+ } else {
+ fprintf(stderr, "%s: Unrecognized argument '%s' for option --exec.\n", test_argv0__, arg);
+ fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__);
+ exit(2);
+ }
+ break;
+
+ case 'E':
+ test_no_exec__ = 1;
+ break;
+
+ case 't':
+#if defined ACUTEST_WIN__ || defined ACUTEST_HAS_POSIX_TIMER__
+ if(arg == NULL || strcmp(arg, "real") == 0) {
+ test_timer__ = 1;
+ #ifndef ACUTEST_WIN__
+ } else if(strcmp(arg, "cpu") == 0) {
+ test_timer__ = 2;
+ #endif
+ } else {
+ fprintf(stderr, "%s: Unrecognized argument '%s' for option --timer.\n", test_argv0__, arg);
+ fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__);
+ exit(2);
+ }
+#endif
+ break;
+
+ case 'S':
+ test_no_summary__ = 1;
+ break;
+
+ case 'T':
+ test_tap__ = 1;
+ break;
+
+ case 'l':
+ test_list_names__();
+ exit(0);
+
+ case 'v':
+ test_verbose_level__ = (arg != NULL ? atoi(arg) : test_verbose_level__+1);
+ break;
+
+ case 'c':
+ if(arg == NULL || strcmp(arg, "always") == 0) {
+ test_colorize__ = 1;
+ } else if(strcmp(arg, "never") == 0) {
+ test_colorize__ = 0;
+ } else if(strcmp(arg, "auto") == 0) {
+ /*noop*/
+ } else {
+ fprintf(stderr, "%s: Unrecognized argument '%s' for option --color.\n", test_argv0__, arg);
+ fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__);
+ exit(2);
+ }
+ break;
+
+ case 'C':
+ test_colorize__ = 0;
+ break;
+
+ case 'h':
+ test_help__();
+ exit(0);
+
+ case 'w':
+ test_worker__ = 1;
+ test_worker_index__ = atoi(arg);
+ break;
+ case 'x':
+ test_xml_output__ = fopen(arg, "w");
+ if (!test_xml_output__) {
+ fprintf(stderr, "Unable to open '%s': %s\n", arg, strerror(errno));
+ exit(2);
+ }
+ break;
+
+ case 0:
+ if(test_lookup__(arg) == 0) {
+ fprintf(stderr, "%s: Unrecognized unit test '%s'\n", test_argv0__, arg);
+ fprintf(stderr, "Try '%s --list' for list of unit tests.\n", test_argv0__);
+ exit(2);
+ }
+ break;
+
+ case TEST_CMDLINE_OPTID_UNKNOWN__:
+ fprintf(stderr, "Unrecognized command line option '%s'.\n", arg);
+ fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__);
+ exit(2);
+
+ case TEST_CMDLINE_OPTID_MISSINGARG__:
+ fprintf(stderr, "The command line option '%s' requires an argument.\n", arg);
+ fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__);
+ exit(2);
+
+ case TEST_CMDLINE_OPTID_BOGUSARG__:
+ fprintf(stderr, "The command line option '%s' does not expect an argument.\n", arg);
+ fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__);
+ exit(2);
+ }
+
+ return 0;
+}
+
+
+#ifdef ACUTEST_LINUX__
+static int
+test_is_tracer_present__(void)
+{
+ char buf[256+32+1];
+ int tracer_present = 0;
+ int fd;
+ ssize_t n_read;
+
+ fd = open("/proc/self/status", O_RDONLY);
+ if(fd == -1)
+ return 0;
+
+ n_read = read(fd, buf, sizeof(buf)-1);
+ while(n_read > 0) {
+ static const char pattern[] = "TracerPid:";
+ const char* field;
+
+ buf[n_read] = '\0';
+ field = strstr(buf, pattern);
+ if(field != NULL && field < buf + sizeof(buf) - 32) {
+ pid_t tracer_pid = (pid_t) atoi(field + sizeof(pattern) - 1);
+ tracer_present = (tracer_pid != 0);
+ break;
+ }
+
+ if(n_read == sizeof(buf)-1) {
+ memmove(buf, buf + sizeof(buf)-1 - 32, 32);
+ n_read = read(fd, buf+32, sizeof(buf)-1-32);
+ if(n_read > 0)
+ n_read += 32;
+ }
+ }
+
+ close(fd);
+ return tracer_present;
+}
+#endif
+
+int
+main(int argc, char** argv)
+{
+ int i;
+ test_argv0__ = argv[0];
+
+#if defined ACUTEST_UNIX__
+ test_colorize__ = isatty(STDOUT_FILENO);
+#elif defined ACUTEST_WIN__
+ #if defined __BORLANDC__
+ test_colorize__ = isatty(_fileno(stdout));
+ #else
+ test_colorize__ = _isatty(_fileno(stdout));
+ #endif
+#else
+ test_colorize__ = 0;
+#endif
+
+ test_timer_init__();
+
+ /* Count all test units */
+ test_list_size__ = 0;
+ for(i = 0; test_list__[i].func != NULL; i++)
+ test_list_size__++;
+
+ test_details__ = (struct test_detail__*)calloc(test_list_size__, sizeof(struct test_detail__));
+ if(test_details__ == NULL) {
+ fprintf(stderr, "Out of memory.\n");
+ exit(2);
+ }
+
+ /* Parse options */
+ test_cmdline_read__(test_cmdline_options__, argc, argv, test_cmdline_callback__);
+
+#if defined(ACUTEST_WIN__)
+ SetUnhandledExceptionFilter(test_seh_exception_filter__);
+#endif
+
+ /* By default, we want to run all tests. */
+ if(test_count__ == 0) {
+ for(i = 0; test_list__[i].func != NULL; i++)
+ test_remember__(i);
+ }
+
+ /* Guess whether we want to run unit tests as child processes. */
+ if(test_no_exec__ < 0) {
+ test_no_exec__ = 0;
+
+ if(test_count__ <= 1) {
+ test_no_exec__ = 1;
+ } else {
+#ifdef ACUTEST_WIN__
+ if(IsDebuggerPresent())
+ test_no_exec__ = 1;
+#endif
+#ifdef ACUTEST_LINUX__
+ if(test_is_tracer_present__())
+ test_no_exec__ = 1;
+#endif
+ }
+ }
+
+ if(test_tap__) {
+ /* TAP requires we know test result ("ok", "not ok") before we output
+ * anything about the test, and this gets problematic for larger verbose
+ * levels. */
+ if(test_verbose_level__ > 2)
+ test_verbose_level__ = 2;
+
+ /* TAP harness should provide some summary. */
+ test_no_summary__ = 1;
+
+ if(!test_worker__)
+ printf("1..%d\n", (int) test_count__);
+ }
+
+ int index = test_worker_index__;
+ for(i = 0; test_list__[i].func != NULL; i++) {
+ int run = (test_details__[i].flags & TEST_FLAG_RUN__);
+ if (test_skip_mode__) /* Run all tests except those listed. */
+ run = !run;
+ if(run)
+ test_run__(&test_list__[i], index++, i);
+ }
+
+ /* Write a summary */
+ if(!test_no_summary__ && test_verbose_level__ >= 1) {
+ if(test_verbose_level__ >= 3) {
+ test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Summary:\n");
+
+ printf(" Count of all unit tests: %4d\n", (int) test_list_size__);
+ printf(" Count of run unit tests: %4d\n", test_stat_run_units__);
+ printf(" Count of failed unit tests: %4d\n", test_stat_failed_units__);
+ printf(" Count of skipped unit tests: %4d\n", (int) test_list_size__ - test_stat_run_units__);
+ }
+
+ if(test_stat_failed_units__ == 0) {
+ test_print_in_color__(TEST_COLOR_GREEN_INTENSIVE__, "SUCCESS:");
+ printf(" All unit tests have passed.\n");
+ } else {
+ test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "FAILED:");
+ printf(" %d of %d unit tests %s failed.\n",
+ test_stat_failed_units__, test_stat_run_units__,
+ (test_stat_failed_units__ == 1) ? "has" : "have");
+ }
+
+ if(test_verbose_level__ >= 3)
+ printf("\n");
+ }
+
+ if (test_xml_output__) {
+#if defined ACUTEST_UNIX__
+ char *suite_name = basename(argv[0]);
+#elif defined ACUTEST_WIN__
+ char suite_name[_MAX_FNAME];
+ _splitpath(argv[0], NULL, NULL, suite_name, NULL);
+#else
+ const char *suite_name = argv[0];
+#endif
+ fprintf(test_xml_output__, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(test_xml_output__, "<testsuite name=\"%s\" tests=\"%d\" errors=\"%d\" failures=\"%d\" skip=\"%d\">\n",
+ suite_name, (int)test_list_size__, test_stat_failed_units__, test_stat_failed_units__,
+ (int)test_list_size__ - test_stat_run_units__);
+ for(i = 0; test_list__[i].func != NULL; i++) {
+ struct test_detail__ *details = &test_details__[i];
+ fprintf(test_xml_output__, " <testcase name=\"%s\" time=\"%.2f\">\n", test_list__[i].name, details->duration);
+ if (details->flags & TEST_FLAG_FAILURE__)
+ fprintf(test_xml_output__, " <failure />\n");
+ if (!(details->flags & TEST_FLAG_FAILURE__) && !(details->flags & TEST_FLAG_SUCCESS__))
+ fprintf(test_xml_output__, " <skipped />\n");
+ fprintf(test_xml_output__, " </testcase>\n");
+ }
+ fprintf(test_xml_output__, "</testsuite>\n");
+ fclose(test_xml_output__);
+ }
+
+ free((void*) test_details__);
+
+ return (test_stat_failed_units__ == 0) ? 0 : 1;
+}
+
+
+#endif /* #ifndef TEST_NO_MAIN */
+
+#ifdef __cplusplus
+ } /* extern "C" */
+#endif
+
+
+#endif /* #ifndef ACUTEST_H__ */
diff --git a/tests/aio.c b/tests/aio.c
index 9bb7de19..fdc68cb8 100644
--- a/tests/aio.c
+++ b/tests/aio.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -14,13 +14,7 @@
#include <nng/protocol/pair1/pair.h>
#include <nng/supplemental/util/platform.h>
-#include "convey.h"
-#include "stubs.h"
-
-#define APPENDSTR(m, s) nng_msg_append(m, s, strlen(s))
-#define CHECKSTR(m, s) \
- So(nng_msg_len(m) == strlen(s)); \
- So(memcmp(nng_msg_body(m), s, strlen(s)) == 0)
+#include "acutest.h"
void
cbdone(void *p)
@@ -41,164 +35,209 @@ cancelfn(nng_aio *aio, void *arg, int rv)
nng_aio_finish(aio, rv);
}
-Main({
- Test("AIO operations", {
- const char *addr = "inproc://aio";
-
- Convey("Sleep works", {
- nng_time start = 0;
- nng_time end = 0;
- nng_aio *saio;
- So(nng_aio_alloc(&saio, sleepdone, &end) == 0);
- start = nng_clock();
- nng_sleep_aio(200, saio);
- nng_aio_wait(saio);
- So(nng_aio_result(saio) == 0);
- So(end != 0);
- So((end - start) >= 200);
- So((end - start) <= 1000);
- So((nng_clock() - start) >= 200);
- So((nng_clock() - start) <= 1000);
- nng_aio_free(saio);
- });
-
- Convey("Sleep timeout works", {
- nng_time start = 0;
- nng_time end = 0;
- nng_aio *saio;
- So(nng_aio_alloc(&saio, sleepdone, &end) == 0);
- nng_aio_set_timeout(saio, 100);
- start = nng_clock();
- nng_sleep_aio(2000, saio);
- nng_aio_wait(saio);
- So(nng_aio_result(saio) == NNG_ETIMEDOUT);
- So(end != 0);
- So((end - start) >= 100);
- So((end - start) <= 1000);
- So((nng_clock() - start) >= 100);
- So((nng_clock() - start) <= 1000);
- nng_aio_free(saio);
- });
-
- Convey("Given a connected pair of sockets", {
- nng_socket s1;
- nng_socket s2;
- nng_aio * txaio;
- nng_aio * rxaio;
- int txdone = 0;
- int rxdone = 0;
- nng_msg * m;
-
- So(nng_pair1_open(&s1) == 0);
- So(nng_pair1_open(&s2) == 0);
-
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(s2, addr, NULL, 0) == 0);
-
- So(nng_aio_alloc(&rxaio, cbdone, &rxdone) == 0);
- So(nng_aio_alloc(&txaio, cbdone, &txdone) == 0);
-
- Reset({
- nng_aio_free(rxaio);
- nng_aio_free(txaio);
- nng_close(s1);
- nng_close(s2);
- });
-
- nng_aio_set_timeout(rxaio, 100);
- nng_aio_set_timeout(txaio, 100);
-
- So(nng_msg_alloc(&m, 0) == 0);
- APPENDSTR(m, "hello");
-
- nng_recv_aio(s2, rxaio);
-
- nng_aio_set_msg(txaio, m);
- nng_send_aio(s1, txaio);
-
- nng_aio_wait(txaio);
- nng_aio_wait(rxaio);
-
- So(nng_aio_result(rxaio) == 0);
- So(nng_aio_result(txaio) == 0);
-
- So((m = nng_aio_get_msg(rxaio)) != NULL);
- CHECKSTR(m, "hello");
-
- nng_msg_free(m);
-
- So(rxdone == 1);
- So(txdone == 1);
- });
-
- Convey("Failure modes work", {
- nng_socket s;
- nng_aio * a;
- int done = 0;
-
- So(nng_pair1_open(&s) == 0);
-
- So(nng_aio_alloc(&a, cbdone, &done) == 0);
-
- Reset({
- nng_aio_free(a);
- nng_close(s);
- });
-
- Convey("Explicit timeout works", {
- nng_aio_set_timeout(a, 40);
- nng_recv_aio(s, a);
- nng_aio_wait(a);
- So(done == 1);
- So(nng_aio_result(a) == NNG_ETIMEDOUT);
- });
- Convey("Default timeout works", {
- So(nng_setopt_ms(s, NNG_OPT_RECVTIMEO, 40) ==
- 0);
- nng_recv_aio(s, a);
- nng_aio_wait(a);
- So(done == 1);
- So(nng_aio_result(a) == NNG_ETIMEDOUT);
- });
- Convey("Zero timeout works", {
- nng_aio_set_timeout(a, NNG_DURATION_ZERO);
- nng_recv_aio(s, a);
- nng_aio_wait(a);
- So(done == 1);
- So(nng_aio_result(a) == NNG_ETIMEDOUT);
- });
- Convey("Cancellation works", {
- nng_aio_set_timeout(a, NNG_DURATION_INFINITE);
- nng_recv_aio(s, a);
- nng_aio_cancel(a);
- nng_aio_wait(a);
- So(done == 1);
- So(nng_aio_result(a) == NNG_ECANCELED);
- })
- });
-
- Convey("We cannot set insane IOVs", {
- nng_aio *aio;
- nng_iov iov;
-
- So(nng_aio_alloc(&aio, NULL, NULL) == 0);
- So(nng_aio_set_iov(aio, 1024, &iov) == NNG_EINVAL);
- nng_aio_free(aio);
- });
-
- Convey("Provider cancellation works", {
- nng_aio *aio;
- int rv = 0;
- // We fake an empty provider that does not do anything.
- So(nng_aio_alloc(&aio, NULL, NULL) == 0);
- So(nng_aio_begin(aio) == true);
- nng_aio_defer(aio, cancelfn, &rv);
- nng_aio_cancel(aio);
- nng_aio_wait(aio);
- So(rv == NNG_ECANCELED);
- nng_aio_free(aio);
- });
- });
-
- nng_fini();
-})
+void
+test_sleep(void)
+{
+ nng_time start = 0;
+ nng_time end = 0;
+ nng_aio *saio;
+
+ TEST_CHECK(nng_aio_alloc(&saio, sleepdone, &end) == 0);
+ start = nng_clock();
+ nng_sleep_aio(200, saio);
+ nng_aio_wait(saio);
+ TEST_CHECK(nng_aio_result(saio) == 0);
+ TEST_CHECK(end != 0);
+ TEST_CHECK((end - start) >= 200);
+ TEST_CHECK((end - start) <= 1000);
+ TEST_CHECK((nng_clock() - start) >= 200);
+ TEST_CHECK((nng_clock() - start) <= 1000);
+ nng_aio_free(saio);
+}
+
+void
+test_sleep_timeout(void)
+{
+ nng_time start = 0;
+ nng_time end = 0;
+ nng_aio *saio;
+ TEST_CHECK(nng_aio_alloc(&saio, sleepdone, &end) == 0);
+ nng_aio_set_timeout(saio, 100);
+ start = nng_clock();
+ nng_sleep_aio(2000, saio);
+ nng_aio_wait(saio);
+ TEST_CHECK(nng_aio_result(saio) == NNG_ETIMEDOUT);
+ TEST_CHECK(end != 0);
+ TEST_CHECK((end - start) >= 100);
+ TEST_CHECK((end - start) <= 1000);
+ TEST_CHECK((nng_clock() - start) >= 100);
+ TEST_CHECK((nng_clock() - start) <= 1000);
+ nng_aio_free(saio);
+}
+
+void
+test_insane_niov(void)
+{
+ nng_aio *aio;
+ nng_iov iov;
+
+ TEST_CHECK(nng_aio_alloc(&aio, NULL, NULL) == 0);
+ TEST_CHECK(nng_aio_set_iov(aio, 1024, &iov) == NNG_EINVAL);
+ nng_aio_free(aio);
+}
+
+void
+test_provider_cancel(void)
+{
+ nng_aio *aio;
+ int rv = 0;
+ // We fake an empty provider that does not do anything.
+ TEST_CHECK(nng_aio_alloc(&aio, NULL, NULL) == 0);
+ TEST_CHECK(nng_aio_begin(aio) == true);
+ nng_aio_defer(aio, cancelfn, &rv);
+ nng_aio_cancel(aio);
+ nng_aio_wait(aio);
+ TEST_CHECK(rv == NNG_ECANCELED);
+ nng_aio_free(aio);
+}
+
+void
+test_consumer_cancel(void)
+{
+ nng_aio * a;
+ nng_socket s1;
+ int done = 0;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_aio_alloc(&a, cbdone, &done) == 0);
+
+ nng_aio_set_timeout(a, NNG_DURATION_INFINITE);
+ nng_recv_aio(s1, a);
+ nng_aio_cancel(a);
+ nng_aio_wait(a);
+ TEST_CHECK(done == 1);
+ TEST_CHECK(nng_aio_result(a) == NNG_ECANCELED);
+
+ nng_aio_free(a);
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_traffic(void)
+{
+ nng_socket s1;
+ nng_socket s2;
+ nng_aio * txaio;
+ nng_aio * rxaio;
+ int txdone = 0;
+ int rxdone = 0;
+ nng_msg * m;
+ char * addr = "inproc://traffic";
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&s2) == 0);
+
+ TEST_CHECK(nng_listen(s1, addr, NULL, 0) == 0);
+ TEST_CHECK(nng_dial(s2, addr, NULL, 0) == 0);
+
+ TEST_CHECK(nng_aio_alloc(&rxaio, cbdone, &rxdone) == 0);
+ TEST_CHECK(nng_aio_alloc(&txaio, cbdone, &txdone) == 0);
+
+ nng_aio_set_timeout(rxaio, 1000);
+ nng_aio_set_timeout(txaio, 1000);
+
+ TEST_CHECK(nng_msg_alloc(&m, 0) == 0);
+ TEST_CHECK(nng_msg_append(m, "hello", strlen("hello")) == 0);
+
+ nng_recv_aio(s2, rxaio);
+
+ nng_aio_set_msg(txaio, m);
+ nng_send_aio(s1, txaio);
+
+ nng_aio_wait(txaio);
+ nng_aio_wait(rxaio);
+
+ TEST_CHECK(nng_aio_result(rxaio) == 0);
+ TEST_CHECK(nng_aio_result(txaio) == 0);
+
+ TEST_CHECK((m = nng_aio_get_msg(rxaio)) != NULL);
+ TEST_CHECK(nng_msg_len(m) == strlen("hello"));
+ TEST_CHECK(memcmp(nng_msg_body(m), "hello", strlen("hello")) == 0);
+
+ nng_msg_free(m);
+
+ TEST_CHECK(rxdone == 1);
+ TEST_CHECK(txdone == 1);
+
+ nng_aio_free(rxaio);
+ nng_aio_free(txaio);
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(s2) == 0);
+}
+
+void
+test_explicit_timeout(void)
+{
+ nng_socket s;
+ nng_aio * a;
+ int done = 0;
+
+ TEST_CHECK(nng_pair1_open(&s) == 0);
+ TEST_CHECK(nng_aio_alloc(&a, cbdone, &done) == 0);
+ nng_aio_set_timeout(a, 40);
+ nng_recv_aio(s, a);
+ nng_aio_wait(a);
+ TEST_CHECK(done == 1);
+ TEST_CHECK(nng_aio_result(a) == NNG_ETIMEDOUT);
+ nng_aio_free(a);
+ TEST_CHECK(nng_close(s) == 0);
+}
+
+void
+test_inherited_timeout(void)
+{
+ nng_socket s;
+ nng_aio * a;
+ int done = 0;
+
+ TEST_CHECK(nng_pair1_open(&s) == 0);
+ TEST_CHECK(nng_aio_alloc(&a, cbdone, &done) == 0);
+ TEST_CHECK(nng_setopt_ms(s, NNG_OPT_RECVTIMEO, 40) == 0);
+ nng_recv_aio(s, a);
+ nng_aio_wait(a);
+ TEST_CHECK(done == 1);
+ TEST_CHECK(nng_aio_result(a) == NNG_ETIMEDOUT);
+ nng_aio_free(a);
+ TEST_CHECK(nng_close(s) == 0);
+}
+
+void
+test_zero_timeout(void)
+{
+ nng_socket s;
+ nng_aio * a;
+ int done = 0;
+
+ TEST_CHECK(nng_pair1_open(&s) == 0);
+ TEST_CHECK(nng_aio_alloc(&a, cbdone, &done) == 0);
+ nng_aio_set_timeout(a, NNG_DURATION_ZERO);
+ nng_recv_aio(s, a);
+ nng_aio_wait(a);
+ TEST_CHECK(done == 1);
+ TEST_CHECK(nng_aio_result(a) == NNG_ETIMEDOUT);
+ nng_aio_free(a);
+ TEST_CHECK(nng_close(s) == 0);
+}
+
+TEST_LIST = {
+ { "sleep", test_sleep },
+ { "sleep timeout", test_sleep_timeout },
+ { "insane niov", test_insane_niov },
+ { "provider cancel", test_provider_cancel },
+ { "consumer cancel", test_consumer_cancel },
+ { "traffic", test_traffic },
+ { "explicit timeout", test_explicit_timeout },
+ { "inherited timeout", test_inherited_timeout },
+ { "zero timeout", test_zero_timeout },
+ { NULL, NULL },
+}; \ No newline at end of file
diff --git a/tests/base64.c b/tests/base64.c
deleted file mode 100644
index 1781c5ef..00000000
--- a/tests/base64.c
+++ /dev/null
@@ -1,84 +0,0 @@
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This software is supplied under the terms of the MIT License, a
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-#include <string.h>
-#include <nng/nng.h>
-
-#include "convey.h"
-#include "supplemental/base64/base64.h"
-
-typedef struct testcase {
- char *decoded;
- char *encoded;
-} testcase;
-
-static struct testcase cases[] = {
- // clang-format off
- { "", "" },
- { "f", "Zg==" },
- { "fo", "Zm8=" },
- { "foo", "Zm9v" },
- { "foob", "Zm9vYg==" },
- { "fooba", "Zm9vYmE=" },
- { "foobar", "Zm9vYmFy" },
- { NULL, NULL }
- // clang-format on
-};
-
-TestMain("Base64 Verification", {
-
- Convey("Encode Works", {
- int rv;
- char buf[1024];
- int i;
- void *dec;
-
- for (i = 0; (dec = cases[i].decoded) != NULL; i++) {
- rv = nni_base64_encode(dec, strlen(dec), buf, 1024);
- So(rv >= 0);
- So(rv == (int) strlen(cases[i].encoded));
- buf[rv] = 0;
- So(strcmp(buf, cases[i].encoded) == 0);
- }
- });
-
- Convey("Decode Works", {
- int rv;
- char buf[1024];
- int i;
- void *enc;
-
- for (i = 0; (enc = cases[i].encoded) != NULL; i++) {
- rv = nni_base64_decode(
- enc, strlen(enc), (void *) buf, 1024);
- So(rv >= 0);
- So(rv == (int) strlen(cases[i].decoded));
- buf[rv] = 0;
- So(strcmp(buf, cases[i].decoded) == 0);
- }
- });
-
- Convey("Overflow Works", {
- char tmp[1024];
- for (int i = 1; cases[i].decoded != NULL; i++) {
- void *enc = cases[i].encoded;
- void *dec = cases[i].decoded;
- void *buf = tmp;
-
- So(nni_base64_encode(
- dec, strlen(dec), buf, strlen(enc) - 1) == -1);
- So(nni_base64_encode(dec, strlen(dec), buf, 0) == -1);
-
- So(nni_base64_decode(
- enc, strlen(enc), buf, strlen(dec) - 1) == -1);
- So(nni_base64_encode(enc, strlen(enc), buf, 0) == -1);
- }
- })
-})
diff --git a/tests/bufsz.c b/tests/bufsz.c
index da6a14cb..4f62905d 100644
--- a/tests/bufsz.c
+++ b/tests/bufsz.c
@@ -8,97 +8,109 @@
// found online at https://opensource.org/licenses/MIT.
//
-#include <string.h>
-
-#include <nng/compat/nanomsg/nn.h>
#include <nng/nng.h>
-#include <nng/protocol/pubsub0/sub.h>
#include <nng/protocol/pair1/pair.h>
#include <nng/supplemental/util/platform.h>
-#include "trantest.h"
-#include "convey.h"
-#include "stubs.h"
-
-#define SECONDS(x) ((x) *1000)
-
-TestMain("Buffer Options", {
-
- atexit(nng_fini);
-
- Convey("We are able to open a PAIR socket", {
- nng_socket s1;
-
- So(nng_pair_open(&s1) == 0);
-
- Reset({ nng_close(s1); });
-
- Convey("Set/Get Recv Buf Option", {
- int cnt;
- So(nng_setopt_int(s1, NNG_OPT_RECVBUF, 10) == 0);
- So(nng_getopt_int(s1, NNG_OPT_RECVBUF, &cnt) == 0);
- So(cnt == 10);
- So(nng_setopt_size(s1, NNG_OPT_RECVBUF, 42) ==
- NNG_EBADTYPE);
-
- });
- Convey("Set/Get Send Buf Option", {
- int cnt;
- So(nng_setopt_int(s1, NNG_OPT_SENDBUF, 10) == 0);
- So(nng_getopt_int(s1, NNG_OPT_SENDBUF, &cnt) == 0);
- So(cnt == 10);
- So(nng_setopt_size(s1, NNG_OPT_SENDBUF, 42) ==
- NNG_EBADTYPE);
-
- });
-
- // NOTE: We are going to use the compat mode, but
- // this assumes that the socket is the same between compat
- // and current mode. This is true, but normal applications
- // MUST NOT assume this. We only do so for testing.
- Convey("Legacy Recv Buf Option", {
- int cnt;
- int os = (int) s1.id;
- size_t sz = sizeof(cnt);
- So(nng_setopt_int(s1, NNG_OPT_RECVBUF, 10) == 0);
- So(nn_getsockopt(
- os, NN_SOL_SOCKET, NN_RCVBUF, &cnt, &sz) == 0);
- So(cnt == 10240);
- cnt = 1;
- So(nn_setsockopt(
- os, NN_SOL_SOCKET, NN_RCVBUF, &cnt, sz) == 0);
- So(nn_getsockopt(
- os, NN_SOL_SOCKET, NN_RCVBUF, &cnt, &sz) == 0);
- So(cnt == 1024); // round up!
- So(nng_getopt_int(s1, NNG_OPT_RECVBUF, &cnt) == 0);
- So(cnt == 1);
-
- So(nn_setsockopt(
- os, NN_SOL_SOCKET, NN_RCVBUF, &cnt, 100) == -1);
- So(nn_errno() == EINVAL);
- });
- Convey("Legacy Send Buf Option", {
- int cnt;
- int os = (int) s1.id;
- size_t sz = sizeof(cnt);
- So(nng_setopt_int(s1, NNG_OPT_SENDBUF, 10) == 0);
- So(nn_getsockopt(
- os, NN_SOL_SOCKET, NN_SNDBUF, &cnt, &sz) == 0);
- So(cnt == 10240);
- cnt = 1;
- So(nn_setsockopt(
- os, NN_SOL_SOCKET, NN_SNDBUF, &cnt, sz) == 0);
- So(nn_getsockopt(
- os, NN_SOL_SOCKET, NN_SNDBUF, &cnt, &sz) == 0);
- So(cnt == 1024); // round up!
- So(nng_getopt_int(s1, NNG_OPT_SENDBUF, &cnt) == 0);
- So(cnt == 1);
-
- So(nn_setsockopt(
- os, NN_SOL_SOCKET, NN_SNDBUF, &cnt, 100) == -1);
- So(nn_errno() == EINVAL);
- });
-
- });
-})
+#include <nng/compat/nanomsg/nn.h>
+
+#include "acutest.h"
+
+void
+test_buffer_options(void)
+{
+ nng_socket s1;
+ int val;
+ size_t sz;
+ char * opt;
+
+ char *cases[] = {
+ NNG_OPT_RECVBUF,
+ NNG_OPT_SENDBUF,
+ NULL,
+ };
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ for (int i = 0; (opt = cases[i]) != NULL; i++) {
+
+ TEST_CASE(opt);
+
+ // Can't receive a size into zero bytes.
+ sz = 0;
+ TEST_CHECK(nng_getopt(s1, opt, &val, &sz) == NNG_EINVAL);
+
+ // Can set a valid size
+ TEST_CHECK(nng_setopt_int(s1, opt, 1234) == 0);
+ TEST_CHECK(nng_getopt_int(s1, opt, &val) == 0);
+ TEST_CHECK(val == 1234);
+
+ val = 0;
+ sz = sizeof(val);
+ TEST_CHECK(nng_getopt(s1, opt, &val, &sz) == 0);
+ TEST_CHECK(val == 1234);
+ TEST_CHECK(sz == sizeof(val));
+
+ // Can't set a negative size
+ TEST_CHECK(nng_setopt_int(s1, opt, -5) == NNG_EINVAL);
+
+ // Can't pass a buf too small for size
+ sz = sizeof(val) - 1;
+ val = 1;
+ TEST_CHECK(nng_setopt(s1, opt, &val, sz) == NNG_EINVAL);
+ // Buffer sizes are limited to sane levels
+ TEST_CHECK(nng_setopt_int(s1, opt, 0x100000) == NNG_EINVAL);
+ }
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_buffer_legacy(void)
+{
+ nng_socket s1;
+ char * opt;
+
+ char *cases[] = {
+ NNG_OPT_RECVBUF,
+ NNG_OPT_SENDBUF,
+ NULL,
+ };
+ int legacy[] = {
+ NN_RCVBUF,
+ NN_SNDBUF,
+ };
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ for (int i = 0; (opt = cases[i]) != NULL; i++) {
+ int cnt;
+ int os = (int) s1.id;
+ size_t sz;
+ int nnopt = legacy[i];
+
+ TEST_CASE(opt);
+
+ sz = sizeof(cnt);
+ TEST_CHECK(nng_setopt_int(s1, opt, 10) == 0);
+ TEST_CHECK(
+ nn_getsockopt(os, NN_SOL_SOCKET, nnopt, &cnt, &sz) == 0);
+ TEST_CHECK(cnt == 10240); // 1k multiple
+
+ cnt = 1;
+ TEST_CHECK(
+ nn_setsockopt(os, NN_SOL_SOCKET, nnopt, &cnt, sz) == 0);
+ TEST_CHECK(nn_getsockopt(os, NN_SOL_SOCKET, nnopt, &cnt, &sz) == 0);
+ TEST_CHECK(cnt == 1024); // round up!
+ TEST_CHECK(nng_getopt_int(s1, opt, &cnt) == 0);
+ TEST_CHECK(cnt == 1);
+
+ TEST_CHECK(nn_setsockopt(os, NN_SOL_SOCKET, nnopt, &cnt, 100) == -1);
+ TEST_CHECK(nn_errno() == EINVAL);
+ }
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+TEST_LIST = {
+ { "buffer options", test_buffer_options },
+ { "buffer legacy", test_buffer_legacy },
+ { NULL, NULL },
+};
diff --git a/tests/pair1.c b/tests/pair1.c
deleted file mode 100644
index f55ea08a..00000000
--- a/tests/pair1.c
+++ /dev/null
@@ -1,541 +0,0 @@
-//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
-//
-// This software is supplied under the terms of the MIT License, a
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-#include <string.h>
-
-#include <nng/nng.h>
-#include <nng/protocol/pair1/pair.h>
-
-#include "convey.h"
-#include "stubs.h"
-#include "trantest.h"
-
-#define SECOND(x) ((x) *1000)
-#define MILLISECOND(x) (x)
-
-#define APPENDSTR(m, s) nng_msg_append(m, s, strlen(s))
-#define CHECKSTR(m, s) \
- So(nng_msg_len(m) == strlen(s)); \
- So(memcmp(nng_msg_body(m), s, strlen(s)) == 0)
-
-TestMain("PAIRv1 protocol", {
- const char * templ = "inproc://pairv1/%u";
- char addr[NNG_MAXADDRLEN + 1];
- nng_socket s1 = NNG_SOCKET_INITIALIZER;
- nng_socket c1 = NNG_SOCKET_INITIALIZER;
- nng_socket c2 = NNG_SOCKET_INITIALIZER;
- nng_duration tmo;
- uint32_t v;
- size_t sz;
-
- atexit(nng_fini);
-
- Convey("Given a few sockets", {
- trantest_next_address(addr, templ);
- So(nng_pair1_open(&s1) == 0);
- So(nng_pair1_open(&c1) == 0);
- So(nng_pair1_open(&c2) == 0);
-
- So(nng_socket_id(s1) > 0);
- So(nng_socket_id(c1) > 0);
- So(nng_socket_id(c2) > 0);
- So(nng_socket_id(s1) != nng_socket_id(c1));
- So(nng_socket_id(s1) != nng_socket_id(c2));
- So(nng_socket_id(c1) != nng_socket_id(c2));
-
- Reset({
- nng_close(s1);
- nng_close(c1);
- nng_close(c2);
- });
-
- tmo = MILLISECOND(300);
- So(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, tmo) == 0);
- So(nng_setopt_ms(c1, NNG_OPT_RECVTIMEO, tmo) == 0);
- So(nng_setopt_ms(c2, NNG_OPT_RECVTIMEO, tmo) == 0);
- tmo = 0;
- So(nng_getopt_ms(s1, NNG_OPT_RECVTIMEO, &tmo) == 0);
- So(tmo == MILLISECOND(300));
-
- Convey("Monogamous cooked mode works", {
- nng_msg *msg;
-
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(c1, addr, NULL, 0) == 0);
- nng_msleep(20);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "ALPHA");
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- CHECKSTR(msg, "ALPHA");
- nng_msg_free(msg);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "BETA");
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c1, &msg, 0) == 0);
- CHECKSTR(msg, "BETA");
- nng_msg_free(msg);
- });
-
- Convey("Monogamous mode ignores new conns", {
- nng_msg *msg;
-
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(c1, addr, NULL, 0) == 0);
- nng_msleep(100);
- So(nng_dial(c2, addr, NULL, 0) == 0);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "ONE");
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- CHECKSTR(msg, "ONE");
- nng_msg_free(msg);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "TWO");
- So(nng_sendmsg(c2, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
- });
-
- Convey("Cannot set raw mode after connect", {
- So(nng_setopt_bool(s1, NNG_OPT_RAW, true) ==
- NNG_EREADONLY);
- });
-
- Convey("Polyamorous mode is best effort", {
- int rv;
- int i;
- nng_msg * msg;
- nng_duration to = MILLISECOND(100);
-
- So(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == 0);
-
- So(nng_setopt_int(s1, NNG_OPT_RECVBUF, 1) == 0);
- So(nng_setopt_int(s1, NNG_OPT_SENDBUF, 1) == 0);
- So(nng_setopt_int(c1, NNG_OPT_RECVBUF, 1) == 0);
- So(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, to) == 0);
-
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(c1, addr, NULL, 0) == 0);
- nng_msleep(20);
-
- for (i = 0, rv = 0; i < 10; i++) {
- So(nng_msg_alloc(&msg, 0) == 0);
- if ((rv = nng_sendmsg(s1, msg, 0)) != 0) {
- nng_msg_free(msg);
- break;
- }
- }
- So(rv == 0);
- So(i == 10);
- });
-
- Convey("Monogamous mode exerts backpressure", {
- int i;
- int rv;
- nng_msg * msg;
- nng_duration to = MILLISECOND(30);
-
- So(nng_setopt_int(s1, NNG_OPT_RECVBUF, 1) == 0);
- So(nng_setopt_int(s1, NNG_OPT_SENDBUF, 1) == 0);
- So(nng_setopt_int(c1, NNG_OPT_RECVBUF, 1) == 0);
- So(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, to) == 0);
-
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(c1, addr, NULL, 0) == 0);
- nng_msleep(20);
-
- // We choose to allow some buffering. In reality the
- // buffer size is just 1, and we will fail after 2.
- for (i = 0, rv = 0; i < 10; i++) {
- So(nng_msg_alloc(&msg, 0) == 0);
- if ((rv = nng_sendmsg(s1, msg, 0)) != 0) {
- nng_msg_free(msg);
- break;
- }
- }
- So(rv == NNG_ETIMEDOUT);
- So(i < 10);
- });
-
- Convey("Cannot set polyamorous mode after connect", {
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(c1, addr, NULL, 0) == 0);
- nng_msleep(100);
-
- So(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) ==
- NNG_ESTATE);
- });
-
- Convey("We cannot set insane TTLs", {
- int ttl;
-
- ttl = 0;
- So(nng_setopt_int(s1, NNG_OPT_MAXTTL, 0) ==
- NNG_EINVAL);
-
- So(nng_setopt_int(s1, NNG_OPT_MAXTTL, 1000) ==
- NNG_EINVAL);
-
- sz = 1;
- ttl = 8;
- So(nng_setopt(s1, NNG_OPT_MAXTTL, &ttl, sz) ==
- NNG_EINVAL);
- });
-
- Convey("Polyamorous cooked mode works", {
- nng_msg *msg;
- bool v;
- nng_pipe p1;
- nng_pipe p2;
-
- So(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
- So(v == false);
-
- So(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == 0);
- So(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
- So(v == true);
-
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(c1, addr, NULL, 0) == 0);
- So(nng_dial(c2, addr, NULL, 0) == 0);
- nng_msleep(20);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "ONE");
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- CHECKSTR(msg, "ONE");
- p1 = nng_msg_get_pipe(msg);
- So(nng_pipe_id(p1) > 0);
- nng_msg_free(msg);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "TWO");
- So(nng_sendmsg(c2, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- CHECKSTR(msg, "TWO");
- p2 = nng_msg_get_pipe(msg);
- So(nng_pipe_id(p2) > 0);
- nng_msg_free(msg);
-
- So(nng_pipe_id(p1) != nng_pipe_id(p2));
-
- So(nng_msg_alloc(&msg, 0) == 0);
-
- nng_msg_set_pipe(msg, p1);
- APPENDSTR(msg, "UNO");
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c1, &msg, 0) == 0);
- CHECKSTR(msg, "UNO");
- nng_msg_free(msg);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- nng_msg_set_pipe(msg, p2);
- APPENDSTR(msg, "DOS");
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c2, &msg, 0) == 0);
- CHECKSTR(msg, "DOS");
- nng_msg_free(msg);
-
- nng_close(c1);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- nng_msg_set_pipe(msg, p1);
- APPENDSTR(msg, "EIN");
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c2, &msg, 0) == NNG_ETIMEDOUT);
- });
-
- Convey("Polyamorous default works", {
- nng_msg *msg;
-
- So(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == 0);
-
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(c1, addr, NULL, 0) == 0);
- nng_msleep(100);
- So(nng_dial(c2, addr, NULL, 0) == 0);
- nng_msleep(20);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "YES");
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c1, &msg, 0) == 0);
- CHECKSTR(msg, "YES");
- nng_msg_free(msg);
-
- nng_close(c1);
- nng_msleep(10);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "AGAIN");
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c2, &msg, 0) == 0);
- CHECKSTR(msg, "AGAIN");
- nng_msg_free(msg);
- });
- });
-
- Convey("Monogamous raw mode works", {
- nng_msg *msg;
- uint32_t hops;
-
- So(nng_pair1_open_raw(&s1) == 0);
- So(nng_pair1_open_raw(&c1) == 0);
- So(nng_pair1_open_raw(&c2) == 0);
-
- Reset({
- nng_close(s1);
- nng_close(c1);
- nng_close(c2);
- });
-
- tmo = MILLISECOND(300);
- So(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, tmo) == 0);
- So(nng_setopt_ms(c1, NNG_OPT_RECVTIMEO, tmo) == 0);
- So(nng_setopt_ms(c2, NNG_OPT_RECVTIMEO, tmo) == 0);
- tmo = 0;
- So(nng_getopt_ms(s1, NNG_OPT_RECVTIMEO, &tmo) == 0);
- So(tmo == MILLISECOND(300));
-
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(c1, addr, NULL, 0) == 0);
- nng_msleep(20);
-
- Convey("Send/recv work", {
- nng_pipe p = NNG_PIPE_INITIALIZER;
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "GAMMA");
- So(nng_msg_header_append_u32(msg, 1) == 0);
- So(nng_msg_header_len(msg) == sizeof(uint32_t));
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- p = nng_msg_get_pipe(msg);
- So(nng_pipe_id(p) > 0);
-
- CHECKSTR(msg, "GAMMA");
- So(nng_msg_header_len(msg) == sizeof(uint32_t));
- So(nng_msg_header_trim_u32(msg, &hops) == 0);
- So(hops == 2);
- nng_msg_free(msg);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "EPSILON");
- So(nng_msg_header_append_u32(msg, 1) == 0);
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c1, &msg, 0) == 0);
- CHECKSTR(msg, "EPSILON");
- So(nng_msg_header_len(msg) == sizeof(uint32_t));
- So(nng_msg_header_trim_u32(msg, &hops) == 0);
- p = nng_msg_get_pipe(msg);
- So(nng_pipe_id(p) > 0);
-
- So(hops == 2);
- nng_msg_free(msg);
- });
-
- Convey("Missing raw header fails", {
- So(nng_msg_alloc(&msg, 0) == 0);
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- So(nng_msg_append_u32(msg, 0xFEEDFACE) == 0);
- So(nng_msg_header_append_u32(msg, 1) == 0);
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- So(nng_msg_trim_u32(msg, &v) == 0);
- So(v == 0xFEEDFACE);
- nng_msg_free(msg);
- });
-
- Convey("Reserved bits in raw header", {
- Convey("Nonzero bits fail", {
- So(nng_msg_alloc(&msg, 0) == 0);
- So(nng_msg_header_append_u32(
- msg, 0xDEAD0000) == 0);
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
- });
- Convey("Zero bits pass", {
- So(nng_msg_alloc(&msg, 0) == 0);
- So(nng_msg_append_u32(msg, 0xFEEDFACE) == 0);
- So(nng_msg_header_append_u32(msg, 1) == 0);
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- So(nng_msg_trim_u32(msg, &v) == 0);
- So(v == 0xFEEDFACE);
- nng_msg_free(msg);
- });
- });
-
- Convey("TTL is honored", {
- int ttl;
-
- So(nng_setopt_int(s1, NNG_OPT_MAXTTL, 4) == 0);
- So(nng_getopt_int(s1, NNG_OPT_MAXTTL, &ttl) == 0);
- So(ttl == 4);
- Convey("Bad TTL bounces", {
- So(nng_msg_alloc(&msg, 0) == 0);
- So(nng_msg_header_append_u32(msg, 4) == 0);
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
- });
- Convey("Good TTL passes", {
- So(nng_msg_alloc(&msg, 0) == 0);
- So(nng_msg_append_u32(msg, 0xFEEDFACE) == 0);
- So(nng_msg_header_append_u32(msg, 3) == 0);
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- So(nng_msg_trim_u32(msg, &v) == 0);
- So(v == 0xFEEDFACE);
- So(nng_msg_header_trim_u32(msg, &v) == 0);
- So(v == 4);
- nng_msg_free(msg);
- });
-
- Convey("Large TTL passes", {
- ttl = 0xff;
- So(nng_setopt_int(s1, NNG_OPT_MAXTTL, 0xff) ==
- 0);
- So(nng_msg_alloc(&msg, 0) == 0);
- So(nng_msg_append_u32(msg, 1234) == 0);
- So(nng_msg_header_append_u32(msg, 0xfe) == 0);
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- So(nng_msg_trim_u32(msg, &v) == 0);
- So(v == 1234);
- So(nng_msg_header_trim_u32(msg, &v) == 0);
- So(v == 0xff);
- nng_msg_free(msg);
- });
-
- Convey("Max TTL fails", {
- ttl = 0xff;
- So(nng_setopt_int(s1, NNG_OPT_MAXTTL, 0xff) ==
- 0);
- So(nng_msg_alloc(&msg, 0) == 0);
- So(nng_msg_header_append_u32(msg, 0xff) == 0);
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
- });
- });
- });
-
- Convey("Polyamorous raw mode works", {
- nng_msg *msg;
- bool v;
- uint32_t hops;
- nng_pipe p1;
- nng_pipe p2;
-
- So(nng_pair1_open_raw(&s1) == 0);
- So(nng_pair1_open(&c1) == 0);
- So(nng_pair1_open(&c2) == 0);
-
- Reset({
- nng_close(s1);
- nng_close(c1);
- nng_close(c2);
- });
-
- tmo = MILLISECOND(300);
- So(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, tmo) == 0);
- So(nng_setopt_ms(c1, NNG_OPT_RECVTIMEO, tmo) == 0);
- So(nng_setopt_ms(c2, NNG_OPT_RECVTIMEO, tmo) == 0);
- tmo = 0;
- So(nng_getopt_ms(s1, NNG_OPT_RECVTIMEO, &tmo) == 0);
- So(tmo == MILLISECOND(300));
-
- So(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
- So(v == 0);
-
- So(nng_setopt_bool(s1, NNG_OPT_PAIR1_POLY, true) == 0);
- So(nng_getopt_bool(s1, NNG_OPT_PAIR1_POLY, &v) == 0);
- So(v == true);
-
- v = false;
- So(nng_getopt_bool(s1, NNG_OPT_RAW, &v) == 0);
- So(v == true);
-
- So(nng_listen(s1, addr, NULL, 0) == 0);
- So(nng_dial(c1, addr, NULL, 0) == 0);
- So(nng_dial(c2, addr, NULL, 0) == 0);
- nng_msleep(20);
-
- Convey("Send/recv works", {
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "ONE");
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- CHECKSTR(msg, "ONE");
- p1 = nng_msg_get_pipe(msg);
- So(nng_pipe_id(p1) > 0);
- So(nng_msg_header_trim_u32(msg, &hops) == 0);
- So(hops == 1);
- nng_msg_free(msg);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "TWO");
- So(nng_sendmsg(c2, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- CHECKSTR(msg, "TWO");
- p2 = nng_msg_get_pipe(msg);
- So(nng_pipe_id(p2) > 0);
- So(nng_msg_header_trim_u32(msg, &hops) == 0);
- So(hops == 1);
- nng_msg_free(msg);
-
- So(nng_pipe_id(p1) != nng_pipe_id(p2));
-
- So(nng_msg_alloc(&msg, 0) == 0);
- nng_msg_set_pipe(msg, p1);
- APPENDSTR(msg, "UNO");
- So(nng_msg_header_append_u32(msg, 1) == 0);
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c1, &msg, 0) == 0);
- CHECKSTR(msg, "UNO");
- nng_msg_free(msg);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- nng_msg_set_pipe(msg, p2);
- APPENDSTR(msg, "DOS");
- So(nng_msg_header_append_u32(msg, 1) == 0);
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c2, &msg, 0) == 0);
- CHECKSTR(msg, "DOS");
- nng_msg_free(msg);
- });
-
- Convey("Closed pipes don't work", {
- So(nng_msg_alloc(&msg, 0) == 0);
- APPENDSTR(msg, "ONE");
- So(nng_sendmsg(c1, msg, 0) == 0);
- So(nng_recvmsg(s1, &msg, 0) == 0);
- CHECKSTR(msg, "ONE");
- p1 = nng_msg_get_pipe(msg);
- So(nng_pipe_id(p1) > 0);
- nng_msg_free(msg);
-
- nng_close(c1);
-
- So(nng_msg_alloc(&msg, 0) == 0);
- nng_msg_set_pipe(msg, p1);
- APPENDSTR(msg, "EIN");
- So(nng_msg_header_append_u32(msg, 1) == 0);
- So(nng_sendmsg(s1, msg, 0) == 0);
- So(nng_recvmsg(c2, &msg, 0) == NNG_ETIMEDOUT);
- });
- });
-})
diff --git a/tests/platform.c b/tests/platform.c
index 7af18029..7546fa7f 100644
--- a/tests/platform.c
+++ b/tests/platform.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -8,11 +8,12 @@
// found online at https://opensource.org/licenses/MIT.
//
+#include "testutil.h"
+
#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>
-#include "convey.h"
-#include "stubs.h"
+#include "acutest.h"
struct addarg {
int cnt;
@@ -31,84 +32,116 @@ add(void *arg)
nng_mtx_unlock(aa->mx);
}
-TestMain("Platform Operations", {
- // This is required for anything else to work
- Convey("The clock works", {
- uint64_t now = getms();
-
- Convey("usleep works", {
- nng_msleep(100);
-
- So((getms() - now) >= 100); // cannot be *shorter*!!
- So((getms() - now) < 200); // crummy clock resolution?
- });
- Convey("times work", {
- uint64_t msend;
- int usdelta;
- int msdelta;
- nng_time usend;
- nng_time usnow = nng_clock();
- nng_msleep(200);
- usend = nng_clock();
- msend = getms();
-
- So(usend > usnow);
- So(msend > now);
- usdelta = (int) (usend - usnow);
- msdelta = (int) (msend - now);
- So(usdelta >= 200);
- So(usdelta < 250); // increased tolerance for CIs
- So(abs(msdelta - usdelta) < 50);
- });
- });
- Convey("Mutexes work", {
- static nng_mtx *mx;
-
- So(nng_mtx_alloc(&mx) == 0);
- Reset({ nng_mtx_free(mx); });
-
- Convey("We can lock and unlock mutex", {
- nng_mtx_lock(mx);
- So(1);
- nng_mtx_unlock(mx);
- So(1);
- Convey("And then lock it again", {
- nng_mtx_lock(mx);
- So(1);
- nng_mtx_unlock(mx);
- So(1);
- });
- });
- });
-
- Convey("Threads work", {
- static nng_thread *thr;
- int rv;
- struct addarg aa;
-
- So(nng_mtx_alloc(&aa.mx) == 0);
- So(nng_cv_alloc(&aa.cv, aa.mx) == 0);
- Reset({
- nng_mtx_free(aa.mx);
- nng_cv_free(aa.cv);
- });
- aa.cnt = 0;
-
- Convey("We can create threads", {
- rv = nng_thread_create(&thr, add, &aa);
- So(rv == 0);
-
- Reset({ nng_thread_destroy(thr); });
-
- Convey("It ran", {
- int val;
- nng_mtx_lock(aa.mx);
- while ((val = aa.cnt) == 0) {
- nng_cv_wait(aa.cv);
- }
- nng_mtx_unlock(aa.mx);
- So(val == 1);
- });
- });
- });
-})
+void
+test_sleep(void)
+{
+ uint64_t start, end;
+ start = testutil_clock();
+ nng_msleep(100);
+ end = testutil_clock();
+ TEST_CHECK((end - start) >= 100);
+ TEST_CHECK((end - start) <= 500);
+}
+
+void
+test_clock(void)
+{
+ uint64_t mstart;
+ uint64_t msend;
+ uint64_t usdelta;
+ uint64_t msdelta;
+ nng_time usend;
+ nng_time usnow;
+
+ mstart = testutil_clock();
+ usnow = nng_clock();
+ nng_msleep(200);
+ usend = nng_clock();
+ msend = testutil_clock();
+
+ TEST_CHECK(usend > usnow);
+ TEST_CHECK(msend > mstart);
+ usdelta = usend - usnow;
+ msdelta = msend - mstart;
+ TEST_CHECK(usdelta >= 200);
+ TEST_CHECK(usdelta < 500); // increased tolerance for CIs
+ if (msdelta > usdelta) {
+ TEST_CHECK((msdelta - usdelta) < 50);
+ } else {
+ TEST_CHECK((usdelta - msdelta) < 50);
+ }
+}
+
+void
+test_mutex(void)
+{
+ nng_mtx *mx, *mx2;
+
+ TEST_CHECK(nng_mtx_alloc(&mx) == 0);
+ nng_mtx_lock(mx);
+ nng_mtx_unlock(mx);
+
+ nng_mtx_lock(mx);
+ nng_mtx_unlock(mx);
+ nng_mtx_free(mx);
+
+ // Verify that the mutexes are not always the same!
+ TEST_CHECK(nng_mtx_alloc(&mx) == 0);
+ TEST_CHECK(nng_mtx_alloc(&mx2) == 0);
+ TEST_CHECK(mx != mx2);
+ nng_mtx_free(mx);
+ nng_mtx_free(mx2);
+}
+
+void
+test_thread(void)
+{
+ nng_thread * thr;
+ int rv;
+ struct addarg aa;
+
+ TEST_CHECK(nng_mtx_alloc(&aa.mx) == 0);
+ TEST_CHECK(nng_cv_alloc(&aa.cv, aa.mx) == 0);
+ aa.cnt = 0;
+
+ TEST_CHECK((rv = nng_thread_create(&thr, add, &aa)) == 0);
+ nng_thread_destroy(thr);
+ TEST_CHECK(aa.cnt == 1);
+
+ nng_cv_free(aa.cv);
+ nng_mtx_free(aa.mx);
+}
+
+void
+test_condvar(void)
+{
+ nng_thread * thr;
+ int rv;
+ struct addarg aa;
+
+ TEST_CHECK(nng_mtx_alloc(&aa.mx) == 0);
+ TEST_CHECK(nng_cv_alloc(&aa.cv, aa.mx) == 0);
+ aa.cnt = 0;
+
+ TEST_CHECK((rv = nng_thread_create(&thr, add, &aa)) == 0);
+
+ nng_mtx_lock(aa.mx);
+ while (aa.cnt == 0) {
+ nng_cv_wait(aa.cv);
+ }
+ nng_mtx_unlock(aa.mx);
+ nng_thread_destroy(thr);
+ TEST_CHECK(aa.cnt == 1);
+
+ nng_cv_free(aa.cv);
+ nng_mtx_free(aa.mx);
+}
+
+TEST_LIST = {
+ { "sleep", test_sleep },
+ { "clock", test_clock },
+ { "mutex", test_mutex },
+ { "thread", test_thread },
+ { "condvar", test_condvar },
+ { NULL, NULL },
+};
diff --git a/tests/reqrep.c b/tests/reqrep.c
deleted file mode 100644
index 526891ca..00000000
--- a/tests/reqrep.c
+++ /dev/null
@@ -1,289 +0,0 @@
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This software is supplied under the terms of the MIT License, a
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-#include <string.h>
-
-#include <nng/nng.h>
-#include <nng/protocol/reqrep0/rep.h>
-#include <nng/protocol/reqrep0/req.h>
-#include <nng/supplemental/util/platform.h>
-
-#include "convey.h"
-#include "stubs.h"
-
-TestMain("REQ/REP pattern", {
- int rv;
- const char *addr = "inproc://test";
- Convey("We can create a REQ socket", {
- nng_socket req;
-
- So(nng_req_open(&req) == 0);
-
- Reset({ nng_close(req); });
-
- Convey("Protocol & peer options match", {
- int p;
- char *s;
- So(nng_getopt_int(req, NNG_OPT_PROTO, &p) == 0);
- So(p == 48);
- So(nng_getopt_string(req, NNG_OPT_PROTONAME, &s) == 0);
- So(strcmp(s, "req") == 0);
- nng_strfree(s);
- So(nng_getopt_int(req, NNG_OPT_PEER, &p) == 0);
- So(p == 49);
- So(nng_getopt_string(req, NNG_OPT_PEERNAME, &s) == 0);
- So(strcmp(s, "rep") == 0);
- nng_strfree(s);
- });
-
- Convey("Resend time option id works", {
- // Set timeout.
- So(nng_setopt_ms(req, NNG_OPT_REQ_RESENDTIME, 10) ==
- 0);
- // Check invalid size
- So(nng_setopt(req, NNG_OPT_REQ_RESENDTIME, "", 1) ==
- NNG_EINVAL);
- });
-
- Convey("Recv with no send fails", {
- nng_msg *msg;
- rv = nng_recvmsg(req, &msg, 0);
- So(rv == NNG_ESTATE);
- });
- });
-
- Convey("We can create a REP socket", {
- nng_socket rep;
- So(nng_rep_open(&rep) == 0);
-
- Reset({ nng_close(rep); });
-
- Convey("Protocol & peer options match", {
- int p;
- char *s;
- So(nng_getopt_int(rep, NNG_OPT_PROTO, &p) == 0);
- So(p == 49);
- So(nng_getopt_string(rep, NNG_OPT_PROTONAME, &s) == 0);
- So(strcmp(s, "rep") == 0);
- nng_strfree(s);
- So(nng_getopt_int(rep, NNG_OPT_PEER, &p) == 0);
- So(p == 48);
- So(nng_getopt_string(rep, NNG_OPT_PEERNAME, &s) == 0);
- So(strcmp(s, "req") == 0);
- nng_strfree(s);
- });
-
- Convey("Send with no recv fails", {
- nng_msg *msg;
- rv = nng_msg_alloc(&msg, 0);
- So(rv == 0);
- rv = nng_sendmsg(rep, msg, 0);
- So(rv == NNG_ESTATE);
- nng_msg_free(msg);
- });
-
- Convey("Cannot set resend time", {
- So(nng_setopt_ms(rep, NNG_OPT_REQ_RESENDTIME, 100) ==
- NNG_ENOTSUP);
- });
- });
-
- Convey("We can create a linked REQ/REP pair", {
- nng_socket req;
- nng_socket rep;
-
- So(nng_rep_open(&rep) == 0);
-
- So(nng_req_open(&req) == 0);
-
- Reset({
- nng_close(rep);
- nng_close(req);
- });
-
- So(nng_listen(rep, addr, NULL, 0) == 0);
- So(nng_dial(req, addr, NULL, 0) == 0);
-
- Convey("They can REQ/REP exchange", {
- nng_msg *ping;
- nng_msg *pong;
-
- So(nng_msg_alloc(&ping, 0) == 0);
- So(nng_msg_append(ping, "ping", 5) == 0);
- So(nng_msg_len(ping) == 5);
- So(memcmp(nng_msg_body(ping), "ping", 5) == 0);
- So(nng_sendmsg(req, ping, 0) == 0);
- pong = NULL;
- So(nng_recvmsg(rep, &pong, 0) == 0);
- So(pong != NULL);
- So(nng_msg_len(pong) == 5);
- So(memcmp(nng_msg_body(pong), "ping", 5) == 0);
- nng_msg_trim(pong, 5);
- So(nng_msg_append(pong, "pong", 5) == 0);
- So(nng_sendmsg(rep, pong, 0) == 0);
- ping = 0;
- So(nng_recvmsg(req, &ping, 0) == 0);
- So(ping != NULL);
- So(nng_msg_len(ping) == 5);
- So(memcmp(nng_msg_body(ping), "pong", 5) == 0);
- nng_msg_free(ping);
- });
- });
-
- Convey("Request cancellation works", {
- nng_msg * abc;
- nng_msg * def;
- nng_msg * cmd;
- nng_duration retry = 100; // 100 ms
-
- nng_socket req;
- nng_socket rep;
-
- So(nng_rep_open(&rep) == 0);
-
- So(nng_req_open(&req) == 0);
-
- Reset({
- nng_close(rep);
- nng_close(req);
- });
-
- So(nng_setopt_ms(req, NNG_OPT_REQ_RESENDTIME, retry) == 0);
- So(nng_setopt_int(req, NNG_OPT_SENDBUF, 16) == 0);
-
- So(nng_msg_alloc(&abc, 0) == 0);
- So(nng_msg_append(abc, "abc", 4) == 0);
- So(nng_msg_alloc(&def, 0) == 0);
- So(nng_msg_append(def, "def", 4) == 0);
-
- So(nng_listen(rep, addr, NULL, 0) == 0);
- So(nng_dial(req, addr, NULL, 0) == 0);
-
- // Send req #1 (abc).
- So(nng_sendmsg(req, abc, 0) == 0);
-
- // Sleep a bit. This is so that we ensure that our
- // request gets to the far side. (If we cancel too
- // fast, then our outgoing send will be canceled before
- // it gets to the wire.)
- nng_msleep(20);
-
- // Send the next next request ("def"). Note that
- // the REP side server will have already buffered the receive
- // request, and should simply be waiting for us to reply to
- // abc.
- So(nng_sendmsg(req, def, 0) == 0);
-
- // Receive the first request (should be abc) on the REP server.
- So(nng_recvmsg(rep, &cmd, 0) == 0);
- So(nng_msg_len(cmd) == 4);
- So(strcmp(nng_msg_body(cmd), "abc") == 0);
-
- // REP sends the reply to first command. This will be
- // discarded by the REQ server.
- So(nng_sendmsg(rep, cmd, 0) == 0);
-
- // Now get the next command from the REP; should be "def".
- So(nng_recvmsg(rep, &cmd, 0) == 0);
- So(nng_msg_len(cmd) == 4);
- So(strcmp(nng_msg_body(cmd), "def") == 0);
-
- // And send it back to REQ.
- So(nng_sendmsg(rep, cmd, 0) == 0);
-
- // Try a req command. This should give back "def"
- So(nng_recvmsg(req, &cmd, 0) == 0);
- So(nng_msg_len(cmd) == 4);
- So(strcmp(nng_msg_body(cmd), "def") == 0);
- nng_msg_free(cmd);
- });
-
- Convey("Request cancellation aborts pending recv", {
- nng_msg * abc;
- nng_msg * def;
- nng_msg * cmd;
- nng_aio * aio;
- nng_duration retry = 100; // 100 ms
-
- nng_socket req;
- nng_socket rep;
-
- So(nng_rep_open(&rep) == 0);
-
- So(nng_req_open(&req) == 0);
- So(nng_aio_alloc(&aio, NULL, NULL) == 0);
-
- Reset({
- nng_close(rep);
- nng_close(req);
- nng_aio_free(aio);
- });
-
- So(nng_setopt_ms(req, NNG_OPT_REQ_RESENDTIME, retry) == 0);
- So(nng_setopt_int(req, NNG_OPT_SENDBUF, 16) == 0);
-
- So(nng_msg_alloc(&abc, 0) == 0);
- So(nng_msg_append(abc, "abc", 4) == 0);
- So(nng_msg_alloc(&def, 0) == 0);
- So(nng_msg_append(def, "def", 4) == 0);
-
- So(nng_listen(rep, addr, NULL, 0) == 0);
- So(nng_dial(req, addr, NULL, 0) == 0);
-
- // Send req #1 (abc).
- So(nng_sendmsg(req, abc, 0) == 0);
-
- // Sleep a bit. This is so that we ensure that our
- // request gets to the far side. (If we cancel too
- // fast, then our outgoing send will be canceled before
- // it gets to the wire.)
- nng_msleep(20);
-
- nng_aio_set_timeout(aio, 1000); // an entire second
- nng_recv_aio(req, aio);
-
- // Give time for this recv to post properly.
- nng_msleep(20);
-
- // Send the next next request ("def"). Note that
- // the REP side server will have already buffered the receive
- // request, and should simply be waiting for us to reply to
- // abc.
- So(nng_sendmsg(req, def, 0) == 0);
-
- nng_aio_wait(aio);
- So(nng_aio_result(aio) == NNG_ECANCELED);
-
- // Receive the first request (should be abc) on the REP server.
- So(nng_recvmsg(rep, &cmd, 0) == 0);
- So(nng_msg_len(cmd) == 4);
- So(strcmp(nng_msg_body(cmd), "abc") == 0);
-
- // REP sends the reply to first command. This will be
- // discarded by the REQ server.
- So(nng_sendmsg(rep, cmd, 0) == 0);
-
- // Now get the next command from the REP; should be "def".
- So(nng_recvmsg(rep, &cmd, 0) == 0);
- So(nng_msg_len(cmd) == 4);
- So(strcmp(nng_msg_body(cmd), "def") == 0);
-
- // And send it back to REQ.
- So(nng_sendmsg(rep, cmd, 0) == 0);
-
- // Try a req command. This should give back "def"
- So(nng_recvmsg(req, &cmd, 0) == 0);
- So(nng_msg_len(cmd) == 4);
- So(strcmp(nng_msg_body(cmd), "def") == 0);
- nng_msg_free(cmd);
- });
-
- nng_fini();
-})
diff --git a/tests/sock.c b/tests/sock.c
index 02cd0d43..cf3cc705 100644
--- a/tests/sock.c
+++ b/tests/sock.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -12,532 +12,615 @@
#include <nng/nng.h>
#include <nng/protocol/pair1/pair.h>
-#include <nng/protocol/pubsub0/sub.h>
#include <nng/supplemental/util/platform.h>
-#include "convey.h"
-#include "stubs.h"
-#include "trantest.h"
-
-#define SECONDS(x) ((x) *1000)
-
-TestMain("Socket Operations", {
- atexit(nng_fini);
- // Reset({ nng_fini(); });
- Reset({ nng_closeall(); });
-
- Convey("We are able to open a PAIR socket", {
- int rv;
- nng_socket s1;
-
- So(nng_pair_open(&s1) == 0);
-
- Reset({ nng_close(s1); });
-
- Convey("Recv with no pipes times out correctly", {
- nng_msg * msg = NULL;
- nng_duration to = 100;
- uint64_t now;
-
- now = getms();
- So(now > 0);
- So(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, to) == 0);
- So(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
- So(msg == NULL);
- So(getms() >= (now + to));
- So(getms() < (now + (to * 2)));
- });
-
- Convey("Recv nonblock with no pipes gives EAGAIN", {
- nng_msg *msg = NULL;
- So(nng_recvmsg(s1, &msg, NNG_FLAG_NONBLOCK) ==
- NNG_EAGAIN);
- So(msg == NULL);
- });
-
- Convey("Send with no pipes times out correctly", {
- nng_msg * msg = NULL;
- nng_duration to = 100;
- uint64_t now;
-
- // We cheat to get access to the core's clock.
- So(nng_msg_alloc(&msg, 0) == 0);
- So(msg != NULL);
- now = getms();
-
- So(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, to) == 0);
- So(nng_sendmsg(s1, msg, 0) == NNG_ETIMEDOUT);
- So(getms() >= (now + to));
- So(getms() < (now + (to * 2)));
- nng_msg_free(msg);
- });
-
- Convey("We can set and get options", {
- nng_duration to = 1234;
-
- So(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, to) == 0);
-
- Convey("Read only options handled properly", {
- So(nng_setopt_int(s1, NNG_OPT_RECVFD, 0) ==
- NNG_EREADONLY);
- So(nng_setopt_int(s1, NNG_OPT_SENDFD, 0) ==
- NNG_EREADONLY);
- So(nng_setopt(s1, NNG_OPT_LOCADDR, "a", 1) ==
- NNG_EREADONLY);
- });
-
- Convey("Sockname option works", {
- char name[128]; // 64 is max
- char * allocd;
- size_t sz;
- sz = sizeof(name);
- So(nng_getopt(
- s1, NNG_OPT_SOCKNAME, name, &sz) == 0);
- So(sz > 0 && sz < 64);
- So(sz == strlen(name) + 1);
- So(atoi(name) == (int) s1.id);
-
- So(nng_setopt(
- s1, NNG_OPT_SOCKNAME, "hello", 6) == 0);
- sz = sizeof(name);
- So(nng_getopt(
- s1, NNG_OPT_SOCKNAME, name, &sz) == 0);
- So(sz == 6);
- So(strcmp(name, "hello") == 0);
-
- memset(name, 'A', 64);
- name[64] = '\0';
-
- // strings must be NULL terminated
- So(nng_setopt(s1, NNG_OPT_SOCKNAME, name, 5) ==
- NNG_EINVAL);
-
- So(nng_getopt_string(
- s1, NNG_OPT_SOCKNAME, &allocd) == 0);
- So(strlen(allocd) == 5);
- So(strcmp(allocd, "hello") == 0);
- nng_strfree(allocd);
- });
-
- Convey("Oversize sockname handled right", {
- char name[256]; // 64 is max
- size_t sz = sizeof(name);
- memset(name, 'A', sz);
- So(nng_setopt(s1, NNG_OPT_SOCKNAME, name,
- sz) == NNG_EINVAL);
- name[sz - 1] = '\0';
- So(nng_setopt(s1, NNG_OPT_SOCKNAME, name,
- sz) == NNG_EINVAL);
-
- strcpy(name, "hello");
- So(nng_setopt(
- s1, NNG_OPT_SOCKNAME, name, sz) == 0);
- sz = sizeof(name);
- memset(name, 'B', sz);
- So(nng_getopt(
- s1, NNG_OPT_SOCKNAME, name, &sz) == 0);
- So(sz == 6);
- So(strcmp(name, "hello") == 0);
- });
-
- Convey("RAW option works", {
- bool raw;
- So(nng_getopt_bool(s1, NNG_OPT_RAW, &raw) ==
- 0);
- So(raw == false);
- });
-
- Convey("URL option works", {
- char url[NNG_MAXADDRLEN];
- nng_listener l;
- nng_dialer d;
- size_t sz;
-
- So(nng_listener_create(
- &l, s1, "inproc://url1") == 0);
- So(nng_dialer_create(
- &d, s1, "inproc://url2") == 0);
- memset(url, 0, sizeof(url));
- sz = sizeof(url);
- So(nng_listener_getopt(
- l, NNG_OPT_URL, url, &sz) == 0);
- So(strcmp(url, "inproc://url1") == 0);
- So(nng_listener_setopt(l, NNG_OPT_URL, url,
- sz) == NNG_EREADONLY);
- sz = sizeof(url);
- So(nng_dialer_getopt(
- d, NNG_OPT_URL, url, &sz) == 0);
- So(strcmp(url, "inproc://url2") == 0);
-
- So(nng_dialer_setopt(d, NNG_OPT_URL, url,
- sz) == NNG_EREADONLY);
- Reset({
- nng_dialer_close(d);
- nng_listener_close(l);
- });
- });
-
- Convey("We can apply options before endpoint", {
- nng_listener l;
- char addr[NNG_MAXADDRLEN];
- size_t sz;
-
- trantest_next_address(
- addr, "ipc:///tmp/lopt_%u");
-
- So(nng_setopt_size(
- s1, NNG_OPT_RECVMAXSZ, 543) == 0);
- So(nng_listener_create(&l, s1, addr) == 0);
- So(nng_listener_getopt_size(
- l, NNG_OPT_RECVMAXSZ, &sz) == 0);
- So(sz == 543);
-
- Convey("Endpoint option can be overridden", {
- So(nng_listener_setopt_size(l,
- NNG_OPT_RECVMAXSZ, 678) == 0);
- So(nng_listener_getopt_size(l,
- NNG_OPT_RECVMAXSZ, &sz) == 0);
- So(sz == 678);
- So(nng_getopt_size(s1,
- NNG_OPT_RECVMAXSZ, &sz) == 0);
- So(sz == 543);
- });
-
- Convey("And socket overrides again", {
- So(nng_setopt_size(s1,
- NNG_OPT_RECVMAXSZ, 911) == 0);
- So(nng_listener_getopt_size(l,
- NNG_OPT_RECVMAXSZ, &sz) == 0);
- So(sz == 911);
- });
- });
- Convey("Short size is not copied", {
- size_t sz = 0;
- to = 0;
- So(nng_getopt(s1, NNG_OPT_SENDTIMEO, &to,
- &sz) == NNG_EINVAL);
- So(sz == sizeof(to));
- So(to == 0);
- sz = 0;
- So(nng_getopt(s1, NNG_OPT_RECONNMINT, &to,
- &sz) == NNG_EINVAL);
-
- So(to == 0);
- sz = 0;
- So(nng_getopt(s1, NNG_OPT_RECONNMAXT, &to,
- &sz) == NNG_EINVAL);
- So(to == 0);
- });
-
- Convey("Correct size is copied", {
- size_t sz = sizeof(to);
- So(nng_getopt(
- s1, NNG_OPT_SENDTIMEO, &to, &sz) == 0);
- So(sz == sizeof(to));
- So(to == 1234);
- });
-
- Convey("Short size buf is not copied", {
- int l = 5;
- size_t sz = 0;
- So(nng_getopt(s1, NNG_OPT_RECVBUF, &l, &sz) ==
- NNG_EINVAL);
- So(sz == sizeof(l));
- So(l == 5);
- });
-
- Convey("Insane buffer size fails", {
- So(nng_setopt_int(s1, NNG_OPT_RECVBUF,
- 0x100000) == NNG_EINVAL);
- So(nng_setopt_int(s1, NNG_OPT_RECVBUF, -200) ==
- NNG_EINVAL);
- });
-
- Convey("Negative timeout fails", {
- So(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, -5) ==
- NNG_EINVAL);
- });
-
- Convey("Short timeout fails", {
- size_t sz = sizeof(to) - 1;
- to = 0;
- So(nng_setopt(s1, NNG_OPT_RECVTIMEO, &to,
- sz) == NNG_EINVAL);
- So(nng_setopt(s1, NNG_OPT_RECONNMINT, &to,
- sz) == NNG_EINVAL);
- });
-
- Convey("Cannot set raw", {
- So(nng_setopt_bool(s1, NNG_OPT_RAW, true) ==
- NNG_EREADONLY);
- });
-
- Convey("Unsupported options fail", {
- char *crap = "crap";
- So(nng_setopt(s1, NNG_OPT_SUB_SUBSCRIBE, crap,
- strlen(crap)) == NNG_ENOTSUP);
- });
-
- Convey("Bogus sizes fail", {
- size_t v;
- int i;
-
- So(nng_setopt_size(
- s1, NNG_OPT_RECVMAXSZ, 6550) == 0);
- So(nng_getopt_size(
- s1, NNG_OPT_RECVMAXSZ, &v) == 0);
- So(v == 6550);
-
- v = 102400;
- So(nng_setopt(s1, NNG_OPT_RECVMAXSZ, &v, 1) ==
- NNG_EINVAL);
- So(nng_getopt_size(
- s1, NNG_OPT_RECVMAXSZ, &v) == 0);
- So(v == 6550);
-
- i = 42;
- So(nng_setopt(s1, NNG_OPT_RECVBUF, &i, 1) ==
- NNG_EINVAL);
-
- if (sizeof(size_t) == 8) {
- v = 0x10000;
- v <<= 30;
- So(nng_setopt_size(s1,
- NNG_OPT_RECVMAXSZ,
- v) == NNG_EINVAL);
- So(nng_getopt_size(s1,
- NNG_OPT_RECVMAXSZ, &v) == 0);
- So(v == 6550);
- }
- });
- });
-
- Convey("Bogus URLs not supported", {
- Convey("Dialing fails properly", {
- rv = nng_dial(s1, "bogus://1", NULL, 0);
- So(rv == NNG_ENOTSUP);
- });
- Convey("Listening fails properly", {
- rv = nng_listen(s1, "bogus://2", NULL, 0);
- So(rv == NNG_ENOTSUP);
- });
- });
-
- Convey("Dialing synch can get refused", {
- rv = nng_dial(s1, "inproc://no", NULL, 0);
- So(rv == NNG_ECONNREFUSED);
- });
-
- Convey("Dialing asynch does not get refused", {
- char * buf;
- size_t sz;
- nng_socket s2;
- char * a = "inproc://asy";
- So(nng_setopt_ms(s1, NNG_OPT_RECONNMINT, 10) == 0);
- So(nng_setopt_ms(s1, NNG_OPT_RECONNMAXT, 10) == 0);
- So(nng_dial(s1, a, NULL, NNG_FLAG_NONBLOCK) == 0);
- Convey("And connects late", {
- So(nng_pair_open(&s2) == 0);
- Reset({ nng_close(s2); });
- So(nng_listen(s2, a, NULL, 0) == 0);
- nng_msleep(100);
- So(nng_send(s1, "abc", 4, 0) == 0);
- So(nng_recv(s2, &buf, &sz, NNG_FLAG_ALLOC) ==
- 0);
- So(sz == 4);
- So(memcmp(buf, "abc", 4) == 0);
- nng_free(buf, sz);
- });
- });
-
- Convey("Listening works", {
- char * a = "inproc://here";
- nng_listener l = NNG_LISTENER_INITIALIZER;
-
- So(nng_listener_id(l) < 0);
- rv = nng_listen(s1, a, &l, 0);
- So(rv == 0);
- So(nng_listener_id(l) > 0);
-
- Convey("Second listen fails ADDRINUSE", {
- rv = nng_listen(s1, a, NULL, 0);
- So(rv == NNG_EADDRINUSE);
- });
-
- Convey("We cannot try to start a listener again",
- { So(nng_listener_start(l, 0) == NNG_ESTATE); });
-
- Convey("We can connect to it", {
- nng_socket s2 = NNG_SOCKET_INITIALIZER;
- So(nng_socket_id(s2) < 0);
- So(nng_pair_open(&s2) == 0);
- Reset({ nng_close(s2); });
- So(nng_dial(s2, a, NULL, 0) == 0);
- nng_close(s2);
- });
- });
-
- Convey("Dialer creation ok", {
- nng_dialer ep = NNG_DIALER_INITIALIZER;
- char * a = "tcp://127.0.0.1:2929";
-
- So(nng_dialer_id(ep) < 0);
- So(nng_dialer_create(&ep, s1, a) == 0);
- So(nng_dialer_id(ep) > 0);
-
- Convey("Options work", {
- size_t sz;
- So(nng_dialer_setopt_size(
- ep, NNG_OPT_RECVMAXSZ, 4321) == 0);
- So(nng_dialer_getopt_size(
- ep, NNG_OPT_RECVMAXSZ, &sz) == 0);
- So(sz == 4321);
- });
-
- Convey("Cannot access as listener", {
- bool b;
- nng_listener l;
- l.id = ep.id;
- So(nng_listener_getopt_bool(
- l, NNG_OPT_RAW, &b) == NNG_ENOENT);
- So(nng_listener_close(l) == NNG_ENOENT);
- });
-
- Convey("Socket opts not for dialer", {
- // Not appropriate for dialer.
- So(nng_dialer_setopt_bool(
- ep, NNG_OPT_RAW, true) == NNG_ENOTSUP);
- So(nng_dialer_setopt_ms(ep, NNG_OPT_SENDTIMEO,
- 1) == NNG_ENOTSUP);
- So(nng_dialer_setopt_string(ep,
- NNG_OPT_SOCKNAME,
- "bogus") == NNG_ENOTSUP);
- });
-
- Convey("URL is readonly", {
- So(nng_dialer_setopt_string(ep, NNG_OPT_URL,
- "tcp://somewhere.else.com:8888") ==
- NNG_EREADONLY);
- });
- Convey("Bad size checks", {
- So(nng_dialer_setopt(ep, NNG_OPT_RECVMAXSZ,
- "a", 1) == NNG_EINVAL);
- });
- });
-
- Convey("Listener creation ok", {
- nng_listener ep;
- char * a = "tcp://127.0.0.1:2929";
- So(nng_listener_create(&ep, s1, a) == 0);
- Convey("Options work", {
- size_t sz;
- So(nng_listener_setopt_size(
- ep, NNG_OPT_RECVMAXSZ, 4321) == 0);
- So(nng_listener_getopt_size(
- ep, NNG_OPT_RECVMAXSZ, &sz) == 0);
- So(sz == 4321);
- });
- Convey("Cannot access as dialer", {
- bool b;
- nng_dialer d;
- d.id = ep.id;
- So(nng_dialer_getopt_bool(
- d, NNG_OPT_RAW, &b) == NNG_ENOENT);
- So(nng_dialer_close(d) == NNG_ENOENT);
- });
-
- Convey("Socket opts not for listener", {
- // Not appropriate for dialer.
- So(nng_listener_setopt_bool(
- ep, NNG_OPT_RAW, true) == NNG_ENOTSUP);
- So(nng_listener_setopt_ms(ep,
- NNG_OPT_RECONNMINT, 1) == NNG_ENOTSUP);
- So(nng_listener_setopt_string(ep,
- NNG_OPT_SOCKNAME,
- "bogus") == NNG_ENOTSUP);
- });
-
- Convey("URL is readonly", {
- So(nng_listener_setopt_string(ep, NNG_OPT_URL,
- "tcp://somewhere.else.com:8888") ==
- NNG_EREADONLY);
- });
-
- Convey("Bad size checks", {
- So(nng_listener_setopt(ep, NNG_OPT_RECVMAXSZ,
- "a", 1) == NNG_EINVAL);
- });
- });
-
- Convey("Cannot access absent ep options", {
- size_t s;
- int i;
- nng_duration t;
- bool b;
- nng_dialer d;
- nng_listener l;
- d.id = 1999;
- l.id = 1999;
-
- So(nng_dialer_setopt_size(d, NNG_OPT_RECVMAXSZ, 10) ==
- NNG_ENOENT);
- So(nng_listener_setopt_size(
- l, NNG_OPT_RECVMAXSZ, 10) == NNG_ENOENT);
-
- s = 1;
- So(nng_dialer_getopt_bool(d, NNG_OPT_RAW, &b) ==
- NNG_ENOENT);
- So(nng_listener_getopt_bool(l, NNG_OPT_RAW, &b) ==
- NNG_ENOENT);
-
- So(nng_dialer_getopt_size(d, NNG_OPT_RECVMAXSZ, &s) ==
- NNG_ENOENT);
- So(nng_listener_getopt_size(
- l, NNG_OPT_RECVMAXSZ, &s) == NNG_ENOENT);
-
- So(nng_dialer_getopt_int(d, NNG_OPT_RAW, &i) ==
- NNG_ENOENT);
- So(nng_listener_getopt_int(l, NNG_OPT_RAW, &i) ==
- NNG_ENOENT);
-
- So(nng_dialer_getopt_ms(d, NNG_OPT_RECVTIMEO, &t) ==
- NNG_ENOENT);
- So(nng_listener_getopt_ms(l, NNG_OPT_SENDTIMEO, &t) ==
- NNG_ENOENT);
- });
-
- Convey("We can send and receive messages", {
- nng_socket s2;
- int len;
- size_t sz;
- nng_duration to = SECONDS(3);
- char * buf;
- char * a = "inproc://t1";
-
- So(nng_pair_open(&s2) == 0);
- Reset({ nng_close(s2); });
-
- So(nng_setopt_int(s1, NNG_OPT_RECVBUF, 1) == 0);
- So(nng_getopt_int(s1, NNG_OPT_RECVBUF, &len) == 0);
- So(len == 1);
-
- So(nng_setopt_int(s1, NNG_OPT_SENDBUF, 1) == 0);
- So(nng_setopt_int(s2, NNG_OPT_SENDBUF, 1) == 0);
-
- So(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, to) == 0);
- So(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, to) == 0);
- So(nng_setopt_ms(s2, NNG_OPT_SENDTIMEO, to) == 0);
- So(nng_setopt_ms(s2, NNG_OPT_RECVTIMEO, to) == 0);
-
- So(nng_listen(s1, a, NULL, 0) == 0);
- So(nng_dial(s2, a, NULL, 0) == 0);
-
- So(nng_send(s1, "abc", 4, 0) == 0);
- So(nng_recv(s2, &buf, &sz, NNG_FLAG_ALLOC) == 0);
- So(buf != NULL);
- So(sz == 4);
- So(memcmp(buf, "abc", 4) == 0);
- nng_free(buf, sz);
- });
- });
-})
+#include "acutest.h"
+#include "testutil.h"
+
+void
+test_recv_timeout(void)
+{
+ nng_socket s1;
+ uint64_t now;
+ nng_msg * msg = NULL;
+
+ TEST_CHECK(nng_pair_open(&s1) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, 10) == 0);
+ now = testutil_clock();
+ TEST_CHECK(nng_recvmsg(s1, &msg, 0) == NNG_ETIMEDOUT);
+ TEST_CHECK(msg == NULL);
+ TEST_CHECK(testutil_clock() >= (now + 9));
+ TEST_CHECK(testutil_clock() < (now + 500));
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_recv_nonblock(void)
+{
+ nng_socket s1;
+ uint64_t now;
+ nng_msg * msg = NULL;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, 10) == 0);
+ now = testutil_clock();
+ TEST_CHECK(nng_recvmsg(s1, &msg, NNG_FLAG_NONBLOCK) == NNG_EAGAIN);
+ TEST_CHECK(msg == NULL);
+ TEST_CHECK(testutil_clock() < (now + 500));
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_send_timeout(void)
+{
+ nng_socket s1;
+ uint64_t now;
+ nng_msg * msg;
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_pair_open(&s1) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, 100) == 0);
+ now = testutil_clock();
+ TEST_CHECK(nng_sendmsg(s1, msg, 0) == NNG_ETIMEDOUT);
+ TEST_CHECK(testutil_clock() >= (now + 9));
+ TEST_CHECK(testutil_clock() < (now + 500));
+ nng_msg_free(msg);
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_send_nonblock(void)
+{
+ nng_socket s1;
+ uint64_t now;
+ nng_msg * msg;
+
+ TEST_CHECK(nng_msg_alloc(&msg, 0) == 0);
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, 500) == 0);
+ now = testutil_clock();
+ TEST_CHECK(nng_sendmsg(s1, msg, NNG_FLAG_NONBLOCK) == NNG_EAGAIN);
+ TEST_CHECK(testutil_clock() < (now + 100));
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_readonly_options(void)
+{
+ nng_socket s1;
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_RECVFD, 0) == NNG_EREADONLY);
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_SENDFD, 0) == NNG_EREADONLY);
+ TEST_CHECK(nng_setopt(s1, NNG_OPT_LOCADDR, "a", 1) == NNG_EREADONLY);
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_socket_base(void)
+{
+ nng_socket s1 = NNG_SOCKET_INITIALIZER;
+
+ TEST_CHECK(nng_socket_id(s1) < 0);
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_socket_id(s1) > 0);
+
+ // Cannot set bogus options
+ TEST_CHECK(nng_setopt_bool(s1, "BAD_OPT", false) == NNG_ENOTSUP);
+
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_socket_name(void)
+{
+ nng_socket s1;
+ char name[128]; // 64 is max
+ char * str;
+ long id;
+ char * end;
+ size_t sz;
+
+ sz = sizeof(name);
+ TEST_CHECK(nng_pair_open(&s1) == 0);
+ TEST_CHECK(nng_getopt(s1, NNG_OPT_SOCKNAME, name, &sz) == 0);
+ TEST_CHECK(sz > 0 && sz < 64);
+ TEST_CHECK(sz == strlen(name) + 1);
+ id = strtol(name, &end, 10);
+ TEST_CHECK(id == (long) s1.id);
+ TEST_CHECK(end != NULL && *end == '\0');
+
+ TEST_CHECK(nng_setopt(s1, NNG_OPT_SOCKNAME, "hello", 6) == 0);
+ sz = sizeof(name);
+ TEST_CHECK(nng_getopt(s1, NNG_OPT_SOCKNAME, name, &sz) == 0);
+ TEST_CHECK(sz == 6);
+ TEST_CHECK(strcmp(name, "hello") == 0);
+
+ memset(name, 'A', 64);
+ name[64] = '\0';
+
+ // strings must be NULL terminated
+ TEST_CHECK(nng_setopt(s1, NNG_OPT_SOCKNAME, name, 5) == NNG_EINVAL);
+
+ TEST_CHECK(nng_getopt_string(s1, NNG_OPT_SOCKNAME, &str) == 0);
+ TEST_ASSERT(str != NULL);
+ TEST_CHECK(strlen(str) == 5);
+ TEST_CHECK(strcmp(str, "hello") == 0);
+ nng_strfree(str);
+
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_socket_name_oversize(void)
+{
+ nng_socket s1;
+ char name[256]; // 64 is max
+ size_t sz = sizeof(name);
+
+ memset(name, 'A', sz);
+ TEST_CHECK(nng_pair_open(&s1) == 0);
+
+ TEST_CHECK(nng_setopt(s1, NNG_OPT_SOCKNAME, name, sz) == NNG_EINVAL);
+ name[sz - 1] = '\0';
+ TEST_CHECK(nng_setopt(s1, NNG_OPT_SOCKNAME, name, sz) == NNG_EINVAL);
+
+ strcpy(name, "hello");
+ TEST_CHECK(nng_setopt(s1, NNG_OPT_SOCKNAME, name, sz) == 0);
+ sz = sizeof(name);
+ memset(name, 'B', sz);
+ TEST_CHECK(nng_getopt(s1, NNG_OPT_SOCKNAME, name, &sz) == 0);
+ TEST_CHECK(sz == 6);
+ TEST_CHECK(strcmp(name, "hello") == 0);
+
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_send_recv(void)
+{
+ nng_socket s1;
+ nng_socket s2;
+ int len;
+ size_t sz;
+ nng_duration to = 3000; // 3 seconds
+ char * buf;
+ char * a = "inproc://t1";
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&s2) == 0);
+
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_RECVBUF, 1) == 0);
+ TEST_CHECK(nng_getopt_int(s1, NNG_OPT_RECVBUF, &len) == 0);
+ TEST_CHECK(len == 1);
+
+ TEST_CHECK(nng_setopt_int(s1, NNG_OPT_SENDBUF, 1) == 0);
+ TEST_CHECK(nng_setopt_int(s2, NNG_OPT_SENDBUF, 1) == 0);
+
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, to) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, to) == 0);
+ TEST_CHECK(nng_setopt_ms(s2, NNG_OPT_SENDTIMEO, to) == 0);
+ TEST_CHECK(nng_setopt_ms(s2, NNG_OPT_RECVTIMEO, to) == 0);
+
+ TEST_CHECK(nng_listen(s1, a, NULL, 0) == 0);
+ TEST_CHECK(nng_dial(s2, a, NULL, 0) == 0);
+
+ TEST_CHECK(nng_send(s1, "abc", 4, 0) == 0);
+ TEST_CHECK(nng_recv(s2, &buf, &sz, NNG_FLAG_ALLOC) == 0);
+ TEST_CHECK(buf != NULL);
+ TEST_CHECK(sz == 4);
+ TEST_CHECK(memcmp(buf, "abc", 4) == 0);
+ nng_free(buf, sz);
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(s2) == 0);
+}
+
+void
+test_connection_refused(void)
+{
+ nng_socket s1;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_dial(s1, "inproc://no", NULL, 0) == NNG_ECONNREFUSED);
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_late_connection(void)
+{
+ char * buf;
+ size_t sz;
+ nng_socket s1;
+ nng_socket s2;
+ char * a = "inproc://asy";
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&s2) == 0);
+
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECONNMINT, 10) == 0);
+ TEST_CHECK(nng_setopt_ms(s1, NNG_OPT_RECONNMAXT, 10) == 0);
+
+ TEST_CHECK(nng_dial(s1, a, NULL, NNG_FLAG_NONBLOCK) == 0);
+ TEST_CHECK(nng_listen(s2, a, NULL, 0) == 0);
+ nng_msleep(100);
+ TEST_CHECK(nng_send(s1, "abc", 4, 0) == 0);
+ TEST_CHECK(nng_recv(s2, &buf, &sz, NNG_FLAG_ALLOC) == 0);
+ TEST_CHECK(sz == 4);
+ TEST_CHECK(memcmp(buf, "abc", 4) == 0);
+ nng_free(buf, sz);
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(s2) == 0);
+}
+
+void
+test_address_busy(void)
+{
+ char * a = "inproc://eaddrinuse";
+ nng_listener l = NNG_LISTENER_INITIALIZER;
+ nng_dialer d = NNG_DIALER_INITIALIZER;
+ nng_socket s1;
+ nng_socket s2;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_pair1_open(&s2) == 0);
+
+ TEST_CHECK(nng_listener_id(l) < 0);
+ TEST_CHECK(nng_listen(s1, a, &l, 0) == 0);
+ TEST_CHECK(nng_listener_id(l) > 0);
+
+ // Cannot start another one.
+ TEST_CHECK(nng_listen(s1, a, NULL, 0) == NNG_EADDRINUSE);
+
+ // We can't restart it -- it's already running
+ TEST_CHECK(nng_listener_start(l, 0) == NNG_ESTATE);
+
+ // We can connect to it.
+ TEST_CHECK(nng_dialer_id(d) < 0);
+ TEST_CHECK(nng_dial(s2, a, &d, 0) == 0);
+ TEST_CHECK(nng_dialer_id(d) > 0);
+
+ TEST_CHECK(nng_close(s1) == 0);
+ TEST_CHECK(nng_close(s2) == 0);
+}
+
+void
+test_endpoint_types(void)
+{
+ nng_socket s1;
+ nng_dialer d = NNG_DIALER_INITIALIZER;
+ nng_listener l = NNG_LISTENER_INITIALIZER;
+ nng_dialer d2;
+ nng_listener l2;
+ char * a = "inproc://mumble...";
+ bool b;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+
+ TEST_CHECK(nng_dialer_id(d) < 0);
+ TEST_CHECK(nng_dialer_create(&d, s1, a) == 0);
+ TEST_CHECK(nng_dialer_id(d) > 0);
+
+ // Forge a listener
+ l2.id = nng_dialer_id(d);
+ TEST_CHECK(
+ nng_listener_getopt_bool(l2, NNG_OPT_RAW, &b) == NNG_ENOENT);
+ TEST_CHECK(nng_listener_close(l2) == NNG_ENOENT);
+ TEST_CHECK(nng_dialer_close(d) == 0);
+
+ TEST_CHECK(nng_listener_id(l) < 0);
+ TEST_CHECK(nng_listener_create(&l, s1, a) == 0);
+ TEST_CHECK(nng_listener_id(l) > 0);
+
+ // Forge a dialer
+ d2.id = nng_listener_id(l);
+ TEST_CHECK(nng_dialer_getopt_bool(d2, NNG_OPT_RAW, &b) == NNG_ENOENT);
+ TEST_CHECK(nng_dialer_close(d2) == NNG_ENOENT);
+ TEST_CHECK(nng_listener_close(l) == 0);
+
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_bad_url(void)
+{
+ nng_socket s1;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_dial(s1, "bogus://1", NULL, 0) == NNG_ENOTSUP);
+ TEST_CHECK(nng_listen(s1, "bogus://2", NULL, 0) == NNG_ENOTSUP);
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_url_option(void)
+{
+ nng_socket s1;
+ char url[NNG_MAXADDRLEN];
+ nng_listener l;
+ nng_dialer d;
+ size_t sz;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+
+ // Listener
+ TEST_CHECK(nng_listener_create(&l, s1, "inproc://url1") == 0);
+ memset(url, 0, sizeof(url));
+ sz = sizeof(url);
+ TEST_CHECK(nng_listener_getopt(l, NNG_OPT_URL, url, &sz) == 0);
+ TEST_CHECK(strcmp(url, "inproc://url1") == 0);
+ TEST_CHECK(
+ nng_listener_setopt(l, NNG_OPT_URL, url, sz) == NNG_EREADONLY);
+ sz = sizeof(url);
+
+ // Dialer
+ TEST_CHECK(nng_dialer_create(&d, s1, "inproc://url2") == 0);
+ TEST_CHECK(nng_dialer_getopt(d, NNG_OPT_URL, url, &sz) == 0);
+ TEST_CHECK(strcmp(url, "inproc://url2") == 0);
+ TEST_CHECK(
+ nng_dialer_setopt(d, NNG_OPT_URL, url, sz) == NNG_EREADONLY);
+
+ nng_close(s1);
+}
+
+void
+test_listener_options(void)
+{
+ nng_socket s1;
+ nng_listener l;
+ size_t sz;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+
+ // Create a listener with the specified options
+ TEST_CHECK(nng_setopt_size(s1, NNG_OPT_RECVMAXSZ, 543) == 0);
+ TEST_CHECK(nng_listener_create(&l, s1, "inproc://listener_opts") == 0);
+ TEST_CHECK(nng_listener_getopt_size(l, NNG_OPT_RECVMAXSZ, &sz) == 0);
+ TEST_CHECK(sz == 543);
+
+ // Verify endpoint overrides
+ TEST_CHECK(nng_listener_setopt_size(l, NNG_OPT_RECVMAXSZ, 678) == 0);
+ TEST_CHECK(nng_listener_getopt_size(l, NNG_OPT_RECVMAXSZ, &sz) == 0);
+ TEST_CHECK(sz == 678);
+ TEST_CHECK(nng_getopt_size(s1, NNG_OPT_RECVMAXSZ, &sz) == 0);
+ TEST_CHECK(sz == 543);
+
+ // And socket overrides again
+ TEST_CHECK(nng_setopt_size(s1, NNG_OPT_RECVMAXSZ, 911) == 0);
+ TEST_CHECK(nng_listener_getopt_size(l, NNG_OPT_RECVMAXSZ, &sz) == 0);
+ TEST_CHECK(sz == 911);
+
+ // Cannot set invalid options
+ TEST_CHECK(nng_listener_setopt_size(l, "BAD_OPT", 1) == NNG_ENOTSUP);
+ TEST_CHECK(nng_listener_setopt_bool(l, NNG_OPT_RECVMAXSZ, true) ==
+ NNG_EBADTYPE);
+ TEST_CHECK(
+ nng_listener_setopt(l, NNG_OPT_RECVMAXSZ, &sz, 1) == NNG_EINVAL);
+
+ // Cannot set inappropriate options
+ TEST_CHECK(nng_listener_setopt_string(l, NNG_OPT_SOCKNAME, "1") ==
+ NNG_ENOTSUP);
+ TEST_CHECK(
+ nng_listener_setopt_bool(l, NNG_OPT_RAW, true) == NNG_ENOTSUP);
+ TEST_CHECK(
+ nng_listener_setopt_ms(l, NNG_OPT_RECONNMINT, 1) == NNG_ENOTSUP);
+ TEST_CHECK(nng_listener_setopt_string(l, NNG_OPT_SOCKNAME, "bogus") ==
+ NNG_ENOTSUP);
+
+ // Read only options
+ TEST_CHECK(nng_listener_setopt_string(
+ l, NNG_OPT_URL, "inproc://junk") == NNG_EREADONLY);
+
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_dialer_options(void)
+{
+ nng_socket s1;
+ nng_dialer d;
+ size_t sz;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+
+ // Create a listener with the specified options
+ TEST_CHECK(nng_setopt_size(s1, NNG_OPT_RECVMAXSZ, 543) == 0);
+ TEST_CHECK(nng_dialer_create(&d, s1, "inproc://dialer_opts") == 0);
+ TEST_CHECK(nng_dialer_getopt_size(d, NNG_OPT_RECVMAXSZ, &sz) == 0);
+ TEST_CHECK(sz == 543);
+
+ // Verify endpoint overrides
+ TEST_CHECK(nng_dialer_setopt_size(d, NNG_OPT_RECVMAXSZ, 678) == 0);
+ TEST_CHECK(nng_dialer_getopt_size(d, NNG_OPT_RECVMAXSZ, &sz) == 0);
+ TEST_CHECK(sz == 678);
+ TEST_CHECK(nng_getopt_size(s1, NNG_OPT_RECVMAXSZ, &sz) == 0);
+ TEST_CHECK(sz == 543);
+
+ // And socket overrides again
+ TEST_CHECK(nng_setopt_size(s1, NNG_OPT_RECVMAXSZ, 911) == 0);
+ TEST_CHECK(nng_dialer_getopt_size(d, NNG_OPT_RECVMAXSZ, &sz) == 0);
+ TEST_CHECK(sz == 911);
+
+ // Cannot set invalid options
+ TEST_CHECK(nng_dialer_setopt_size(d, "BAD_OPT", 1) == NNG_ENOTSUP);
+ TEST_CHECK(nng_dialer_setopt_bool(d, NNG_OPT_RECVMAXSZ, true) ==
+ NNG_EBADTYPE);
+ TEST_CHECK(
+ nng_dialer_setopt(d, NNG_OPT_RECVMAXSZ, &sz, 1) == NNG_EINVAL);
+
+ // Cannot set inappropriate options
+ TEST_CHECK(
+ nng_dialer_setopt_string(d, NNG_OPT_SOCKNAME, "1") == NNG_ENOTSUP);
+ TEST_CHECK(
+ nng_dialer_setopt_bool(d, NNG_OPT_RAW, true) == NNG_ENOTSUP);
+ TEST_CHECK(
+ nng_dialer_setopt_ms(d, NNG_OPT_SENDTIMEO, 1) == NNG_ENOTSUP);
+ TEST_CHECK(nng_dialer_setopt_string(d, NNG_OPT_SOCKNAME, "bogus") ==
+ NNG_ENOTSUP);
+
+ // Read only options
+ TEST_CHECK(nng_dialer_setopt_string(d, NNG_OPT_URL, "inproc://junk") ==
+ NNG_EREADONLY);
+
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_endpoint_absent_options(void)
+{
+ size_t s;
+ int i;
+ nng_duration t;
+ bool b;
+ nng_dialer d;
+ nng_listener l;
+ d.id = 1999;
+ l.id = 1999;
+
+ TEST_CHECK(
+ nng_dialer_setopt_size(d, NNG_OPT_RECVMAXSZ, 10) == NNG_ENOENT);
+ TEST_CHECK(
+ nng_listener_setopt_size(l, NNG_OPT_RECVMAXSZ, 10) == NNG_ENOENT);
+
+ TEST_CHECK(nng_dialer_getopt_bool(d, NNG_OPT_RAW, &b) == NNG_ENOENT);
+ TEST_CHECK(nng_listener_getopt_bool(l, NNG_OPT_RAW, &b) == NNG_ENOENT);
+
+ TEST_CHECK(
+ nng_dialer_getopt_size(d, NNG_OPT_RECVMAXSZ, &s) == NNG_ENOENT);
+ TEST_CHECK(
+ nng_listener_getopt_size(l, NNG_OPT_RECVMAXSZ, &s) == NNG_ENOENT);
+
+ TEST_CHECK(nng_dialer_getopt_int(d, NNG_OPT_RAW, &i) == NNG_ENOENT);
+ TEST_CHECK(nng_listener_getopt_int(l, NNG_OPT_RAW, &i) == NNG_ENOENT);
+
+ TEST_CHECK(
+ nng_dialer_getopt_ms(d, NNG_OPT_RECVTIMEO, &t) == NNG_ENOENT);
+ TEST_CHECK(
+ nng_listener_getopt_ms(l, NNG_OPT_SENDTIMEO, &t) == NNG_ENOENT);
+}
+
+void
+test_timeout_options(void)
+{
+ nng_socket s1;
+ nng_duration to;
+ size_t sz;
+
+ char *cases[] = {
+ NNG_OPT_RECVTIMEO,
+ NNG_OPT_SENDTIMEO,
+ NNG_OPT_RECONNMAXT,
+ NNG_OPT_RECONNMINT,
+ NULL,
+ };
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ for (int i = 0; cases[i] != NULL; i++) {
+ bool b;
+ TEST_CASE(cases[i]);
+
+ // Can't receive a duration into zero bytes.
+ sz = 0;
+ TEST_CHECK(nng_getopt(s1, cases[i], &to, &sz) == NNG_EINVAL);
+
+ // Type mismatches
+ TEST_CHECK(nng_getopt_bool(s1, cases[i], &b) == NNG_EBADTYPE);
+ sz = 1;
+ TEST_CHECK(nng_getopt(s1, cases[i], &b, &sz) == NNG_EINVAL);
+
+ // Can set a valid duration
+ TEST_CHECK(nng_setopt_ms(s1, cases[i], 1234) == 0);
+ TEST_CHECK(nng_getopt_ms(s1, cases[i], &to) == 0);
+ TEST_CHECK(to == 1234);
+
+ to = 0;
+ sz = sizeof(to);
+ TEST_CHECK(nng_getopt(s1, cases[i], &to, &sz) == 0);
+ TEST_CHECK(to == 1234);
+ TEST_CHECK(sz == sizeof(to));
+
+ // Can't set a negative duration
+ TEST_CHECK(nng_setopt_ms(s1, cases[i], -5) == NNG_EINVAL);
+
+ // Can't pass a buf too small for duration
+ sz = sizeof(to) - 1;
+ to = 1;
+ TEST_CHECK(nng_setopt(s1, cases[i], &to, sz) == NNG_EINVAL);
+ }
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_size_options(void)
+{
+ nng_socket s1;
+ size_t val;
+ size_t sz;
+ char * opt;
+
+ char *cases[] = {
+ NNG_OPT_RECVMAXSZ,
+ NULL,
+ };
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ for (int i = 0; (opt = cases[i]) != NULL; i++) {
+ TEST_CASE(opt);
+
+ // Can't receive a size into zero bytes.
+ sz = 0;
+ TEST_CHECK(nng_getopt(s1, opt, &val, &sz) == NNG_EINVAL);
+
+ // Can set a valid duration
+ TEST_CHECK(nng_setopt_size(s1, opt, 1234) == 0);
+ TEST_CHECK(nng_getopt_size(s1, opt, &val) == 0);
+ TEST_CHECK(val == 1234);
+
+ val = 0;
+ sz = sizeof(val);
+ TEST_CHECK(nng_getopt(s1, opt, &val, &sz) == 0);
+ TEST_CHECK(val == 1234);
+ TEST_CHECK(sz == sizeof(val));
+
+ // Can't pass a buf too small for size
+ sz = sizeof(val) - 1;
+ val = 1;
+ TEST_CHECK(nng_setopt(s1, opt, &val, sz) == NNG_EINVAL);
+
+ // We limit the limit to 4GB. Clear it if you want to
+ // ship more than 4GB at a time.
+#if defined(_WIN64) || defined(_LP64)
+ val = 0x10000u;
+ val <<= 30u;
+ TEST_CHECK(nng_setopt_size(s1, opt, val) == NNG_EINVAL);
+ TEST_CHECK(nng_getopt_size(s1, opt, &val) == 0);
+ TEST_CHECK(val == 1234);
+#endif
+ }
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+TEST_LIST = {
+ { "recv timeout", test_recv_timeout },
+ { "recv non-block", test_recv_nonblock },
+ { "send timeout", test_send_timeout },
+ { "send non-block", test_send_nonblock },
+ { "read only options", test_readonly_options },
+ { "socket base", test_socket_base },
+ { "socket name", test_socket_name },
+ { "socket name oversize", test_socket_name_oversize },
+ { "send recv", test_send_recv },
+ { "connection refused", test_connection_refused },
+ { "late connection", test_late_connection },
+ { "address busy", test_address_busy },
+ { "bad url", test_bad_url },
+ { "url option", test_url_option },
+ { "listener options", test_listener_options },
+ { "dialer options", test_dialer_options },
+ { "timeout options", test_timeout_options },
+ { "size options", test_size_options },
+ { "endpoint absent options", test_endpoint_absent_options },
+ { "endpoint types", test_endpoint_types },
+
+ { NULL, NULL },
+};
diff --git a/tests/stubs.h b/tests/stubs.h
index a8fa59e9..f178a9bc 100644
--- a/tests/stubs.h
+++ b/tests/stubs.h
@@ -72,7 +72,11 @@ fdready(int fd)
case 1:
return (true);
default:
+#ifdef CONVEY_H
ConveyError("BAD POLL RETURN!");
+#elif defined(TEST_CHECK)
+ TEST_ASSERT(0);
+#endif
return (false);
}
}
@@ -81,7 +85,9 @@ int
nosocket(nng_socket *s)
{
(void) s; // not used
+#ifdef CONVEY_H
ConveySkip("Protocol unconfigured");
+#endif
return (NNG_ENOTSUP);
}
@@ -94,14 +100,6 @@ test_htons(uint16_t in)
return (in);
}
-#ifndef NNG_HAVE_REQ0
-#define nng_req0_open nosocket
-#endif
-
-#ifndef NNG_HAVE_REP0
-#define nng_rep0_open nosocket
-#endif
-
#ifndef NNG_HAVE_PUB0
#define nng_pub0_open nosocket
#endif
@@ -114,10 +112,6 @@ test_htons(uint16_t in)
#define nng_pair0_open nosocket
#endif
-#ifndef NNG_HAVE_PAIR1
-#define nng_pair1_open nosocket
-#endif
-
#ifndef NNG_HAVE_PUSH0
#define nng_push0_open nosocket
#endif
diff --git a/tests/testutil.c b/tests/testutil.c
new file mode 100644
index 00000000..77b985a3
--- /dev/null
+++ b/tests/testutil.c
@@ -0,0 +1,310 @@
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#ifdef _WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+#include <winsock2.h>
+// order counts
+#include <mswsock.h>
+#define poll WSAPoll
+#include <io.h>
+#else
+#include <fcntl.h>
+#include <poll.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#if !defined(_WIN32) && !defined(CLOCK_MONOTONIC)
+#include <poll.h>
+#endif
+
+#include "testutil.h"
+
+#include <nng/supplemental/util/platform.h>
+
+uint64_t
+testutil_clock(void)
+{
+#ifdef _WIN32
+ return (GetTickCount64());
+#elif defined(CLOCK_MONTONIC)
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ uint64_t val;
+
+ val = ts.tv_sec;
+ val *= 1000;
+ val += ts.tv_nsec / 1000000;
+ return (val);
+#else
+ static time_t epoch;
+ struct timeval tv;
+
+ if (epoch == 0) {
+ epoch = time(NULL);
+ }
+ gettimeofday(&tv, NULL);
+
+ if (tv.tv_sec < epoch) {
+ // Broken clock.
+ // This will force all other timing tests to fail
+ return (0);
+ }
+ tv.tv_sec -= epoch;
+ return (
+ ((uint64_t)(tv.tv_sec) * 1000) + (uint64_t)(tv.tv_usec / 1000));
+#endif
+
+#ifdef _WIN32
+#else
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+}
+
+bool
+testutil_pollfd(int fd)
+{
+#ifdef _WIN32
+ struct pollfd pfd;
+ pfd.fd = (SOCKET) fd;
+ pfd.events = POLLRDNORM;
+ pfd.revents = 0;
+
+ switch (WSAPoll(&pfd, 1, 0)) {
+ case 0:
+ return (false);
+ case 1:
+ return (true);
+ }
+#else
+ struct pollfd pfd;
+
+ pfd.fd = fd;
+ pfd.events = POLLRDNORM;
+ pfd.revents = 0;
+
+ switch (poll(&pfd, 1, 0)) {
+ case 0:
+ return (false);
+ case 1:
+ return (true);
+ }
+#endif
+ return (false);
+}
+
+uint16_t
+testutil_htons(uint16_t in)
+{
+#ifdef NNG_LITTLE_ENDIAN
+ in = ((in >> 8u) & 0xffu) | ((in & 0xffu) << 8u);
+#endif
+ return (in);
+}
+
+// testutil_next_port returns a "next" allocation port.
+// Ports are chosen by starting from a random point within a
+// range (normally 38000-40000, but other good places to choose
+// might be 36000-37000, 42000-43000, 45000-47000, 48000-49000.
+// These are non-ephemeral ports. Successive calls to this function
+// will return the next port in the range (wrapping). This works even
+// across process boundaries, as the range is tracked in a file named
+// by $TEST_PORT_FILE. The range of ports can be configured by using
+// $TEST_PORT_RANGE (the range is specified as "lo:hi" where the actual
+// port will be in the range [lo,hi).
+uint16_t
+testutil_next_port(void)
+{
+ char * pfile;
+ FILE * f;
+ uint16_t port;
+ uint16_t base;
+ uint16_t end;
+ char * str;
+#ifdef _WIN32
+ OVERLAPPED olp;
+ HANDLE h;
+#endif
+
+ pfile = getenv("TEST_PORT_FILE");
+ if (pfile == NULL) {
+ pfile = ".nng_ports";
+ }
+ if (((str = getenv("TEST_PORT_RANGE")) == NULL) ||
+ ((sscanf(str, "%hu:%hu", &base, &end)) != 1) ||
+ ((int) end - (int) base) < 1) {
+ base = 38000;
+ end = 40000;
+ }
+
+ if (((f = fopen(pfile, "r+")) == NULL) &&
+ ((f = fopen(pfile, "w+")) == NULL)) {
+ return (0);
+ }
+ (void) fseek(f, 0, SEEK_SET);
+
+#ifdef _WIN32
+ h = (HANDLE) _get_osfhandle(_fileno(f));
+
+ // This contains the offset information for LockFileEx.
+ ZeroMemory(&olp, sizeof(olp));
+
+ if (LockFileEx(h, LOCKFILE_EXCLUSIVE_LOCK, 0, MAXDWORD, MAXDWORD,
+ &olp) == FALSE) {
+ fclose(f);
+ return (0);
+ }
+#else
+ if (lockf(fileno(f), 0, F_LOCK) != 0) {
+ (void) fclose(f);
+ return (0);
+ }
+#endif
+ if (fscanf(f, "%hu", &port) != 1) {
+ unsigned seed = (unsigned) time(NULL);
+
+#ifdef _WIN32
+ port = base + rand_s(&seed) % (end - base);
+#else
+ port = base + rand_r(&seed) % (end - base);
+#endif
+ }
+ port++;
+ if ((port < base) || (port >= (base + end))) {
+ port = base;
+ }
+
+#ifdef _WIN32
+ fseek(f, 0, SEEK_SET);
+ SetEndOfFile(h);
+ (void) fprintf(f, "%u", port);
+ ZeroMemory(&olp, sizeof(olp));
+ (void) UnlockFileEx(h, 0, MAXDWORD, MAXDWORD, &olp);
+#else
+ fseek(f, 0, SEEK_SET);
+ ftruncate(fileno(f), 0);
+
+ (void) fprintf(f, "%u", port);
+ (void) lockf(fileno(f), 0, F_ULOCK);
+
+#endif
+ (void) fclose(f);
+ return (port);
+}
+
+void
+testutil_sleep(int msec)
+{
+#ifdef _WIN32
+ Sleep(msec);
+#elif defined(CLOCK_MONOTONIC)
+ struct timespec ts;
+
+ ts.tv_sec = msec / 1000;
+ ts.tv_nsec = (msec % 1000) * 1000000;
+
+ // Do this in a loop, so that interrupts don't actually wake us.
+ while (ts.tv_sec || ts.tv_nsec) {
+ if (nanosleep(&ts, &ts) == 0) {
+ break;
+ }
+ }
+#else
+ poll(NULL, 0, msec);
+#endif
+}
+
+struct marriage_notice {
+ nng_mtx *mx;
+ nng_cv * cv;
+ int s1;
+ int s2;
+ int cnt1;
+ int cnt2;
+};
+
+static void
+married(nng_pipe p, nng_pipe_ev ev, void *arg)
+{
+ struct marriage_notice *notice = arg;
+ (void) p;
+ (void) ev;
+
+ nng_mtx_lock(notice->mx);
+ if (nng_socket_id(nng_pipe_socket(p)) == notice->s1) {
+ notice->cnt1++;
+ } else if (nng_socket_id(nng_pipe_socket(p)) == notice->s2) {
+ notice->cnt2++;
+ }
+ nng_cv_wake(notice->cv);
+ nng_mtx_unlock(notice->mx);
+}
+
+int
+testutil_marry(nng_socket s1, nng_socket s2)
+{
+ struct marriage_notice note;
+ nng_time timeout;
+ int rv;
+ char addr[32];
+
+ (void) snprintf(addr, sizeof(addr), "inproc://marry%04x%04x%04x%04x",
+ nng_random(), nng_random(), nng_random(), nng_random());
+
+ note.cnt1 = 0;
+ note.cnt2 = 0;
+ note.s1 = nng_socket_id(s1);
+ note.s2 = nng_socket_id(s2);
+ timeout = nng_clock() + 1000; // 1 second
+
+ if (((rv = nng_mtx_alloc(&note.mx)) != 0) ||
+ ((rv = nng_cv_alloc(&note.cv, note.mx)) != 0) ||
+ ((rv = nng_pipe_notify(
+ s1, NNG_PIPE_EV_ADD_POST, married, &note)) != 0) ||
+ ((rv = nng_pipe_notify(
+ s2, NNG_PIPE_EV_ADD_POST, married, &note)) != 0) ||
+ ((rv = nng_listen(s1, addr, NULL, 0)) != 0) ||
+ ((rv = nng_dial(s2, addr, NULL, 0)) != 0)) {
+ goto done;
+ }
+
+ nng_mtx_lock(note.mx);
+ while ((note.cnt1 == 0) || (note.cnt2 == 0)) {
+ if ((rv = nng_cv_until(note.cv, timeout)) != 0) {
+ break;
+ }
+ }
+ nng_mtx_unlock(note.mx);
+
+done:
+ nng_pipe_notify(s1, NNG_PIPE_EV_ADD_POST, NULL, NULL);
+ nng_pipe_notify(s2, NNG_PIPE_EV_ADD_POST, NULL, NULL);
+ if (note.cv != NULL) {
+ nng_cv_free(note.cv);
+ }
+ if (note.mx != NULL) {
+ nng_mtx_free(note.mx);
+ }
+ return (rv);
+} \ No newline at end of file
diff --git a/tests/testutil.h b/tests/testutil.h
new file mode 100644
index 00000000..97540f36
--- /dev/null
+++ b/tests/testutil.h
@@ -0,0 +1,49 @@
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#ifndef TESTUTIL_H
+#define TESTUTIL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+// The following headers are provided for test code convenience.
+#include <nng/nng.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// testutil_clock returns the current time in milliseconds.
+// The reference clock may be any point in the past (typically since
+// the program started running.)
+extern uint64_t testutil_clock(void);
+
+// testutil_pollfd tests if the given file descriptor polls as readable.
+extern bool testutil_pollfd(int);
+
+// testutil_htons is just htons portably.
+extern uint16_t testutil_htons(uint16_t);
+
+// testutil_sleep sleeps the specified number of msec
+extern void testutil_sleep(int);
+
+// testutil_next_port returns a new port number (presumably unique)
+extern uint16_t testutil_next_port(void);
+
+// testutil_marry connects two sockets using inproc. It uses socket
+// pipe hooks to ensure that it does not return before both sockets
+// are fully connected.
+extern int testutil_marry(nng_socket, nng_socket);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // TESTUTIL_H