2 * libusbx 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 "libusbx_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"
53 * Converts a test result code into a human readable string.
55 static const char* test_result_to_str(libusbx_testlib_result result)
58 case TEST_STATUS_SUCCESS:
60 case TEST_STATUS_FAILURE:
62 case TEST_STATUS_ERROR:
64 case TEST_STATUS_SKIP:
71 static void print_usage(int argc, char ** argv)
73 printf("Usage: %s [-l] [-v] [<test_name> ...]\n",
74 argc > 0 ? argv[0] : "test_*");
75 printf(" -l List available tests\n");
76 printf(" -v Don't redirect STDERR/STDOUT during tests\n");
79 static void cleanup_test_output(libusbx_testlib_ctx * ctx)
81 #ifndef DISABLE_STDOUT_REDIRECTION
83 if (ctx->old_stdout != INVALID_FD) {
84 dup2(ctx->old_stdout, STDOUT_FILENO);
85 ctx->old_stdout = INVALID_FD;
87 if (ctx->old_stderr != INVALID_FD) {
88 dup2(ctx->old_stderr, STDERR_FILENO);
89 ctx->old_stderr = INVALID_FD;
91 if (ctx->null_fd != INVALID_FD) {
93 ctx->null_fd = INVALID_FD;
95 if (ctx->output_file != stdout) {
96 fclose(ctx->output_file);
97 ctx->output_file = stdout;
104 * Setup test output handles
105 * \return zero on success, non-zero on failure
107 static int setup_test_output(libusbx_testlib_ctx * ctx)
109 #ifndef DISABLE_STDOUT_REDIRECTION
110 /* Stop output to stdout and stderr from being displayed if using non-verbose output */
112 /* Keep a copy of STDOUT and STDERR */
113 ctx->old_stdout = dup(STDOUT_FILENO);
114 if (ctx->old_stdout < 0) {
115 ctx->old_stdout = INVALID_FD;
116 printf("Failed to duplicate stdout handle: %d\n", errno);
119 ctx->old_stderr = dup(STDERR_FILENO);
120 if (ctx->old_stderr < 0) {
121 ctx->old_stderr = INVALID_FD;
122 cleanup_test_output(ctx);
123 printf("Failed to duplicate stderr handle: %d\n", errno);
126 /* Redirect STDOUT_FILENO and STDERR_FILENO to /dev/null or "nul"*/
127 ctx->null_fd = open(NULL_PATH, O_WRONLY);
128 if (ctx->null_fd < 0) {
129 ctx->null_fd = INVALID_FD;
130 cleanup_test_output(ctx);
131 printf("Failed to open null handle: %d\n", errno);
134 if ((dup2(ctx->null_fd, STDOUT_FILENO) < 0) ||
135 (dup2(ctx->null_fd, STDERR_FILENO) < 0)) {
136 cleanup_test_output(ctx);
139 ctx->output_file = fdopen(ctx->old_stdout, "w");
140 if (!ctx->output_file) {
141 cleanup_test_output(ctx);
142 printf("Failed to open FILE for output handle: %d\n", errno);
150 void libusbx_testlib_logf(libusbx_testlib_ctx * ctx,
151 const char* fmt, ...)
155 vfprintf(ctx->output_file, fmt, va);
157 fprintf(ctx->output_file, "\n");
158 fflush(ctx->output_file);
161 int libusbx_testlib_run_tests(int argc,
163 const libusbx_testlib_test * tests)
173 libusbx_testlib_result test_result;
174 libusbx_testlib_ctx ctx;
176 /* Setup default mode of operation */
177 ctx.test_names = NULL;
179 ctx.list_tests = false;
181 ctx.old_stdout = INVALID_FD;
182 ctx.old_stderr = INVALID_FD;
183 ctx.output_file = stdout;
184 ctx.null_fd = INVALID_FD;
186 /* Parse command line options */
188 for (j = 1; j < argc; j++) {
189 arglen = strlen(argv[j]);
190 if ( ((argv[j][0] == '-') || (argv[j][0] == '/')) &&
192 switch (argv[j][1]) {
194 ctx.list_tests = true;
200 printf("Unknown option: '%s'\n", argv[j]);
201 print_usage(argc, argv);
205 /* End of command line options, remaining must be list of tests to run */
206 ctx.test_names = argv + j;
207 ctx.test_count = argc - j;
213 /* Validate command line options */
214 if (ctx.test_names && ctx.list_tests) {
215 printf("List of tests requested but test list provided\n");
216 print_usage(argc, argv);
220 /* Setup test log output */
221 r = setup_test_output(&ctx);
225 /* Act on any options not related to running tests */
226 if (ctx.list_tests) {
227 while (tests[idx].function != NULL) {
228 libusbx_testlib_logf(&ctx, tests[idx].name);
231 cleanup_test_output(&ctx);
235 /* Run any requested tests */
236 while (tests[idx].function != NULL) {
237 const libusbx_testlib_test * test = &tests[idx];
239 if (ctx.test_count > 0) {
240 /* Filtering tests to run, check if this is one of them */
242 for (i = 0; i < ctx.test_count; ++i) {
243 if (strcmp(ctx.test_names[i], test->name) == 0)
244 /* Matches a requested test name */
247 if (i >= ctx.test_count) {
248 /* Failed to find a test match, so do the next loop iteration */
252 libusbx_testlib_logf(&ctx,
253 "Starting test run: %s...", test->name);
254 test_result = test->function(&ctx);
255 libusbx_testlib_logf(&ctx,
257 test_result_to_str(test_result), test_result);
258 switch (test_result) {
259 case TEST_STATUS_SUCCESS: pass_count++; break;
260 case TEST_STATUS_FAILURE: fail_count++; break;
261 case TEST_STATUS_ERROR: error_count++; break;
262 case TEST_STATUS_SKIP: skip_count++; break;
266 libusbx_testlib_logf(&ctx, "---");
267 libusbx_testlib_logf(&ctx, "Ran %d tests", run_count);
268 libusbx_testlib_logf(&ctx, "Passed %d tests", pass_count);
269 libusbx_testlib_logf(&ctx, "Failed %d tests", fail_count);
270 libusbx_testlib_logf(&ctx, "Error in %d tests", error_count);
271 libusbx_testlib_logf(&ctx, "Skipped %d tests", skip_count);
273 cleanup_test_output(&ctx);
274 return pass_count != run_count;