2 * libusb test library helper functions
3 * Copyright © 2012 Toby Gray <toby.gray@realvnc.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "libusb_testlib.h"
26 #if !defined(_WIN32_WCE)
27 #include <sys/types.h>
32 #if defined(_WIN32_WCE)
33 // No support for selective redirection of STDOUT on WinCE.
34 #define DISABLE_STDOUT_REDIRECTION
35 #define STDOUT_FILENO 1
42 #define fdopen _fdopen
43 #define NULL_PATH "nul"
44 #define STDOUT_FILENO 1
45 #define STDERR_FILENO 2
48 #define NULL_PATH "/dev/null"
51 #define IGNORE_RETVAL(expr) do { (void)(expr); } while(0)
54 * Converts a test result code into a human readable string.
56 static const char* test_result_to_str(libusb_testlib_result result)
59 case TEST_STATUS_SUCCESS:
61 case TEST_STATUS_FAILURE:
63 case TEST_STATUS_ERROR:
65 case TEST_STATUS_SKIP:
72 static void print_usage(int argc, char ** argv)
74 printf("Usage: %s [-l] [-v] [<test_name> ...]\n",
75 argc > 0 ? argv[0] : "test_*");
76 printf(" -l List available tests\n");
77 printf(" -v Don't redirect STDERR/STDOUT during tests\n");
80 static void cleanup_test_output(libusb_testlib_ctx * ctx)
82 #ifndef DISABLE_STDOUT_REDIRECTION
84 if (ctx->old_stdout != INVALID_FD) {
85 IGNORE_RETVAL(dup2(ctx->old_stdout, STDOUT_FILENO));
86 ctx->old_stdout = INVALID_FD;
88 if (ctx->old_stderr != INVALID_FD) {
89 IGNORE_RETVAL(dup2(ctx->old_stderr, STDERR_FILENO));
90 ctx->old_stderr = INVALID_FD;
92 if (ctx->null_fd != INVALID_FD) {
94 ctx->null_fd = INVALID_FD;
96 if (ctx->output_file != stdout) {
97 fclose(ctx->output_file);
98 ctx->output_file = stdout;
105 * Setup test output handles
106 * \return zero on success, non-zero on failure
108 static int setup_test_output(libusb_testlib_ctx * ctx)
110 #ifndef DISABLE_STDOUT_REDIRECTION
111 /* Stop output to stdout and stderr from being displayed if using non-verbose output */
113 /* Keep a copy of STDOUT and STDERR */
114 ctx->old_stdout = dup(STDOUT_FILENO);
115 if (ctx->old_stdout < 0) {
116 ctx->old_stdout = INVALID_FD;
117 printf("Failed to duplicate stdout handle: %d\n", errno);
120 ctx->old_stderr = dup(STDERR_FILENO);
121 if (ctx->old_stderr < 0) {
122 ctx->old_stderr = INVALID_FD;
123 cleanup_test_output(ctx);
124 printf("Failed to duplicate stderr handle: %d\n", errno);
127 /* Redirect STDOUT_FILENO and STDERR_FILENO to /dev/null or "nul"*/
128 ctx->null_fd = open(NULL_PATH, O_WRONLY);
129 if (ctx->null_fd < 0) {
130 ctx->null_fd = INVALID_FD;
131 cleanup_test_output(ctx);
132 printf("Failed to open null handle: %d\n", errno);
135 if ((dup2(ctx->null_fd, STDOUT_FILENO) < 0) ||
136 (dup2(ctx->null_fd, STDERR_FILENO) < 0)) {
137 cleanup_test_output(ctx);
140 ctx->output_file = fdopen(ctx->old_stdout, "w");
141 if (!ctx->output_file) {
142 ctx->output_file = stdout;
143 cleanup_test_output(ctx);
144 printf("Failed to open FILE for output handle: %d\n", errno);
152 void libusb_testlib_logf(libusb_testlib_ctx * ctx,
153 const char* fmt, ...)
157 vfprintf(ctx->output_file, fmt, va);
159 fprintf(ctx->output_file, "\n");
160 fflush(ctx->output_file);
163 int libusb_testlib_run_tests(int argc,
165 const libusb_testlib_test * tests)
175 libusb_testlib_result test_result;
176 libusb_testlib_ctx ctx;
178 /* Setup default mode of operation */
179 ctx.test_names = NULL;
181 ctx.list_tests = false;
183 ctx.old_stdout = INVALID_FD;
184 ctx.old_stderr = INVALID_FD;
185 ctx.output_file = stdout;
186 ctx.null_fd = INVALID_FD;
188 /* Parse command line options */
190 for (j = 1; j < argc; j++) {
191 arglen = strlen(argv[j]);
192 if ( ((argv[j][0] == '-') || (argv[j][0] == '/')) &&
194 switch (argv[j][1]) {
196 ctx.list_tests = true;
202 printf("Unknown option: '%s'\n", argv[j]);
203 print_usage(argc, argv);
207 /* End of command line options, remaining must be list of tests to run */
208 ctx.test_names = argv + j;
209 ctx.test_count = argc - j;
215 /* Validate command line options */
216 if (ctx.test_names && ctx.list_tests) {
217 printf("List of tests requested but test list provided\n");
218 print_usage(argc, argv);
222 /* Setup test log output */
223 r = setup_test_output(&ctx);
227 /* Act on any options not related to running tests */
228 if (ctx.list_tests) {
229 while (tests[idx].function != NULL) {
230 libusb_testlib_logf(&ctx, tests[idx].name);
233 cleanup_test_output(&ctx);
237 /* Run any requested tests */
238 while (tests[idx].function != NULL) {
239 const libusb_testlib_test * test = &tests[idx];
241 if (ctx.test_count > 0) {
242 /* Filtering tests to run, check if this is one of them */
244 for (i = 0; i < ctx.test_count; ++i) {
245 if (strcmp(ctx.test_names[i], test->name) == 0)
246 /* Matches a requested test name */
249 if (i >= ctx.test_count) {
250 /* Failed to find a test match, so do the next loop iteration */
254 libusb_testlib_logf(&ctx,
255 "Starting test run: %s...", test->name);
256 test_result = test->function(&ctx);
257 libusb_testlib_logf(&ctx,
259 test_result_to_str(test_result), test_result);
260 switch (test_result) {
261 case TEST_STATUS_SUCCESS: pass_count++; break;
262 case TEST_STATUS_FAILURE: fail_count++; break;
263 case TEST_STATUS_ERROR: error_count++; break;
264 case TEST_STATUS_SKIP: skip_count++; break;
268 libusb_testlib_logf(&ctx, "---");
269 libusb_testlib_logf(&ctx, "Ran %d tests", run_count);
270 libusb_testlib_logf(&ctx, "Passed %d tests", pass_count);
271 libusb_testlib_logf(&ctx, "Failed %d tests", fail_count);
272 libusb_testlib_logf(&ctx, "Error in %d tests", error_count);
273 libusb_testlib_logf(&ctx, "Skipped %d tests", skip_count);
275 cleanup_test_output(&ctx);
276 return pass_count != run_count;