Commit 1365ff5b authored by Nick Mathewson's avatar Nick Mathewson 🥔
Browse files

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.
parent 065097b8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
  o Testing:
    - Update to the latest version of tinytest
+128 −22
Original line number Diff line number Diff line
@@ -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;
}
+16 −3
Original line number Diff line number Diff line
@@ -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);
+45 −0
Original line number Diff line number Diff line
@@ -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);
}
+10 −0
Original line number Diff line number Diff line
@@ -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)

Loading