[tor-commits] [tor/master] Upgrade to the latest version of tinytest.

nickm at torproject.org nickm at torproject.org
Thu Mar 6 23:07:15 UTC 2014


commit 1365ff5b9a04a7da2acc2e52df18a61b6cb39fe6
Author: Nick Mathewson <nickm at torproject.org>
Date:   Thu Mar 6 18:06:08 2014 -0500

    Upgrade to the latest version of tinytest.
    
    This brings us to tinytest commit 709a36ba63ff16d8.
    
    The only big change tor-side is that we don't need our own test_mem_op
    operation any longer.
---
 changes/tinytest_upgrade  |    2 +
 src/ext/tinytest.c        |  150 ++++++++++++++++++++++++++++++++++++++-------
 src/ext/tinytest.h        |   19 +++++-
 src/ext/tinytest_demo.c   |   45 ++++++++++++++
 src/ext/tinytest_macros.h |   10 +++
 src/test/test.h           |   17 +----
 6 files changed, 202 insertions(+), 41 deletions(-)

diff --git a/changes/tinytest_upgrade b/changes/tinytest_upgrade
new file mode 100644
index 0000000..ccac402
--- /dev/null
+++ b/changes/tinytest_upgrade
@@ -0,0 +1,2 @@
+  o Testing:
+    - Update to the latest version of tinytest
diff --git a/src/ext/tinytest.c b/src/ext/tinytest.c
index 4d9afac..3a8e331 100644
--- a/src/ext/tinytest.c
+++ b/src/ext/tinytest.c
@@ -31,6 +31,8 @@
 #include <string.h>
 #include <assert.h>
 
+#ifndef NO_FORKING
+
 #ifdef _WIN32
 #include <windows.h>
 #else
@@ -39,6 +41,17 @@
 #include <unistd.h>
 #endif
 
+#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
+    __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
+/* Workaround for a stupid bug in OSX 10.6 */
+#define FORK_BREAKS_GCOV
+#include <vproc.h>
+#endif
+#endif
+
+#endif /* !NO_FORKING */
+
 #ifndef __GNUC__
 #define __attribute__(x)
 #endif
@@ -58,6 +71,8 @@ static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
 static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
 const char *verbosity_flag = "";
 
+const struct testlist_alias_t *cfg_aliases=NULL;
+
 enum outcome { SKIP=2, OK=1, FAIL=0 };
 static enum outcome cur_test_outcome = 0;
 const char *cur_test_prefix = NULL; /**< prefix of the current test group */
@@ -71,6 +86,7 @@ static char commandname[MAX_PATH+1];
 
 static void usage(struct testgroup_t *groups, int list_groups)
   __attribute__((noreturn));
+static int process_test_option(struct testgroup_t *groups, const char *test);
 
 static enum outcome
 testcase_run_bare_(const struct testcase_t *testcase)
@@ -99,6 +115,8 @@ testcase_run_bare_(const struct testcase_t *testcase)
 
 #define MAGIC_EXITCODE 42
 
+#ifndef NO_FORKING
+
 static enum outcome
 testcase_run_forked_(const struct testgroup_t *group,
 		     const struct testcase_t *testcase)
