aa38cf12787be78982ff7f518be14475c27b1221
[rtmpclient.git] / app / src / main / jni / libusb / tests / testlib.c
1 /*
2  * libusb 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 "libusb_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(libusb_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(libusb_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(libusb_testlib_ctx * ctx)
109 {
110 #ifndef DISABLE_STDOUT_REDIRECTION
111         /* Stop output to stdout and stderr from being displayed if using non-verbose 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                         ctx->output_file = stdout;
143                         cleanup_test_output(ctx);
144                         printf("Failed to open FILE for output handle: %d\n", errno);
145                         return 1;
146                 }
147         }
148 #endif
149         return 0;
150 }
151
152 void libusb_testlib_logf(libusb_testlib_ctx * ctx,
153         const char* fmt, ...)
154 {
155         va_list va;
156         va_start(va, fmt);
157         vfprintf(ctx->output_file, fmt, va);
158         va_end(va);
159         fprintf(ctx->output_file, "\n");
160         fflush(ctx->output_file);
161 }
162
163 int libusb_testlib_run_tests(int argc,
164         char ** argv,
165         const libusb_testlib_test * tests)
166 {
167         int run_count = 0;
168         int idx = 0;
169         int pass_count = 0;
170         int fail_count = 0;
171         int error_count = 0;
172         int skip_count = 0;
173         int r, j;
174         size_t arglen;
175         libusb_testlib_result test_result;
176         libusb_testlib_ctx ctx;
177
178         /* Setup default mode of operation */
179         ctx.test_names = NULL;
180         ctx.test_count = 0;
181         ctx.list_tests = false;
182         ctx.verbose = false;
183         ctx.old_stdout = INVALID_FD;
184         ctx.old_stderr = INVALID_FD;
185         ctx.output_file = stdout;
186         ctx.null_fd = INVALID_FD;
187
188         /* Parse command line options */
189         if (argc >= 2) {
190                 for (j = 1; j < argc; j++) {
191                         arglen = strlen(argv[j]);
192                         if ( ((argv[j][0] == '-') || (argv[j][0] == '/')) &&
193                                 arglen >=2 ) {
194                                         switch (argv[j][1]) {
195                                         case 'l':
196                                                 ctx.list_tests = true;
197                                                 break;
198                                         case 'v':
199                                                 ctx.verbose = true;
200                                                 break;
201                                         default:
202                                                 printf("Unknown option: '%s'\n", argv[j]);
203                                                 print_usage(argc, argv);
204                                                 return 1;
205                                         }
206                         } else {
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;
210                                 break;
211                         }
212                 }
213         }
214
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);
219                 return 1;
220         }
221
222         /* Setup test log output */
223         r = setup_test_output(&ctx);
224         if (r != 0)
225                 return r;  
226
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);
231                         ++idx;
232                 }
233                 cleanup_test_output(&ctx);
234                 return 0;
235         }
236
237         /* Run any requested tests */
238         while (tests[idx].function != NULL) {
239                 const libusb_testlib_test * test = &tests[idx];
240                 ++idx;
241                 if (ctx.test_count > 0) {
242                         /* Filtering tests to run, check if this is one of them */
243                         int i;
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 */
247                                         break;
248                         }
249                         if (i >= ctx.test_count) {
250                                 /* Failed to find a test match, so do the next loop iteration */
251                                 continue;
252                         }
253                 }
254                 libusb_testlib_logf(&ctx,
255                         "Starting test run: %s...", test->name);
256                 test_result = test->function(&ctx);
257                 libusb_testlib_logf(&ctx,
258                         "%s (%d)",
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;
265                 }
266                 ++run_count;
267         }
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);
274
275         cleanup_test_output(&ctx);
276         return pass_count != run_count;
277 }