Tests: Fix broken OS-X and Linux builds
[platform/upstream/libusb.git] / tests / testlib.c
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
52 /**
53  * Converts a test result code into a human readable string.
54  */
55 static const char* test_result_to_str(libusbx_testlib_result result)
56 {
57         switch (result) {
58         case TEST_STATUS_SUCCESS:
59                 return "Success";
60         case TEST_STATUS_FAILURE:
61                 return "Failure";
62         case TEST_STATUS_ERROR:
63                 return "Error";
64         case TEST_STATUS_SKIP:
65                 return "Skip";
66         default:
67                 return "Unknown";
68         }
69 }
70
71 static void print_usage(int argc, char ** argv)
72 {
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");
77 }
78
79 static void cleanup_test_output(libusbx_testlib_ctx * ctx)
80 {
81 #ifndef DISABLE_STDOUT_REDIRECTION
82         if (!ctx->verbose) {
83                 if (ctx->old_stdout != INVALID_FD) {
84                         dup2(ctx->old_stdout, STDOUT_FILENO);
85                         ctx->old_stdout = INVALID_FD;
86                 }
87                 if (ctx->old_stderr != INVALID_FD) {
88                         dup2(ctx->old_stderr, STDERR_FILENO);
89                         ctx->old_stderr = INVALID_FD;
90                 }
91                 if (ctx->null_fd != INVALID_FD) {
92                         close(ctx->null_fd);
93                         ctx->null_fd = INVALID_FD;
94                 }
95                 if (ctx->output_file != stdout) {
96                         fclose(ctx->output_file);
97                         ctx->output_file = stdout;
98                 }
99         }
100 #endif
101 }
102
103 /**
104  * Setup test output handles
105  * \return zero on success, non-zero on failure
106  */
107 static int setup_test_output(libusbx_testlib_ctx * ctx)
108 {
109 #ifndef DISABLE_STDOUT_REDIRECTION
110         /* Stop output to stdout and stderr from being displayed if using non-verbose output */
111         if (!ctx->verbose) {
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);
117                         return 1;
118                 }
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);
124                         return 1;
125                 }
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);
132                         return 1;
133                 }
134                 if ((dup2(ctx->null_fd, STDOUT_FILENO) < 0) ||
135                         (dup2(ctx->null_fd, STDERR_FILENO) < 0)) {
136                                 cleanup_test_output(ctx);
137                                 return 1;
138                 }
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);
143                         return 1;
144                 }
145         }
146 #endif
147         return 0;
148 }
149
150 void libusbx_testlib_logf(libusbx_testlib_ctx * ctx,
151         const char* fmt, ...)
152 {
153         va_list va;
154         va_start(va, fmt);
155         vfprintf(ctx->output_file, fmt, va);
156         va_end(va);
157         fprintf(ctx->output_file, "\n");
158         fflush(ctx->output_file);
159 }
160
161 int libusbx_testlib_run_tests(int argc,
162         char ** argv,
163         const libusbx_testlib_test * tests)
164 {
165         int run_count = 0;
166         int idx = 0;
167         int pass_count = 0;
168         int fail_count = 0;
169         int error_count = 0;
170         int skip_count = 0;
171         int r, j;
172         size_t arglen;
173         libusbx_testlib_result test_result;
174         libusbx_testlib_ctx ctx;
175
176         /* Setup default mode of operation */
177         ctx.test_names = NULL;
178         ctx.test_count = 0;
179         ctx.list_tests = false;
180         ctx.verbose = false;
181         ctx.old_stdout = INVALID_FD;
182         ctx.old_stderr = INVALID_FD;
183         ctx.output_file = stdout;
184         ctx.null_fd = INVALID_FD;
185
186         /* Parse command line options */
187         if (argc >= 2) {
188                 for (j = 1; j < argc; j++) {
189                         arglen = strlen(argv[j]);
190                         if ( ((argv[j][0] == '-') || (argv[j][0] == '/')) &&
191                                 arglen >=2 ) {
192                                         switch (argv[j][1]) {
193                                         case 'l':
194                                                 ctx.list_tests = true;
195                                                 break;
196                                         case 'v':
197                                                 ctx.verbose = true;
198                                                 break;
199                                         default:
200                                                 printf("Unknown option: '%s'\n", argv[j]);
201                                                 print_usage(argc, argv);
202                                                 return 1;
203                                         }
204                         } else {
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;
208                                 break;
209                         }
210                 }
211         }
212
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);
217                 return 1;
218         }
219
220         /* Setup test log output */
221         r = setup_test_output(&ctx);
222         if (r != 0)
223                 return r;  
224
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);
229                         ++idx;
230                 }
231                 cleanup_test_output(&ctx);
232                 return 0;
233         }
234
235         /* Run any requested tests */
236         while (tests[idx].function != NULL) {
237                 const libusbx_testlib_test * test = &tests[idx];
238                 ++idx;
239                 if (ctx.test_count > 0) {
240                         /* Filtering tests to run, check if this is one of them */
241                         int i;
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 */
245                                         break;
246                         }
247                         if (i >= ctx.test_count) {
248                                 /* Failed to find a test match, so do the next loop iteration */
249                                 continue;
250                         }
251                 }
252                 libusbx_testlib_logf(&ctx,
253                         "Starting test run: %s...", test->name);
254                 test_result = test->function(&ctx);
255                 libusbx_testlib_logf(&ctx,
256                         "%s (%d)",
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;
263                 }
264                 ++run_count;
265         }
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);
272
273         cleanup_test_output(&ctx);
274         return pass_count != run_count;
275 }