aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2016-12-15 22:07:49 -0800
committerGarrett D'Amore <garrett@damore.org>2016-12-15 22:07:49 -0800
commit2fea9b850333d8f48e83fbbd87921f47c1fa8bb5 (patch)
treed92973acba58636f06d644de14ee06954f1768c2 /tests
parent474168faf403fc9e9733c7bcb826773dc00eced1 (diff)
downloadnng-2fea9b850333d8f48e83fbbd87921f47c1fa8bb5.tar.gz
nng-2fea9b850333d8f48e83fbbd87921f47c1fa8bb5.tar.bz2
nng-2fea9b850333d8f48e83fbbd87921f47c1fa8bb5.zip
Early test framework, modeled on GoConvey.
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt56
-rw-r--r--tests/demo.c33
-rw-r--r--tests/test.c86
-rw-r--r--tests/test.h176
4 files changed, 351 insertions, 0 deletions
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 */