| OLD | NEW |
| (Empty) | |
| 1 /* |
| 2 * libusbx test library helper functions |
| 3 * Copyright © 2012 Toby Gray <toby.gray@realvnc.com> |
| 4 * |
| 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. |
| 9 * |
| 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. |
| 14 * |
| 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 |
| 18 */ |
| 19 |
| 20 #include "libusbx_testlib.h" |
| 21 |
| 22 #include <stdio.h> |
| 23 #include <stdarg.h> |
| 24 #include <string.h> |
| 25 #include <errno.h> |
| 26 #if !defined(_WIN32_WCE) |
| 27 #include <sys/types.h> |
| 28 #include <sys/stat.h> |
| 29 #include <fcntl.h> |
| 30 #endif |
| 31 |
| 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 |
| 36 #elif defined(_WIN32) |
| 37 #include <io.h> |
| 38 #define dup _dup |
| 39 #define dup2 _dup2 |
| 40 #define open _open |
| 41 #define close _close |
| 42 #define fdopen _fdopen |
| 43 #define NULL_PATH "nul" |
| 44 #define STDOUT_FILENO 1 |
| 45 #define STDERR_FILENO 2 |
| 46 #else |
| 47 #include <unistd.h> |
| 48 #define NULL_PATH "/dev/null" |
| 49 #endif |
| 50 #define INVALID_FD -1 |
| 51 #define IGNORE_RETVAL(expr) do { (void)(expr); } while(0) |
| 52 |
| 53 /** |
| 54 * Converts a test result code into a human readable string. |
| 55 */ |
| 56 static const char* test_result_to_str(libusbx_testlib_result result) |
| 57 { |
| 58 switch (result) { |
| 59 case TEST_STATUS_SUCCESS: |
| 60 return "Success"; |
| 61 case TEST_STATUS_FAILURE: |
| 62 return "Failure"; |
| 63 case TEST_STATUS_ERROR: |
| 64 return "Error"; |
| 65 case TEST_STATUS_SKIP: |
| 66 return "Skip"; |
| 67 default: |
| 68 return "Unknown"; |
| 69 } |
| 70 } |
| 71 |
| 72 static void print_usage(int argc, char ** argv) |
| 73 { |
| 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"); |
| 78 } |
| 79 |
| 80 static void cleanup_test_output(libusbx_testlib_ctx * ctx) |
| 81 { |
| 82 #ifndef DISABLE_STDOUT_REDIRECTION |
| 83 if (!ctx->verbose) { |
| 84 if (ctx->old_stdout != INVALID_FD) { |
| 85 IGNORE_RETVAL(dup2(ctx->old_stdout, STDOUT_FILENO)); |
| 86 ctx->old_stdout = INVALID_FD; |
| 87 } |
| 88 if (ctx->old_stderr != INVALID_FD) { |
| 89 IGNORE_RETVAL(dup2(ctx->old_stderr, STDERR_FILENO)); |
| 90 ctx->old_stderr = INVALID_FD; |
| 91 } |
| 92 if (ctx->null_fd != INVALID_FD) { |
| 93 close(ctx->null_fd); |
| 94 ctx->null_fd = INVALID_FD; |
| 95 } |
| 96 if (ctx->output_file != stdout) { |
| 97 fclose(ctx->output_file); |
| 98 ctx->output_file = stdout; |
| 99 } |
| 100 } |
| 101 #endif |
| 102 } |
| 103 |
| 104 /** |
| 105 * Setup test output handles |
| 106 * \return zero on success, non-zero on failure |
| 107 */ |
| 108 static int setup_test_output(libusbx_testlib_ctx * ctx) |
| 109 { |
| 110 #ifndef DISABLE_STDOUT_REDIRECTION |
| 111 /* Stop output to stdout and stderr from being displayed if using non-ve
rbose output */ |
| 112 if (!ctx->verbose) { |
| 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)
; |
| 118 return 1; |
| 119 } |
| 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)
; |
| 125 return 1; |
| 126 } |
| 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); |
| 133 return 1; |
| 134 } |
| 135 if ((dup2(ctx->null_fd, STDOUT_FILENO) < 0) || |
| 136 (dup2(ctx->null_fd, STDERR_FILENO) < 0)) { |
| 137 cleanup_test_output(ctx); |
| 138 return 1; |
| 139 } |
| 140 ctx->output_file = fdopen(ctx->old_stdout, "w"); |
| 141 if (!ctx->output_file) { |
| 142 cleanup_test_output(ctx); |
| 143 printf("Failed to open FILE for output handle: %d\n", er
rno); |
| 144 return 1; |
| 145 } |
| 146 } |
| 147 #endif |
| 148 return 0; |
| 149 } |
| 150 |
| 151 void libusbx_testlib_logf(libusbx_testlib_ctx * ctx, |
| 152 const char* fmt, ...) |
| 153 { |
| 154 va_list va; |
| 155 va_start(va, fmt); |
| 156 vfprintf(ctx->output_file, fmt, va); |
| 157 va_end(va); |
| 158 fprintf(ctx->output_file, "\n"); |
| 159 fflush(ctx->output_file); |
| 160 } |
| 161 |
| 162 int libusbx_testlib_run_tests(int argc, |
| 163 char ** argv, |
| 164 const libusbx_testlib_test * tests) |
| 165 { |
| 166 int run_count = 0; |
| 167 int idx = 0; |
| 168 int pass_count = 0; |
| 169 int fail_count = 0; |
| 170 int error_count = 0; |
| 171 int skip_count = 0; |
| 172 int r, j; |
| 173 size_t arglen; |
| 174 libusbx_testlib_result test_result; |
| 175 libusbx_testlib_ctx ctx; |
| 176 |
| 177 /* Setup default mode of operation */ |
| 178 ctx.test_names = NULL; |
| 179 ctx.test_count = 0; |
| 180 ctx.list_tests = false; |
| 181 ctx.verbose = false; |
| 182 ctx.old_stdout = INVALID_FD; |
| 183 ctx.old_stderr = INVALID_FD; |
| 184 ctx.output_file = stdout; |
| 185 ctx.null_fd = INVALID_FD; |
| 186 |
| 187 /* Parse command line options */ |
| 188 if (argc >= 2) { |
| 189 for (j = 1; j < argc; j++) { |
| 190 arglen = strlen(argv[j]); |
| 191 if ( ((argv[j][0] == '-') || (argv[j][0] == '/')) && |
| 192 arglen >=2 ) { |
| 193 switch (argv[j][1]) { |
| 194 case 'l': |
| 195 ctx.list_tests = true; |
| 196 break; |
| 197 case 'v': |
| 198 ctx.verbose = true; |
| 199 break; |
| 200 default: |
| 201 printf("Unknown option: '%s'\n",
argv[j]); |
| 202 print_usage(argc, argv); |
| 203 return 1; |
| 204 } |
| 205 } else { |
| 206 /* End of command line options, remaining must b
e list of tests to run */ |
| 207 ctx.test_names = argv + j; |
| 208 ctx.test_count = argc - j; |
| 209 break; |
| 210 } |
| 211 } |
| 212 } |
| 213 |
| 214 /* Validate command line options */ |
| 215 if (ctx.test_names && ctx.list_tests) { |
| 216 printf("List of tests requested but test list provided\n"); |
| 217 print_usage(argc, argv); |
| 218 return 1; |
| 219 } |
| 220 |
| 221 /* Setup test log output */ |
| 222 r = setup_test_output(&ctx); |
| 223 if (r != 0) |
| 224 return r; |
| 225 |
| 226 /* Act on any options not related to running tests */ |
| 227 if (ctx.list_tests) { |
| 228 while (tests[idx].function != NULL) { |
| 229 libusbx_testlib_logf(&ctx, tests[idx].name); |
| 230 ++idx; |
| 231 } |
| 232 cleanup_test_output(&ctx); |
| 233 return 0; |
| 234 } |
| 235 |
| 236 /* Run any requested tests */ |
| 237 while (tests[idx].function != NULL) { |
| 238 const libusbx_testlib_test * test = &tests[idx]; |
| 239 ++idx; |
| 240 if (ctx.test_count > 0) { |
| 241 /* Filtering tests to run, check if this is one of them
*/ |
| 242 int i; |
| 243 for (i = 0; i < ctx.test_count; ++i) { |
| 244 if (strcmp(ctx.test_names[i], test->name) == 0) |
| 245 /* Matches a requested test name */ |
| 246 break; |
| 247 } |
| 248 if (i >= ctx.test_count) { |
| 249 /* Failed to find a test match, so do the next l
oop iteration */ |
| 250 continue; |
| 251 } |
| 252 } |
| 253 libusbx_testlib_logf(&ctx, |
| 254 "Starting test run: %s...", test->name); |
| 255 test_result = test->function(&ctx); |
| 256 libusbx_testlib_logf(&ctx, |
| 257 "%s (%d)", |
| 258 test_result_to_str(test_result), test_result); |
| 259 switch (test_result) { |
| 260 case TEST_STATUS_SUCCESS: pass_count++; break; |
| 261 case TEST_STATUS_FAILURE: fail_count++; break; |
| 262 case TEST_STATUS_ERROR: error_count++; break; |
| 263 case TEST_STATUS_SKIP: skip_count++; break; |
| 264 } |
| 265 ++run_count; |
| 266 } |
| 267 libusbx_testlib_logf(&ctx, "---"); |
| 268 libusbx_testlib_logf(&ctx, "Ran %d tests", run_count); |
| 269 libusbx_testlib_logf(&ctx, "Passed %d tests", pass_count); |
| 270 libusbx_testlib_logf(&ctx, "Failed %d tests", fail_count); |
| 271 libusbx_testlib_logf(&ctx, "Error in %d tests", error_count); |
| 272 libusbx_testlib_logf(&ctx, "Skipped %d tests", skip_count); |
| 273 |
| 274 cleanup_test_output(&ctx); |
| 275 return pass_count != run_count; |
| 276 } |
| OLD | NEW |