aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2016-12-18 21:31:43 -0800
committerGarrett D'Amore <garrett@damore.org>2016-12-18 21:31:43 -0800
commit99dcb2df6ee30004b9fbac1cc2360c6e627dc449 (patch)
treee2092158c1ab3f62881c66a9e5d3b66d742fa755
parent260ce618d98c9ec732362ab82b2efeb2c412ac24 (diff)
downloadnng-99dcb2df6ee30004b9fbac1cc2360c6e627dc449.tar.gz
nng-99dcb2df6ee30004b9fbac1cc2360c6e627dc449.tar.bz2
nng-99dcb2df6ee30004b9fbac1cc2360c6e627dc449.zip
Added support for test_reset(), better than cleanup or other hacks.
-rw-r--r--tests/demo.c29
-rw-r--r--tests/test.c6
-rw-r--r--tests/test.h77
3 files changed, 72 insertions, 40 deletions
diff --git a/tests/demo.c b/tests/demo.c
index 9ff70727..e831109a 100644
--- a/tests/demo.c
+++ b/tests/demo.c
@@ -62,4 +62,33 @@ test_main_group({
test_so(x == 1);
});
});
+
+ test_group("Reset group", {
+ static int x = 0;
+ static int y = 0;
+ test_reset({
+ x = 20;
+ });
+ test_convey("Add one to both y and x", {
+ x++;
+ y++;
+ test_so(x == 1); /* no reset yet */
+ test_so(y == 1);
+ });
+ test_convey("Again", {
+ x++;
+ y++;
+ test_so(x == 21);
+ test_so(y == 2);
+ });
+ test_convey("Third time", {
+ x++;
+ y++;
+ test_so(x == 21);
+ test_so(y == 3);
+ });
+
+ test_so(x == 20);
+ test_so(y == 3);
+ });
})
diff --git a/tests/test.c b/tests/test.c
index 1fb99113..ae4eab20 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -171,6 +171,7 @@ print_result(tctx_t *t)
log_free(t->t_fatallog);
}
t = t->t_next;
+ memset(freeit, 0, sizeof (*freeit));
free(freeit);
}
}
@@ -270,7 +271,6 @@ test_i_loop(test_ctx_t *ctx, int unwind)
return (1);
}
}
-
if (!t->t_started) {
t->t_started = 1;
@@ -617,9 +617,9 @@ log_dump(tlog_t *log, const char *header, const char *color)
return;
}
- printf("\n\n%s%s%s\n\n", color, header, color_none);
+ (void) printf("\n\n%s%s%s\n\n", color, header, color_none);
for (s = STRTOK(log->l_buf, "\n"); s != NULL; s = STRTOK(NULL, "\n")) {
- printf(" %s%s%s\n", color, s, color_none);
+ (void) printf(" %s%s%s\n", color, s, color_none);
}
}
diff --git a/tests/test.h b/tests/test.h
index b14101f6..454cb25d 100644
--- a/tests/test.h
+++ b/tests/test.h
@@ -100,25 +100,24 @@ extern void test_i_fatal(const char *, int, const char *);
* code. It has to be here exposed, in order for setjmp() to work.
* and for the code block to be inlined.
*/
-#define test_i_run(T_name, T_code, T_reset, T_rvp) \
+#define test_i_run(T_name, T_code, T_rvp) \
do { \
static test_ctx_t T_ctx; \
int T_unwind; \
+ int T_break = 0; \
if (test_i_start(&T_ctx, T_name) != 0) { \
break; \
} \
T_unwind = setjmp(T_ctx.T_jmp); \
- if (T_unwind) { \
- do { \
- T_reset \
- } while (0); \
- } \
if (test_i_loop(&T_ctx, T_unwind) != 0) { \
break; \
} \
do { \
T_code \
} while (0); \
+ if (T_break) { \
+ break; \
+ } \
test_i_finish(&T_ctx, T_rvp); \
} while (0)
@@ -130,7 +129,7 @@ extern void test_i_fatal(const char *, int, const char *);
#define test_main(T_name, T_code) \
int test_main_impl(void) { \
int T_rv; \
- test_i_run(T_name, T_code, /*NOP*/, &T_rv); \
+ test_i_run(T_name, T_code, &T_rv); \
return (T_rv); \
} \
int main(int argc, char **argv) { \
@@ -141,8 +140,7 @@ extern void test_i_fatal(const char *, int, const char *);
* If you want multiple top-level tests in your test suite, the test
* code should create a test_main_group(), with multiple calls to
* test_group() in the intervening section. This will cause a new main
- * to be emitted that runs all the main groups. If a rest for the group
- * is required, it can be supplied with test_group_reset.
+ * to be emitted that runs all the main groups.
*/
#define test_main_group(T_code) \
static int test_main_rv; \
@@ -156,18 +154,15 @@ extern void test_i_fatal(const char *, int, const char *);
return (test_i_main(argc, argv)); \
}
-#define test_group_reset(T_name, T_code, T_reset) \
+#define test_group(T_name, T_code) \
do { \
int T_rv; \
- test_i_run(T_name, T_code, T_reset, &T_rv); \
+ test_i_run(T_name, T_code, &T_rv); \
if (T_rv > test_main_rv) { \
test_main_rv = T_rv; \
- } \
+ }; \
} while (0)
-#define test_group(T_name, T_code) \
- test_group_reset(T_name, T_code, /*NOP*/)
-
/*
* If you don't want to use the test framework's main routine, but
* prefer (or need, because of threading for example) to have your
@@ -180,8 +175,7 @@ extern void test_i_fatal(const char *, int, const char *);
* memory in the test framework, and anything else indicates a
* an error or failure in the code being tested.
*/
-#define test_block(T_name, T_code, T_reset) \
- test_i_run(T_name, T_code, T_reset, NULL)
+#define test_block(T_name, T_code) test_i_run(T_name, T_code, NULL)
/*
* test_assert and test_so allow you to run assertions.
@@ -204,29 +198,14 @@ extern void test_i_fatal(const char *, int, const char *);
} \
} while (0)
-/*
- * These are convenience versions that use the "global" context.
- * Note that normally convey() will create its own contexts. These
- * are the macros you should use.
- */
/*
* test_convey(name, <code>) starts a convey context, with <code> as
* the body. The <code> is its scope, and may be called repeatedly
* within the body of a loop.
*/
-#define test_convey(T_name, T_code) \
- test_i_run(T_name, T_code, /*NOP*/, NULL)
+#define test_convey(T_name, T_code) test_i_run(T_name, T_code, NULL)
-/*
- * test_convey_reset is like convey, but offers the ability to specify
- * a reset block of code, which will run to clean up after each nested
- * convey, or when the code completes. (Note that any code placed *after*
- * conveys is executed as part of the current context, which can be
- * another way to clean up code just once.)
- */
-#define test_convey_reset(T_name, T_code, T_reset) \
- test_i_run(T_name, T_code, T_reset, NULL)
/*
* test_skip() just stops processing of the rest of the current context,
@@ -251,11 +230,35 @@ extern void test_i_fatal(const char *, int, const char *);
test_convey(T_name, test_skip())
/*
- * test_get_context obtains the current context. It uses thread local
- * storage in the event that threading is in use. This means by default
- * conveys started in new threads will have their own root contexts.
+ * test_reset establishes a reset for the current block. This code will
+ * be executed every time the current block is unwinding. This means that
+ * the code will be executed each time a child convey exits. It is also
+ * going to be executed once more, for the final pass, which doesn't actually
+ * execute any convey blocks. (This final pass is required in order to
+ * learn that all convey's, as well as any code beyond them, are complete.)
+ *
+ * The way this works is by overriding the existing block's jump buffer.
+ *
+ * Unlike with GoConvey, this must be registered before any children
+ * convey blocks; the logic only affects convey blocks that follow this
+ * one, within the same scope.
+ *
+ * It is possible to have a subsequent reset at the same convey scope
+ * override a prior reset. Normally you should avoid this, and just
+ * use lower level convey blocks.
*/
-extern test_ctx_t *test_get_context(void);
+#define test_reset(T_reset_code) \
+ T_unwind = setjmp(T_ctx.T_jmp); \
+ if (T_unwind) { \
+ do { \
+ T_reset_code \
+ } while (0); \
+ } \
+ if (test_i_loop(&T_ctx, T_unwind) != 0) { \
+ T_break = 1; \
+ break; \
+ }
+
/*
* test_init sets up initial things required for testing. If you don't