@@ -160,6 +178,9 @@ testcase_run_forked_(const struct testgroup_t *group,
 	if (opt_verbosity>0)
 		printf("[forking] ");
 	pid = fork();
+#ifdef FORK_BREAKS_GCOV
+	vproc_transaction_begin(0);
+#endif
 	if (!pid) {
 		/* child. */
 		int test_r, write_r;
@@ -196,16 +217,19 @@ testcase_run_forked_(const struct testgroup_t *group,
 #endif
 }
 
+#endif /* !NO_FORKING */
+
 int
 testcase_run_one(const struct testgroup_t *group,
 		 const struct testcase_t *testcase)
 {
 	enum outcome outcome;
 
-	if (testcase->flags & TT_SKIP) {
+	if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
 		if (opt_verbosity>0)
-			printf("%s%s: SKIPPED\n",
-			    group->prefix, testcase->name);
+			printf("%s%s: %s\n",
+			   group->prefix, testcase->name,
+			   (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
 		++n_skipped;
 		return SKIP;
 	}
@@ -218,9 +242,13 @@ testcase_run_one(const struct testgroup_t *group,
 		cur_test_name = testcase->name;
 	}
 
+#ifndef NO_FORKING
 	if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
 		outcome = testcase_run_forked_(group, testcase);
 	} else {
+#else
+	{
+#endif
 		outcome = testcase_run_bare_(testcase);
 	}
 
@@ -247,7 +275,7 @@ testcase_run_one(const struct testgroup_t *group,
 }
 
 int
-tinytest_set_flag_(struct testgroup_t *groups, const char *arg, unsigned long flag)
+tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag)
 {
 	int i, j;
 	size_t length = LONGEST_TEST_NAME;
@@ -257,12 +285,23 @@ tinytest_set_flag_(struct testgroup_t *groups, const char *arg, unsigned long fl
 		length = strstr(arg,"..")-arg;
 	for (i=0; groups[i].prefix; ++i) {
 		for (j=0; groups[i].cases[j].name; ++j) {
+			struct testcase_t *testcase = &groups[i].cases[j];
 			snprintf(fullname, sizeof(fullname), "%s%s",
-				 groups[i].prefix, groups[i].cases[j].name);
-			if (!flag) /* Hack! */
-				printf("    %s\n", fullname);
+				 groups[i].prefix, testcase->name);
+			if (!flag) { /* Hack! */
+				printf("    %s", fullname);
+				if (testcase->flags & TT_OFF_BY_DEFAULT)
+					puts("   (Off by default)");
+				else if (testcase->flags & TT_SKIP)
+					puts("  (DISABLED)");
+				else
+					puts("");
+			}
 			if (!strncmp(fullname, arg, length)) {
-				groups[i].cases[j].flags |= flag;
+				if (set)
+					testcase->flags |= flag;
+				else
+					testcase->flags &= ~flag;
 				++found;
 			}
 		}
@@ -275,15 +314,69 @@ usage(struct testgroup_t *groups, int list_groups)
 {
 	puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
 	puts("  Specify tests by name, or using a prefix ending with '..'");
-	puts("  To skip a test, list give its name prefixed with a colon.");
+	puts("  To skip a test, prefix its name with a colon.");
+	puts("  To enable a disabled test, prefix its name with a plus.");
 	puts("  Use --list-tests for a list of tests.");
 	if (list_groups) {
 		puts("Known tests are:");
-		tinytest_set_flag_(groups, "..", 0);
+		tinytest_set_flag_(groups, "..", 1, 0);
 	}
 	exit(0);
 }
 
+static int
+process_test_alias(struct testgroup_t *groups, const char *test)
+{
+	int i, j, n, r;
+	for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
+		if (!strcmp(cfg_aliases[i].name, test)) {
+			n = 0;
+			for (j = 0; cfg_aliases[i].tests[j]; ++j) {
+				r = process_test_option(groups, cfg_aliases[i].tests[j]);
+				if (r<0)
+					return -1;
+				n += r;
+			}
+			return n;
+		}
+	}
+	printf("No such test alias as @%s!",test);
+	return -1;
+}
+
+static int
+process_test_option(struct testgroup_t *groups, const char *test)
+{
+	int flag = TT_ENABLED_;
+	int n = 0;
+	if (test[0] == '@') {
+		return process_test_alias(groups, test + 1);
+	} else if (test[0] == ':') {
+		++test;
+		flag = TT_SKIP;
+	} else if (test[0] == '+') {
+		++test;
+		++n;
+		if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
+			printf("No such test as %s!\n", test);
+			return -1;
+		}
+	} else {
+		++n;
+	}
+	if (!tinytest_set_flag_(groups, test, 1, flag)) {
+		printf("No such test as %s!\n", test);
+		return -1;
+	}
+	return n;
+}
+
+void
+tinytest_set_aliases(const struct testlist_alias_t *aliases)
+{
+	cfg_aliases = aliases;
+}
+
 int
 tinytest_main(int c, const char **v, struct testgroup_t *groups)
 {
@@ -321,24 +414,18 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups)
 				return -1;
 			}
 		} else {
-			const char *test = v[i];
-			int flag = TT_ENABLED_;
-			if (test[0] == ':') {
-				++test;
-				flag = TT_SKIP;
-			} else {
-				++n;
-			}
-			if (!tinytest_set_flag_(groups, test, flag)) {
-				printf("No such test as %s!\n", v[i]);
+			int r = process_test_option(groups, v[i]);
+			if (r<0)
 				return -1;
-			}
+			n += r;
 		}
 	}
 	if (!n)
-		tinytest_set_flag_(groups, "..", TT_ENABLED_);
+		tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
 
+#ifdef _IONBF
 	setvbuf(stdout, NULL, _IONBF, 0);
+#endif
 
 	++in_tinytest_main;
 	for (i=0; groups[i].prefix; ++i)
@@ -385,3 +472,22 @@ tinytest_set_test_skipped_(void)
 		cur_test_outcome = SKIP;
 }
 
