diff options
| -rw-r--r-- | CMakeLists.txt | 89 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 56 | ||||
| -rw-r--r-- | tests/demo.c | 33 | ||||
| -rw-r--r-- | tests/test.c | 86 | ||||
| -rw-r--r-- | tests/test.h | 176 |
5 files changed, 353 insertions, 87 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d94ecd26..d41a5b2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,6 +205,8 @@ endif () add_subdirectory (src) +add_subdirectory (tests) + # Build the tools if (NNG_ENABLE_NNGCAT) @@ -305,93 +307,6 @@ if (NNG_ENABLE_DOC) endif () -# Build unit tests. - -if (NNG_TESTS) - - enable_testing () - set (all_tests "") - - set (TEST_PORT 12100) - macro (add_libnng_test NAME TIMEOUT) - list (APPEND all_tests ${NAME}) - add_executable (${NAME} tests/${NAME}.c) - 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 "${TEST_PORT}+10") - endmacro (add_libnng_test) - - # Transport tests. - #add_libnng_test (inproc 5) - #add_libnng_test (inproc_shutdown 5) - #add_libnng_test (ipc 5) - #add_libnng_test (ipc_shutdown 30) - #add_libnng_test (ipc_stress 5) - #add_libnng_test (tcp 5) - #add_libnng_test (tcp_shutdown 120) - #add_libnng_test (ws 5) - - # Protocol tests. - #add_libnng_test (pair 5) - #add_libnng_test (pubsub 5) - #add_libnng_test (reqrep 5) - #add_libnng_test (pipeline 5) - #add_libnng_test (survey 5) - #add_libnng_test (bus 5) - - # Feature tests. - #add_libnng_test (async_shutdown 30) - #add_libnng_test (block 5) - #add_libnng_test (term 5) - #add_libnng_test (timeo 5) - #add_libnng_test (iovec 5) - #add_libnng_test (msg 5) - #add_libnng_test (prio 5) - #add_libnng_test (poll 5) - #add_libnng_test (device 5) - #add_libnng_test (device4 5) - #add_libnng_test (device5 5) - #add_libnng_test (device6 5) - #add_libnng_test (device7 30) - #add_libnng_test (emfile 5) - #add_libnng_test (domain 5) - #add_libnng_test (trie 5) - #add_libnng_test (list 5) - #add_libnng_test (hash 5) - #add_libnng_test (stats 5) - #add_libnng_test (symbol 5) - #add_libnng_test (separation 5) - #add_libnng_test (zerocopy 5) - #add_libnng_test (shutdown 5) - #add_libnng_test (cmsg 5) - #add_libnng_test (bug328 5) - #add_libnng_test (bug777 5) - #add_libnng_test (ws_async_shutdown 5) - #add_libnng_test (reqttl 10) - #add_libnng_test (surveyttl 10) - - # Platform-specific tests - #if (WIN32) - # add_libnng_test (win_sec_attr 5) - #endif() - - # Build the performance tests. - - macro (add_libnng_perf NAME) - add_executable (${NAME} perf/${NAME}.c) - target_link_libraries (${NAME} ${PROJECT_NAME}) - endmacro (add_libnng_perf) - - #add_libnng_perf (inproc_lat) - #add_libnng_perf (inproc_thr) - #add_libnng_perf (local_lat) - #add_libnng_perf (remote_lat) - #add_libnng_perf (local_thr) - #add_libnng_perf (remote_thr) - -endif () - install (TARGETS LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install (TARGETS ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install (FILES src/nng.h DESTINATION include/nng) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 00000000..1d8bcad5 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,56 @@ +# +# 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 Garrett D'Amore <garrett@damore.org> +# Copyright 2016 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com> +# +# 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. +# + +# Build unit tests. + +if (NNG_TESTS) + + enable_testing () + set (all_tests "") + + set (TEST_PORT 12100) + macro (add_nng_test NAME TIMEOUT) + list (APPEND all_tests ${NAME}) + add_executable (${NAME} ${NAME}.c test.c) + 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 "${TEST_PORT}+10") + endmacro (add_nng_test) + + macro (add_nng_perf NAME) + add_executable (${NAME} perf/${NAME}.c) + target_link_libraries (${NAME} ${PROJECT_NAME}) + endmacro (add_nng_perf) + +else () + macro (add_nng_test NAME TIMEOUT) + endmacro (add_nng_test) + macro (add_nng_perf NAME) + endmacro (add_nng_perf) +endif () + +add_nng_test(demo 5) diff --git a/tests/demo.c b/tests/demo.c new file mode 100644 index 00000000..2b874b9e --- /dev/null +++ b/tests/demo.c @@ -0,0 +1,33 @@ +#include <stdio.h> +#include "test.h" + +test_main("Things work", { + int x; + int y; + x = 1; + y = 2; + test_convey("X is one", { + test_assert(x == 1); + }); + test_convey("Y is two", { + test_so(y == 2); + y = 3; + test_so(y == 3); + }); + +test_convey("Bounce", { + test_convey("Arithmetic", { + test_so(y == 2); + test_convey("Addition", { + test_so(x + y == 3); + test_so(x + y + y == 5); + y = 5; + test_so(x + y == 6); + }); + test_convey("Subtraction", { + test_so(x - y == -1); + test_so(y - x == 1); + }); + }); +}); +}) diff --git a/tests/test.c b/tests/test.c new file mode 100644 index 00000000..2a881307 --- /dev/null +++ b/tests/test.c @@ -0,0 +1,86 @@ +/* + * Copyright 2016 Garrett D'Amore <garrett@damore.org> + * + * 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. + */ + +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <setjmp.h> +#include <stdarg.h> + +#include "test.h" + +test_ctx_t *T_C = NULL; + +void +test_ctx_print_start(test_ctx_t *ctx) +{ + int i; + if (ctx->T_printed) { + return; + } + ctx->T_printed = 1; + if (ctx->T_root) { + printf("\n=== RUN: %s\n", ctx->T_name); + } else { + printf("\n"); + for (i = 0; i < ctx->T_level; i++) { + printf(" "); + } + printf("%s ", ctx->T_name); + fflush(stdout); + } +} + +void +test_ctx_print_result(test_ctx_t *ctx) +{ + if (ctx->T_root) { + printf("\n\n--- %s: %s\n", + ctx->T_fatal ? "FATAL" : + ctx->T_fail ? "FAIL" : + ctx->T_skip ? "SKIP" : + "PASS", ctx->T_name); + } +} + +void +test_ctx_log(test_ctx_t ctx, const char *fmt, ...) +{ +} + +void +test_ctx_fatal(test_ctx_t *ctx, const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + printf("FATALITY: "); + vprintf(fmt, va); + printf("\n"); +} + +extern int test_main_impl(void); + +int +main(int argc, char **argv) +{ + test_main_impl(); +}
\ No newline at end of file diff --git a/tests/test.h b/tests/test.h new file mode 100644 index 00000000..3be760b2 --- /dev/null +++ b/tests/test.h @@ -0,0 +1,176 @@ + +/* + * Copyright 2016 Garrett D'Amore <garrett@damore.org> + * + * 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 TESTS_TEST_H + +#define TESTS_TEST_H + +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <setjmp.h> +#include <stdarg.h> + +/* + * This test framework allows one to write tests as a form of assertion, + * giving simpler and more readable test logic. + * + * The test framework provides a main() function. + * + * To use this call the test_main() macro, and embed test_convey() references. + * These can be nested, and after each convey the entire stack is popped so + * that execution can continue from the beginning, giving each test section + * the same environment. + * + * There are assertion macros too, which don't roll back the stack, but which + * do update the test state. + * + * Here's a sample file: + * + * test_main("Integer Tests", { + * int x = 1; int y = 2; + * test_convey("Addition works", func() { + * test_so(y == 2); + * test_so(y + x == 3); + * test_so(x + y == 3); + * test_convey("Even big numbers", func() { + * y = 100; + * test_so(x + y == 101); + * }); + * test_convey("Notice y is still 2 in this context", func() { + * test_so(y == 2); + * }); + * }); + * }) + * + * There are other macros, but this is a work in progress. The inspiration + * for this is from GoConvey -- github.com/smartystreets/goconvey - but this + * is a version for C programs. + */ + +typedef struct test_ctx { + const char *T_name; + jmp_buf T_jmp; + void (*T_cleanup_fn)(void *); + void *T_cleanup_arg; + int T_fail; + int T_fatal; + int T_skip; + int T_asserts; + int T_good; + int T_bad; + int T_done; + int T_root; + int T_level; + int T_printed; + struct test_ctx *T_parent; +} test_ctx_t; + +extern test_ctx_t *T_C; + +#define test_ctx_do(T_xparent, T_xname, T_xcode) \ +do { \ + static test_ctx_t T_ctx; \ + T_ctx.T_name = T_xname; \ + T_ctx.T_parent = T_xparent; \ + if (T_xparent != NULL) { \ + T_ctx.T_level = T_xparent->T_level + 1; \ + T_ctx.T_root = 0; \ + } else { \ + T_ctx.T_root = 1; \ + T_ctx.T_level = 0; \ + } \ + if (T_ctx.T_done) { \ + test_ctx_print_result(&T_ctx); \ + break; \ + } \ + if (setjmp(T_ctx.T_jmp) != 0) { \ + if (T_ctx.T_cleanup_fn != NULL) { \ + T_ctx.T_cleanup_fn(T_ctx.T_cleanup_arg); \ + } \ + if (!T_ctx.T_root) { \ + longjmp(T_ctx.T_parent->T_jmp, 1); \ + } \ + if (T_ctx.T_done) { \ + test_ctx_print_result(&T_ctx); \ + break; \ + } \ + } \ + test_ctx_print_start(&T_ctx); \ + do { \ + T_C = &T_ctx; \ + { T_xcode } \ + T_ctx.T_done = 1; \ + } while (0); \ + longjmp(T_ctx.T_jmp, 1); \ +} while (0); + +#define test_main(name, code) \ +int test_main_impl(void) { \ + static test_ctx_t ctx; \ + test_ctx_t *T_null = NULL; \ + ctx.T_root = 1; \ + test_ctx_t *T_xctx = &ctx; \ + test_ctx_do(T_null, name, code); \ + return (ctx.T_fatal ? 2 : ctx.T_fail ? 1 : 0); \ +} + +#define test_ctx_convey(T_xparent, T_xname, T_xcode) \ +{ \ + test_ctx_do( T_xparent, T_xname, T_xcode); \ +} + +#define test_convey(T_xname, T_xcode) test_ctx_convey(T_C, T_xname, T_xcode) + + +#define test_ctx_assert(T_xctx, T_cond) \ + if (!(T_cond)) { \ + T_xctx->T_bad++; \ + test_ctx_fatal(T_xctx, "%s: %d: Assertion failed: %s", \ + __FILE__, __LINE__, #T_cond); \ + } else { \ + printf("."); \ + T_xctx->T_good++; \ + } + +#define test_assert(T_cond) test_ctx_assert(T_C, T_cond) + +#define test_ctx_so(T_xctx, T_cond) \ + if (!(T_cond)) { \ + printf("X"); \ + T_xctx->T_bad++; \ + } else { \ + printf("."); \ + T_xctx->T_good++; \ + } + +#define test_so(T_cond) test_ctx_so(T_C, T_cond) + +#define test_assert(T_cond) test_ctx_assert(T_C, T_cond) + +extern void test_ctx_print_start(test_ctx_t *); +extern void test_ctx_print_result(test_ctx_t *); +extern void test_ctx_fatal(test_ctx_t *ctx, const char *fmt, ...); +extern int test_main_impl(void); + +#endif /* TEST_TEST_H */ |
