tests: Refactor testlib to simplify and fix Cygwin build

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
diff --git a/libusb/os/windows_common.c b/libusb/os/windows_common.c
index f91075a..8dc0e0a 100644
--- a/libusb/os/windows_common.c
+++ b/libusb/os/windows_common.c
@@ -297,7 +297,7 @@
 	struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
 	OVERLAPPED *overlapped = &transfer_priv->overlapped;
 
-	usbi_dbg("transfer %p, length %lu", USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer), size);
+	usbi_dbg("transfer %p, length %lu", USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer), ULONG_CAST(size));
 
 	overlapped->Internal = (ULONG_PTR)STATUS_SUCCESS;
 	overlapped->InternalHigh = (ULONG_PTR)size;
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 8a2be53..4e73d5c 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11570
+#define LIBUSB_NANO 11571
diff --git a/tests/libusb_testlib.h b/tests/libusb_testlib.h
index 6c987d3..b3dbaae 100644
--- a/tests/libusb_testlib.h
+++ b/tests/libusb_testlib.h
@@ -20,18 +20,6 @@
 #ifndef LIBUSB_TESTLIB_H
 #define LIBUSB_TESTLIB_H
 
-#include <stdio.h>
-
-#if !defined(bool)
-#define bool int
-#endif
-#if !defined(true)
-#define true (1 == 1)
-#endif
-#if !defined(false)
-#define false (!true)
-#endif
-
 /** Values returned from a test function to indicate test result */
 typedef enum {
 	/** Indicates that the test ran successfully. */
@@ -41,53 +29,33 @@
 	/** Indicates that an unexpected error occurred. */
 	TEST_STATUS_ERROR,
 	/** Indicates that the test can't be run. For example this may be
-	* due to no suitable device being connected to perform the tests.*/
+	 * due to no suitable device being connected to perform the tests. */
 	TEST_STATUS_SKIP
 } libusb_testlib_result;
 
 /**
- * Context for test library functions
- */
-typedef struct {
-	char ** test_names;
-	int test_count;
-	bool list_tests;
-	bool verbose;
-	int old_stdout;
-	int old_stderr;
-	FILE* output_file;
-	int null_fd;
-} libusb_testlib_ctx;
-
-/**
  * Logs some test information or state
  */
-void libusb_testlib_logf(libusb_testlib_ctx * ctx, 
-                          const char* fmt, ...);
-
-/**
- * Function pointer for a libusb test function.
- *
- * Should return TEST_STATUS_SUCCESS on success or another TEST_STATUS value.
- */
-typedef libusb_testlib_result
-(*libusb_testlib_test_function)(libusb_testlib_ctx * ctx);
+void libusb_testlib_logf(const char *fmt, ...);
 
 /**
  * Structure holding a test description.
  */
 typedef struct {
 	/** Human readable name of the test. */
-	const char * name;
-	/** The test library will call this function to run the test. */
-	libusb_testlib_test_function function;
+	const char *name;
+	/** The test library will call this function to run the test.
+	 *
+	 * Should return TEST_STATUS_SUCCESS on success or another TEST_STATUS value.
+	 */
+	libusb_testlib_result (*function)(void);
 } libusb_testlib_test;
 
 /**
  * Value to use at the end of a test array to indicate the last
  * element.
  */
-#define LIBUSB_NULL_TEST {NULL, NULL}
+#define LIBUSB_NULL_TEST { NULL, NULL }
 
 /**
  * Runs the tests provided.
@@ -100,8 +68,7 @@
  * \param tests A NULL_TEST terminated array of tests
  * \return 0 on success, non-zero on failure
  */
-int libusb_testlib_run_tests(int argc,
-                              char ** argv,
-                              const libusb_testlib_test * tests);
+int libusb_testlib_run_tests(int argc, char *argv[],
+	const libusb_testlib_test *tests);
 
 #endif //LIBUSB_TESTLIB_H
diff --git a/tests/stress.c b/tests/stress.c
index 1602ee9..5c8c315 100644
--- a/tests/stress.c
+++ b/tests/stress.c
@@ -17,111 +17,114 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include <stdio.h>
 #include <string.h>
-#include <memory.h>
 
 #include "libusb.h"
 #include "libusb_testlib.h"
 
 /** Test that creates and destroys a single concurrent context
  * 10000 times. */