+char *
+tinytest_format_hex_(const void *val_, unsigned long len)
+{
+	const unsigned char *val = val_;
+	char *result, *cp;
+	size_t i;
+
+	if (!val)
+		return strdup("null");
+	if (!(result = malloc(len*2+1)))
+		return strdup("<allocation failure>");
+	cp = result;
+	for (i=0;i<len;++i) {
+		*cp++ = "0123456789ABCDEF"[val[i] >> 4];
+		*cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
+	}
+	*cp = 0;
+	return result;
+}
diff --git a/src/ext/tinytest.h b/src/ext/tinytest.h
index bcac9f0..ed07b26 100644
--- a/src/ext/tinytest.h
+++ b/src/ext/tinytest.h
@@ -32,8 +32,10 @@
 #define TT_SKIP  (1<<1)
 /** Internal runtime flag for a test we've decided to run. */
 #define TT_ENABLED_  (1<<2)
+/** Flag for a test that's off by default. */
+#define TT_OFF_BY_DEFAULT  (1<<3)
 /** If you add your own flags, make them start at this point. */
-#define TT_FIRST_USER_FLAG (1<<3)
+#define TT_FIRST_USER_FLAG (1<<4)
 
 typedef void (*testcase_fn)(void *);
 
@@ -64,6 +66,12 @@ struct testgroup_t {
 };
 #define END_OF_GROUPS { NULL, NULL}
 
+struct testlist_alias_t {
+	const char *name;
+	const char **tests;
+};
+#define END_OF_ALIASES { NULL, NULL }
+
 /** Implementation: called from a test to indicate failure, before logging. */
 void tinytest_set_test_failed_(void);
 /** Implementation: called from a test to indicate that we're skipping. */
@@ -72,14 +80,19 @@ void tinytest_set_test_skipped_(void);
 int tinytest_get_verbosity_(void);
 /** Implementation: Set a flag on tests matching a name; returns number
  * of tests that matched. */
-int tinytest_set_flag_(struct testgroup_t *, const char *, unsigned long);
+int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long);
+/** Implementation: Put a chunk of memory into hex. */
+char *tinytest_format_hex_(const void *, unsigned long);
 
 /** Set all tests in 'groups' matching the name 'named' to be skipped. */
 #define tinytest_skip(groups, named) \
-	tinytest_set_flag_(groups, named, TT_SKIP)
+	tinytest_set_flag_(groups, named, 1, TT_SKIP)
 
 /** Run a single testcase in a single group. */
 int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
+
+void tinytest_set_aliases(const struct testlist_alias_t *aliases);
+
 /** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
     as selected from the command line. */
 int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
diff --git a/src/ext/tinytest_demo.c b/src/ext/tinytest_demo.c
index be95ce4..bdd0e60 100644
--- a/src/ext/tinytest_demo.c
+++ b/src/ext/tinytest_demo.c
@@ -35,6 +35,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <time.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
 
 /* ============================================================ */
 
@@ -148,6 +152,9 @@ test_memcpy(void *ptr)
 	memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
 	tt_str_op(db->buffer1, ==, db->buffer2);
 
+        /* This one works if there's an internal NUL. */
+        tt_mem_op(db->buffer1, <, db->buffer2, sizeof(db->buffer1));
+
 	/* Now we've allocated memory that's referenced by a local variable.
 	   The end block of the function will clean it up. */
 	mem = strdup("Hello world.");
@@ -162,6 +169,27 @@ test_memcpy(void *ptr)
 		free(mem);
 }
 
+void
+test_timeout(void *ptr)
+{
+	time_t t1, t2;
+	(void)ptr;
+	t1 = time(NULL);
+#ifdef _WIN32
+	Sleep(5000);
+#else
+	sleep(5);
+#endif
+	t2 = time(NULL);
+
+	tt_int_op(t2-t1, >=, 4);
+
+	tt_int_op(t2-t1, <=, 6);
+
+ end:
+	;
+}
+
 /* ============================================================ */
 
 /* Now we need to make sure that our tests get invoked.	  First, you take
@@ -178,6 +206,10 @@ struct testcase_t demo_tests[] = {
 	   its environment. */
 	{ "memcpy", test_memcpy, TT_FORK, &data_buffer_setup },
 
+	/* This flag is off-by-default, since it takes a while to run.	You
+	 * can enable it manually by passing +demo/timeout at the command line.*/
+	{ "timeout", test_timeout, TT_OFF_BY_DEFAULT },
+
 	/* The array has to end with END_OF_TESTCASES. */
 	END_OF_TESTCASES
 };
@@ -192,6 +224,18 @@ struct testgroup_t groups[] = {
 	END_OF_GROUPS
 };
 
+/* We can also define test aliases. These can be used for types of tests that
+ * cut across groups. */
+const char *alltests[] = { "+..", NULL };
+const char *slowtests[] = { "+demo/timeout", NULL };
+struct testlist_alias_t aliases[] = {
+
+	{ "ALL", alltests },
+	{ "SLOW", slowtests },
+
+	END_OF_ALIASES
+};
+
 
 int
 main(int c, const char **v)
@@ -211,5 +255,6 @@ main(int c, const char **v)
 	   "tinytest-demo" and "tinytest-demo .." mean the same thing.
 
 	*/
+	tinytest_set_aliases(aliases);
 	return tinytest_main(c, v, groups);
 }
diff --git a/src/ext/tinytest_macros.h b/src/ext/tinytest_macros.h
index 5bb8f8e..db2dfcb 100644
--- a/src/ext/tinytest_macros.h
+++ b/src/ext/tinytest_macros.h
@@ -171,6 +171,16 @@
 	    (val1_ && val2_ && strcmp(val1_,val2_) op 0),"<%s>",	\
 	    TT_EXIT_TEST_FUNCTION)
 
+#define tt_mem_op(expr1, op, expr2, len)                                \
+  tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2,            \
+			  const char *,                                 \
+			  (val1_ && val2_ && memcmp(val1_, val2_, len) op 0), \
+			  char *, "%s",					\
+			  { print_ = tinytest_format_hex_(value_, (len)); }, \
+			  { if (print_) free(print_); },		\
+			  TT_EXIT_TEST_FUNCTION				\
+                          );
+
 #define tt_want_int_op(a,op,b)						\
 	tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0)
 
diff --git a/src/test/test.h b/src/test/test.h
index b902c6e..ba82f52 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -36,22 +36,7 @@
 #define test_strneq(expr1, expr2) tt_str_op((expr1), !=, (expr2))
 
 #define test_mem_op(expr1, op, expr2, len)                              \
-  tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2,            \
-                          const char *,                                 \
-                          (val1_ && val2_ && memcmp(val1_, val2_, len) op 0), \
-                          char *, "%s",                                 \
-                          { size_t printlen = (len)*2+1;                \
-                            if (value_) {                               \
-                              print_ = tor_malloc(printlen);            \
-                              base16_encode(print_, printlen, value_,   \
-                                            (len));                     \
-                            } else {                                    \
-                              print_ = tor_strdup("null");              \
-                            }                                           \
-                          },                                            \
-                          { tor_free(print_); },                        \
-                          TT_EXIT_TEST_FUNCTION                         \
-                          );
+  tt_mem_op((expr1), op, (expr2), (len))
 
 #define test_memeq(expr1, expr2, len) test_mem_op((expr1), ==, (expr2), len)
 #define test_memneq(expr1, expr2, len) test_mem_op((expr1), !=, (expr2), len)



More information about the tor-commits mailing list