-static libusb_testlib_result test_init_and_exit(libusb_testlib_ctx * tctx)
+static libusb_testlib_result test_init_and_exit(void)
 {
-	libusb_context * ctx = NULL;
-	int i;
-	for (i = 0; i < 10000; ++i) {
-		int r = libusb_init(&ctx);
+	for (int i = 0; i < 10000; ++i) {
+		libusb_context *ctx = NULL;
+		int r;
+
+		r = libusb_init(&ctx);
 		if (r != LIBUSB_SUCCESS) {
-			libusb_testlib_logf(tctx,
+			libusb_testlib_logf(
 				"Failed to init libusb on iteration %d: %d",
 				i, r);
 			return TEST_STATUS_FAILURE;
 		}
 		libusb_exit(ctx);
-		ctx = NULL;
 	}
 
 	return TEST_STATUS_SUCCESS;
 }
 
 /** Tests that devices can be listed 1000 times. */
-static libusb_testlib_result test_get_device_list(libusb_testlib_ctx * tctx)
+static libusb_testlib_result test_get_device_list(void)
 {
-	libusb_context * ctx = NULL;
-	int r, i;
+	libusb_context *ctx;
+	int r;
+
 	r = libusb_init(&ctx);
 	if (r != LIBUSB_SUCCESS) {
-		libusb_testlib_logf(tctx, "Failed to init libusb: %d", r);
+		libusb_testlib_logf("Failed to init libusb: %d", r);
 		return TEST_STATUS_FAILURE;
 	}
-	for (i = 0; i < 1000; ++i) {
-		libusb_device ** device_list;
+
+	for (int i = 0; i < 1000; ++i) {
+		libusb_device **device_list = NULL;
 		ssize_t list_size = libusb_get_device_list(ctx, &device_list);
-		if (list_size < 0 || device_list == NULL) {
-			libusb_testlib_logf(tctx,
+		if (list_size < 0 || !device_list) {
+			libusb_testlib_logf(
 				"Failed to get device list on iteration %d: %ld (%p)",
 				i, (long)-list_size, device_list);
+			libusb_exit(ctx);
 			return TEST_STATUS_FAILURE;
 		}
 		libusb_free_device_list(device_list, 1);
 	}
+
 	libusb_exit(ctx);
 	return TEST_STATUS_SUCCESS;
 }
 
 /** Tests that 100 concurrent device lists can be open at a time. */
-static libusb_testlib_result test_many_device_lists(libusb_testlib_ctx * tctx)
+static libusb_testlib_result test_many_device_lists(void)
 {
 #define LIST_COUNT 100
-	libusb_context * ctx = NULL;
-	libusb_device ** device_lists[LIST_COUNT];
-	int r, i;
-	memset(device_lists, 0, sizeof(device_lists));
+	libusb_testlib_result result = TEST_STATUS_SUCCESS;
+	libusb_context *ctx = NULL;
+	libusb_device **device_lists[LIST_COUNT];
+	int r;
 
 	r = libusb_init(&ctx);
 	if (r != LIBUSB_SUCCESS) {
-		libusb_testlib_logf(tctx, "Failed to init libusb: %d", r);
+		libusb_testlib_logf("Failed to init libusb: %d", r);
 		return TEST_STATUS_FAILURE;
 	}
 
+	memset(device_lists, 0, sizeof(device_lists));
+
 	/* Create the 100 device lists. */
-	for (i = 0; i < LIST_COUNT; ++i) {
-		ssize_t list_size = libusb_get_device_list(ctx, &(device_lists[i]));
-		if (list_size < 0 || device_lists[i] == NULL) {
-			libusb_testlib_logf(tctx,
-				"Failed to get device list on iteration %d: %d (%p)",
-				i, -list_size, device_lists[i]);
-			return TEST_STATUS_FAILURE;
+	for (int i = 0; i < LIST_COUNT; ++i) {
+		ssize_t list_size = libusb_get_device_list(ctx, &device_lists[i]);
+		if (list_size < 0 || !device_lists[i]) {
+			libusb_testlib_logf(
+				"Failed to get device list on iteration %d: %ld (%p)",
+				i, (long)-list_size, device_lists[i]);
+			result = TEST_STATUS_FAILURE;
+			break;
 		}
 	}
 
 	/* Destroy the 100 device lists. */
-	for (i = 0; i < LIST_COUNT; ++i) {
-		if (device_lists[i]) {
+	for (int i = 0; i < LIST_COUNT; ++i) {
+		if (device_lists[i])
 			libusb_free_device_list(device_lists[i], 1);
-			device_lists[i] = NULL;
-		}
 	}
 
 	libusb_exit(ctx);
-	return TEST_STATUS_SUCCESS;
+	return result;
 #undef LIST_COUNT
 }
 
 /** Tests that the default context (used for various things including
  * logging) works correctly when the first context created in a
  * process is destroyed. */
-static libusb_testlib_result test_default_context_change(libusb_testlib_ctx * tctx)
+static libusb_testlib_result test_default_context_change(void)
 {
-	libusb_context * ctx = NULL;
-	int r, i;
+	for (int i = 0; i < 100; ++i) {
+		libusb_context *ctx = NULL;
+		int r;
 
-	for (i = 0; i < 100; ++i) {
 		/* First create a new context */
 		r = libusb_init(&ctx);
 		if (r != LIBUSB_SUCCESS) {
-			libusb_testlib_logf(tctx, "Failed to init libusb: %d", r);
+			libusb_testlib_logf("Failed to init libusb: %d", r);
 			return TEST_STATUS_FAILURE;
 		}
 
@@ -132,7 +135,8 @@
 		/* Now create a reference to the default context */
 		r = libusb_init(NULL);
 		if (r != LIBUSB_SUCCESS) {
-			libusb_testlib_logf(tctx, "Failed to init libusb: %d", r);
+			libusb_testlib_logf("Failed to init libusb: %d", r);
+			libusb_exit(ctx);
 			return TEST_STATUS_FAILURE;
 		}
 
@@ -147,14 +151,14 @@
 
 /* Fill in the list of tests. */
 static const libusb_testlib_test tests[] = {
-	{"init_and_exit", &test_init_and_exit},
-	{"get_device_list", &test_get_device_list},
-	{"many_device_lists", &test_many_device_lists},
-	{"default_context_change", &test_default_context_change},
+	{ "init_and_exit", &test_init_and_exit },
+	{ "get_device_list", &test_get_device_list },
+	{ "many_device_lists", &test_many_device_lists },
+	{ "default_context_change", &test_default_context_change },
 	LIBUSB_NULL_TEST
 };
 
-int main (int argc, char ** argv)
+int main(int argc, char *argv[])
 {
 	return libusb_testlib_run_tests(argc, argv, tests);
 }
diff --git a/tests/testlib.c b/tests/testlib.c
index 95c9c0a..fb4fee6 100644
--- a/tests/testlib.c
+++ b/tests/testlib.c
@@ -19,35 +19,22 @@
 
 #include "libusb_testlib.h"
 
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
 
 #if defined(_WIN32)
-#include <io.h>
-#define dup _dup
-#define dup2 _dup2
-#define open _open
-#define close _close
-#define fdopen _fdopen
 #define NULL_PATH "nul"
-#define STDOUT_FILENO 1
-#define STDERR_FILENO 2
 #else
-#include <unistd.h>
 #define NULL_PATH "/dev/null"
 #endif
-#define INVALID_FD -1
-#define IGNORE_RETVAL(expr) do { (void)(expr); } while(0)
 
 /**
  * Converts a test result code into a human readable string.
  */
-static const char* test_result_to_str(libusb_testlib_result result)
+static const char *test_result_to_str(libusb_testlib_result result)
 {
 	switch (result) {
 	case TEST_STATUS_SUCCESS:
@@ -63,96 +50,27 @@
 	}
 }
 
-static void print_usage(int argc, char ** argv)
+static void print_usage(const char *progname)
 {
-	printf("Usage: %s [-l] [-v] [<test_name> ...]\n",
-		argc > 0 ? argv[0] : "test_*");
+	printf("Usage: %s [-l] [-v] [<test_name> ...]\n", progname);
 	printf("   -l   List available tests\n");
-	printf("   -v   Don't redirect STDERR/STDOUT during tests\n");
+	printf("   -v   Don't redirect STDERR before running tests\n");
+	printf("   -h   Display this help and exit\n");
 }
 
-static void cleanup_test_output(libusb_testlib_ctx * ctx)
-{
-	if (!ctx->verbose) {
-		if (ctx->old_stdout != INVALID_FD) {
-			IGNORE_RETVAL(dup2(ctx->old_stdout, STDOUT_FILENO));
-			ctx->old_stdout = INVALID_FD;
-		}
-		if (ctx->old_stderr != INVALID_FD) {
-			IGNORE_RETVAL(dup2(ctx->old_stderr, STDERR_FILENO));
-			ctx->old_stderr = INVALID_FD;
-		}
-		if (ctx->null_fd != INVALID_FD) {
-			close(ctx->null_fd);
-			ctx->null_fd = INVALID_FD;
-		}
-		if (ctx->output_file != stdout) {
-			fclose(ctx->output_file);
-			ctx->output_file = stdout;
-		}
-	}
-}
-
-/**
- * Setup test output handles
- * \return zero on success, non-zero on failure
- */
-static int setup_test_output(libusb_testlib_ctx * ctx)
-{
-	/* Stop output to stdout and stderr from being displayed if using non-verbose output */
-	if (!ctx->verbose) {
-		/* Keep a copy of STDOUT and STDERR */
-		ctx->old_stdout = dup(STDOUT_FILENO);
-		if (ctx->old_stdout < 0) {
-			ctx->old_stdout = INVALID_FD;
-			printf("Failed to duplicate stdout handle: %d\n", errno);
-			return 1;
-		}
-		ctx->old_stderr = dup(STDERR_FILENO);
-		if (ctx->old_stderr < 0) {
-			ctx->old_stderr = INVALID_FD;
-			cleanup_test_output(ctx);
-			printf("Failed to duplicate stderr handle: %d\n", errno);
-			return 1;
-		}
-		/* Redirect STDOUT_FILENO and STDERR_FILENO to /dev/null or "nul"*/
-		ctx->null_fd = open(NULL_PATH, O_WRONLY);
-		if (ctx->null_fd < 0) {
-			ctx->null_fd = INVALID_FD;
-			cleanup_test_output(ctx);
-			printf("Failed to open null handle: %d\n", errno);
-			return 1;
-		}
-		if ((dup2(ctx->null_fd, STDOUT_FILENO) < 0) ||
-			(dup2(ctx->null_fd, STDERR_FILENO) < 0)) {
-				cleanup_test_output(ctx);
-				return 1;
-		}
-		ctx->output_file = fdopen(ctx->old_stdout, "w");
-		if (!ctx->output_file) {
-			ctx->output_file = stdout;
-			cleanup_test_output(ctx);
-			printf("Failed to open FILE for output handle: %d\n", errno);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-void libusb_testlib_logf(libusb_testlib_ctx * ctx,
-	const char* fmt, ...)
+void libusb_testlib_logf(const char *fmt, ...)
 {
 	va_list va;
+
 	va_start(va, fmt);
-	vfprintf(ctx->output_file, fmt, va);
+	vfprintf(stdout, fmt, va);
 	va_end(va);
-	fprintf(ctx->output_file, "\n");
-	fflush(ctx->output_file);
+	fputc('\n', stdout);
+	fflush(stdout);
 }
 
-int libusb_testlib_run_tests(int argc,
-	char ** argv,
-	const libusb_testlib_test * tests)
+int libusb_testlib_run_tests(int argc, char *argv[],
+	const libusb_testlib_test *tests)
 {
 	int run_count = 0;
 	int idx = 0;
@@ -160,108 +78,105 @@
 	int fail_count = 0;
 	int error_count = 0;
 	int skip_count = 0;
-	int r, j;
-	size_t arglen;
-	libusb_testlib_result test_result;
-	libusb_testlib_ctx ctx;
 
 	/* Setup default mode of operation */
-	ctx.test_names = NULL;
-	ctx.test_count = 0;
-	ctx.list_tests = false;
-	ctx.verbose = false;
-	ctx.old_stdout = INVALID_FD;
-	ctx.old_stderr = INVALID_FD;
-	ctx.output_file = stdout;
-	ctx.null_fd = INVALID_FD;
+	char **test_names = NULL;
+	int test_count = 0;
+	bool list_tests = false;
+	bool verbose = false;
 
 	/* Parse command line options */
 	if (argc >= 2) {
-		for (j = 1; j < argc; j++) {
-			arglen = strlen(argv[j]);
-			if ( ((argv[j][0] == '-') || (argv[j][0] == '/')) &&
-				arglen >=2 ) {
-					switch (argv[j][1]) {
+		for (int j = 1; j < argc; j++) {
+			const char *argstr = argv[j];
+			size_t arglen = strlen(argstr);
+
+			if (argstr[0] == '-' || argstr[0] == '/') {
+				if (arglen == 2) {
+					switch (argstr[1]) {
 					case 'l':
-						ctx.list_tests = true;
-						break;
+						list_tests = true;
+						continue;
 					case 'v':
-						ctx.verbose = true;
-						break;
-					default:
-						printf("Unknown option: '%s'\n", argv[j]);
-						print_usage(argc, argv);
-						return 1;
+						verbose = true;
+						continue;
+					case 'h':
+						print_usage(argv[0]);
+						return 0;
 					}
+				}
+
+				fprintf(stderr, "Unknown option: '%s'\n", argstr);
+				print_usage(argv[0]);
+				return 1;
 			} else {
 				/* End of command line options, remaining must be list of tests to run */
-				ctx.test_names = argv + j;
-				ctx.test_count = argc - j;
+				test_names = argv + j;
+				test_count = argc - j;
 				break;
 			}
 		}
 	}
 
 	/* Validate command line options */
-	if (ctx.test_names && ctx.list_tests) {
-		printf("List of tests requested but test list provided\n");
-		print_usage(argc, argv);
+	if (test_names && list_tests) {
+		fprintf(stderr, "List of tests requested but test list provided\n");
+		print_usage(argv[0]);
 		return 1;
 	}
 
 	/* Setup test log output */
-	r = setup_test_output(&ctx);
-	if (r != 0)
-		return r;  
+	if (!verbose) {
+		if (!freopen(NULL_PATH, "w", stderr)) {
+			printf("Failed to open null handle: %d\n", errno);
+			return 1;
+		}
+	}
 
 	/* Act on any options not related to running tests */
-	if (ctx.list_tests) {
-		while (tests[idx].function != NULL) {
-			libusb_testlib_logf(&ctx, tests[idx].name);
-			++idx;
-		}
-		cleanup_test_output(&ctx);
+	if (list_tests) {
+		while (tests[idx].function)
+			libusb_testlib_logf("%s", tests[idx++].name);
 		return 0;
 	}
 
 	/* Run any requested tests */
-	while (tests[idx].function != NULL) {
-		const libusb_testlib_test * test = &tests[idx];
-		++idx;
-		if (ctx.test_count > 0) {
+	while (tests[idx].function) {
+		const libusb_testlib_test *test = &tests[idx++];
+		libusb_testlib_result test_result;
+
+		if (test_count > 0) {
 			/* Filtering tests to run, check if this is one of them */
 			int i;
-			for (i = 0; i < ctx.test_count; ++i) {
-				if (strcmp(ctx.test_names[i], test->name) == 0)
+
+			for (i = 0; i < test_count; i++) {
+				if (!strcmp(test_names[i], test->name))
 					/* Matches a requested test name */
 					break;
 			}
-			if (i >= ctx.test_count) {
+			if (i == test_count) {
 				/* Failed to find a test match, so do the next loop iteration */
 				continue;
 			}
 		}
-		libusb_testlib_logf(&ctx,
-			"Starting test run: %s...", test->name);
-		test_result = test->function(&ctx);
-		libusb_testlib_logf(&ctx,
-			"%s (%d)",
-			test_result_to_str(test_result), test_result);
+		libusb_testlib_logf("Starting test run: %s...", test->name);
+		test_result = test->function();
+		libusb_testlib_logf("%s (%d)", test_result_to_str(test_result), test_result);
 		switch (test_result) {
 		case TEST_STATUS_SUCCESS: pass_count++; break;
 		case TEST_STATUS_FAILURE: fail_count++; break;
 		case TEST_STATUS_ERROR: error_count++; break;
 		case TEST_STATUS_SKIP: skip_count++; break;
 		}
-		++run_count;
+		run_count++;
 	}
-	libusb_testlib_logf(&ctx, "---");
-	libusb_testlib_logf(&ctx, "Ran %d tests", run_count);
-	libusb_testlib_logf(&ctx, "Passed %d tests", pass_count);
-	libusb_testlib_logf(&ctx, "Failed %d tests", fail_count);
-	libusb_testlib_logf(&ctx, "Error in %d tests", error_count);
-	libusb_testlib_logf(&ctx, "Skipped %d tests", skip_count);
 
-	cleanup_test_output(&ctx);
+	libusb_testlib_logf("---");
+	libusb_testlib_logf("Ran %d tests", run_count);
+	libusb_testlib_logf("Passed %d tests", pass_count);
+	libusb_testlib_logf("Failed %d tests", fail_count);
+	libusb_testlib_logf("Error in %d tests", error_count);
+	libusb_testlib_logf("Skipped %d tests", skip_count);
+
 	return pass_count != run_count;
 }