1*663afb9bSAndroid Build Coastguard Worker /* tinytest.c -- Copyright 2009-2012 Nick Mathewson
2*663afb9bSAndroid Build Coastguard Worker *
3*663afb9bSAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
4*663afb9bSAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
5*663afb9bSAndroid Build Coastguard Worker * are met:
6*663afb9bSAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
7*663afb9bSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
8*663afb9bSAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
9*663afb9bSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
10*663afb9bSAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
11*663afb9bSAndroid Build Coastguard Worker * 3. The name of the author may not be used to endorse or promote products
12*663afb9bSAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
13*663afb9bSAndroid Build Coastguard Worker *
14*663afb9bSAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*663afb9bSAndroid Build Coastguard Worker * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*663afb9bSAndroid Build Coastguard Worker * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*663afb9bSAndroid Build Coastguard Worker * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*663afb9bSAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*663afb9bSAndroid Build Coastguard Worker * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*663afb9bSAndroid Build Coastguard Worker * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*663afb9bSAndroid Build Coastguard Worker * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*663afb9bSAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*663afb9bSAndroid Build Coastguard Worker * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*663afb9bSAndroid Build Coastguard Worker */
25*663afb9bSAndroid Build Coastguard Worker #ifdef TINYTEST_LOCAL
26*663afb9bSAndroid Build Coastguard Worker #include "tinytest_local.h"
27*663afb9bSAndroid Build Coastguard Worker #endif
28*663afb9bSAndroid Build Coastguard Worker
29*663afb9bSAndroid Build Coastguard Worker #include <stdio.h>
30*663afb9bSAndroid Build Coastguard Worker #include <stdlib.h>
31*663afb9bSAndroid Build Coastguard Worker #include <string.h>
32*663afb9bSAndroid Build Coastguard Worker #include <assert.h>
33*663afb9bSAndroid Build Coastguard Worker
34*663afb9bSAndroid Build Coastguard Worker #ifndef NO_FORKING
35*663afb9bSAndroid Build Coastguard Worker
36*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
37*663afb9bSAndroid Build Coastguard Worker #include <windows.h>
38*663afb9bSAndroid Build Coastguard Worker #else
39*663afb9bSAndroid Build Coastguard Worker #include <sys/types.h>
40*663afb9bSAndroid Build Coastguard Worker #include <sys/wait.h>
41*663afb9bSAndroid Build Coastguard Worker #include <unistd.h>
42*663afb9bSAndroid Build Coastguard Worker #endif
43*663afb9bSAndroid Build Coastguard Worker
44*663afb9bSAndroid Build Coastguard Worker #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
45*663afb9bSAndroid Build Coastguard Worker #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
46*663afb9bSAndroid Build Coastguard Worker __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
47*663afb9bSAndroid Build Coastguard Worker /* Workaround for a stupid bug in OSX 10.6 */
48*663afb9bSAndroid Build Coastguard Worker #define FORK_BREAKS_GCOV
49*663afb9bSAndroid Build Coastguard Worker #include <vproc.h>
50*663afb9bSAndroid Build Coastguard Worker #endif
51*663afb9bSAndroid Build Coastguard Worker #endif
52*663afb9bSAndroid Build Coastguard Worker
53*663afb9bSAndroid Build Coastguard Worker #endif /* !NO_FORKING */
54*663afb9bSAndroid Build Coastguard Worker
55*663afb9bSAndroid Build Coastguard Worker #ifndef __GNUC__
56*663afb9bSAndroid Build Coastguard Worker #define __attribute__(x)
57*663afb9bSAndroid Build Coastguard Worker #endif
58*663afb9bSAndroid Build Coastguard Worker
59*663afb9bSAndroid Build Coastguard Worker #include "tinytest.h"
60*663afb9bSAndroid Build Coastguard Worker #include "tinytest_macros.h"
61*663afb9bSAndroid Build Coastguard Worker
62*663afb9bSAndroid Build Coastguard Worker #define LONGEST_TEST_NAME 16384
63*663afb9bSAndroid Build Coastguard Worker #define DEFAULT_TESTCASE_TIMEOUT 30U
64*663afb9bSAndroid Build Coastguard Worker #define MAGIC_EXITCODE 42
65*663afb9bSAndroid Build Coastguard Worker
66*663afb9bSAndroid Build Coastguard Worker static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
67*663afb9bSAndroid Build Coastguard Worker static int n_ok = 0; /**< Number of tests that have passed */
68*663afb9bSAndroid Build Coastguard Worker static int n_bad = 0; /**< Number of tests that have failed. */
69*663afb9bSAndroid Build Coastguard Worker static int n_skipped = 0; /**< Number of tests that have been skipped. */
70*663afb9bSAndroid Build Coastguard Worker
71*663afb9bSAndroid Build Coastguard Worker static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
72*663afb9bSAndroid Build Coastguard Worker static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
73*663afb9bSAndroid Build Coastguard Worker static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
74*663afb9bSAndroid Build Coastguard Worker static unsigned int opt_timeout = DEFAULT_TESTCASE_TIMEOUT; /**< Timeout for every test (using alarm()) */
75*663afb9bSAndroid Build Coastguard Worker const char *verbosity_flag = "";
76*663afb9bSAndroid Build Coastguard Worker
77*663afb9bSAndroid Build Coastguard Worker const struct testlist_alias_t *cfg_aliases=NULL;
78*663afb9bSAndroid Build Coastguard Worker
79*663afb9bSAndroid Build Coastguard Worker enum outcome { SKIP=2, OK=1, FAIL=0 };
80*663afb9bSAndroid Build Coastguard Worker static enum outcome cur_test_outcome = 0;
81*663afb9bSAndroid Build Coastguard Worker const char *cur_test_prefix = NULL; /**< prefix of the current test group */
82*663afb9bSAndroid Build Coastguard Worker /** Name of the current test, if we haven't logged is yet. Used for --quiet */
83*663afb9bSAndroid Build Coastguard Worker const char *cur_test_name = NULL;
84*663afb9bSAndroid Build Coastguard Worker
85*663afb9bSAndroid Build Coastguard Worker static void usage(struct testgroup_t *groups, int list_groups)
86*663afb9bSAndroid Build Coastguard Worker __attribute__((noreturn));
87*663afb9bSAndroid Build Coastguard Worker static int process_test_option(struct testgroup_t *groups, const char *test);
88*663afb9bSAndroid Build Coastguard Worker
89*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
90*663afb9bSAndroid Build Coastguard Worker /* Copy of argv[0] for win32. */
91*663afb9bSAndroid Build Coastguard Worker static char commandname[MAX_PATH+1];
92*663afb9bSAndroid Build Coastguard Worker
93*663afb9bSAndroid Build Coastguard Worker struct timeout_thread_args {
94*663afb9bSAndroid Build Coastguard Worker const testcase_fn *fn;
95*663afb9bSAndroid Build Coastguard Worker void *env;
96*663afb9bSAndroid Build Coastguard Worker };
97*663afb9bSAndroid Build Coastguard Worker
98*663afb9bSAndroid Build Coastguard Worker static DWORD WINAPI
timeout_thread_proc_(LPVOID arg)99*663afb9bSAndroid Build Coastguard Worker timeout_thread_proc_(LPVOID arg)
100*663afb9bSAndroid Build Coastguard Worker {
101*663afb9bSAndroid Build Coastguard Worker struct timeout_thread_args *args = arg;
102*663afb9bSAndroid Build Coastguard Worker (*(args->fn))(args->env);
103*663afb9bSAndroid Build Coastguard Worker ExitThread(cur_test_outcome == FAIL ? 1 : 0);
104*663afb9bSAndroid Build Coastguard Worker }
105*663afb9bSAndroid Build Coastguard Worker
106*663afb9bSAndroid Build Coastguard Worker static enum outcome
testcase_run_in_thread_(const struct testcase_t * testcase,void * env)107*663afb9bSAndroid Build Coastguard Worker testcase_run_in_thread_(const struct testcase_t *testcase, void *env)
108*663afb9bSAndroid Build Coastguard Worker {
109*663afb9bSAndroid Build Coastguard Worker /* We will never run testcase in a new thread when the
110*663afb9bSAndroid Build Coastguard Worker timeout is set to zero */
111*663afb9bSAndroid Build Coastguard Worker assert(opt_timeout);
112*663afb9bSAndroid Build Coastguard Worker DWORD ret, tid;
113*663afb9bSAndroid Build Coastguard Worker HANDLE handle;
114*663afb9bSAndroid Build Coastguard Worker struct timeout_thread_args args = {
115*663afb9bSAndroid Build Coastguard Worker &(testcase->fn),
116*663afb9bSAndroid Build Coastguard Worker env
117*663afb9bSAndroid Build Coastguard Worker };
118*663afb9bSAndroid Build Coastguard Worker
119*663afb9bSAndroid Build Coastguard Worker handle =CreateThread(NULL, 0, timeout_thread_proc_,
120*663afb9bSAndroid Build Coastguard Worker (LPVOID)&args, 0, &tid);
121*663afb9bSAndroid Build Coastguard Worker ret = WaitForSingleObject(handle, opt_timeout * 1000U);
122*663afb9bSAndroid Build Coastguard Worker if (ret == WAIT_OBJECT_0) {
123*663afb9bSAndroid Build Coastguard Worker ret = 0;
124*663afb9bSAndroid Build Coastguard Worker if (!GetExitCodeThread(handle, &ret)) {
125*663afb9bSAndroid Build Coastguard Worker printf("GetExitCodeThread failed\n");
126*663afb9bSAndroid Build Coastguard Worker ret = 1;
127*663afb9bSAndroid Build Coastguard Worker }
128*663afb9bSAndroid Build Coastguard Worker } else if (ret == WAIT_TIMEOUT) {
129*663afb9bSAndroid Build Coastguard Worker printf("timeout\n");
130*663afb9bSAndroid Build Coastguard Worker } else {
131*663afb9bSAndroid Build Coastguard Worker printf("Wait failed\n");
132*663afb9bSAndroid Build Coastguard Worker }
133*663afb9bSAndroid Build Coastguard Worker CloseHandle(handle);
134*663afb9bSAndroid Build Coastguard Worker if (ret == 0)
135*663afb9bSAndroid Build Coastguard Worker return OK;
136*663afb9bSAndroid Build Coastguard Worker else if (ret == MAGIC_EXITCODE)
137*663afb9bSAndroid Build Coastguard Worker return SKIP;
138*663afb9bSAndroid Build Coastguard Worker else
139*663afb9bSAndroid Build Coastguard Worker return FAIL;
140*663afb9bSAndroid Build Coastguard Worker }
141*663afb9bSAndroid Build Coastguard Worker #else
testcase_set_timeout_(void)142*663afb9bSAndroid Build Coastguard Worker static unsigned int testcase_set_timeout_(void)
143*663afb9bSAndroid Build Coastguard Worker {
144*663afb9bSAndroid Build Coastguard Worker return alarm(opt_timeout);
145*663afb9bSAndroid Build Coastguard Worker }
146*663afb9bSAndroid Build Coastguard Worker
testcase_reset_timeout_(void)147*663afb9bSAndroid Build Coastguard Worker static unsigned int testcase_reset_timeout_(void)
148*663afb9bSAndroid Build Coastguard Worker {
149*663afb9bSAndroid Build Coastguard Worker return alarm(0);
150*663afb9bSAndroid Build Coastguard Worker }
151*663afb9bSAndroid Build Coastguard Worker #endif
152*663afb9bSAndroid Build Coastguard Worker
153*663afb9bSAndroid Build Coastguard Worker static enum outcome
testcase_run_bare_(const struct testcase_t * testcase)154*663afb9bSAndroid Build Coastguard Worker testcase_run_bare_(const struct testcase_t *testcase)
155*663afb9bSAndroid Build Coastguard Worker {
156*663afb9bSAndroid Build Coastguard Worker void *env = NULL;
157*663afb9bSAndroid Build Coastguard Worker int outcome;
158*663afb9bSAndroid Build Coastguard Worker if (testcase->setup) {
159*663afb9bSAndroid Build Coastguard Worker env = testcase->setup->setup_fn(testcase);
160*663afb9bSAndroid Build Coastguard Worker if (!env)
161*663afb9bSAndroid Build Coastguard Worker return FAIL;
162*663afb9bSAndroid Build Coastguard Worker else if (env == (void*)TT_SKIP)
163*663afb9bSAndroid Build Coastguard Worker return SKIP;
164*663afb9bSAndroid Build Coastguard Worker }
165*663afb9bSAndroid Build Coastguard Worker
166*663afb9bSAndroid Build Coastguard Worker cur_test_outcome = OK;
167*663afb9bSAndroid Build Coastguard Worker {
168*663afb9bSAndroid Build Coastguard Worker if (opt_timeout) {
169*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
170*663afb9bSAndroid Build Coastguard Worker cur_test_outcome = testcase_run_in_thread_(testcase, env);
171*663afb9bSAndroid Build Coastguard Worker #else
172*663afb9bSAndroid Build Coastguard Worker testcase_set_timeout_();
173*663afb9bSAndroid Build Coastguard Worker testcase->fn(env);
174*663afb9bSAndroid Build Coastguard Worker testcase_reset_timeout_();
175*663afb9bSAndroid Build Coastguard Worker #endif
176*663afb9bSAndroid Build Coastguard Worker } else {
177*663afb9bSAndroid Build Coastguard Worker testcase->fn(env);
178*663afb9bSAndroid Build Coastguard Worker }
179*663afb9bSAndroid Build Coastguard Worker }
180*663afb9bSAndroid Build Coastguard Worker outcome = cur_test_outcome;
181*663afb9bSAndroid Build Coastguard Worker
182*663afb9bSAndroid Build Coastguard Worker if (testcase->setup) {
183*663afb9bSAndroid Build Coastguard Worker if (testcase->setup->cleanup_fn(testcase, env) == 0)
184*663afb9bSAndroid Build Coastguard Worker outcome = FAIL;
185*663afb9bSAndroid Build Coastguard Worker }
186*663afb9bSAndroid Build Coastguard Worker
187*663afb9bSAndroid Build Coastguard Worker return outcome;
188*663afb9bSAndroid Build Coastguard Worker }
189*663afb9bSAndroid Build Coastguard Worker
190*663afb9bSAndroid Build Coastguard Worker
191*663afb9bSAndroid Build Coastguard Worker #ifndef NO_FORKING
192*663afb9bSAndroid Build Coastguard Worker
193*663afb9bSAndroid Build Coastguard Worker static enum outcome
testcase_run_forked_(const struct testgroup_t * group,const struct testcase_t * testcase)194*663afb9bSAndroid Build Coastguard Worker testcase_run_forked_(const struct testgroup_t *group,
195*663afb9bSAndroid Build Coastguard Worker const struct testcase_t *testcase)
196*663afb9bSAndroid Build Coastguard Worker {
197*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
198*663afb9bSAndroid Build Coastguard Worker /* Fork? On Win32? How primitive! We'll do what the smart kids do:
199*663afb9bSAndroid Build Coastguard Worker we'll invoke our own exe (whose name we recall from the command
200*663afb9bSAndroid Build Coastguard Worker line) with a command line that tells it to run just the test we
201*663afb9bSAndroid Build Coastguard Worker want, and this time without forking.
202*663afb9bSAndroid Build Coastguard Worker
203*663afb9bSAndroid Build Coastguard Worker (No, threads aren't an option. The whole point of forking is to
204*663afb9bSAndroid Build Coastguard Worker share no state between tests.)
205*663afb9bSAndroid Build Coastguard Worker */
206*663afb9bSAndroid Build Coastguard Worker int ok;
207*663afb9bSAndroid Build Coastguard Worker char buffer[LONGEST_TEST_NAME+256];
208*663afb9bSAndroid Build Coastguard Worker STARTUPINFOA si;
209*663afb9bSAndroid Build Coastguard Worker PROCESS_INFORMATION info;
210*663afb9bSAndroid Build Coastguard Worker DWORD ret;
211*663afb9bSAndroid Build Coastguard Worker
212*663afb9bSAndroid Build Coastguard Worker if (!in_tinytest_main) {
213*663afb9bSAndroid Build Coastguard Worker printf("\nERROR. On Windows, testcase_run_forked_ must be"
214*663afb9bSAndroid Build Coastguard Worker " called from within tinytest_main.\n");
215*663afb9bSAndroid Build Coastguard Worker abort();
216*663afb9bSAndroid Build Coastguard Worker }
217*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity>0)
218*663afb9bSAndroid Build Coastguard Worker printf("[forking] ");
219*663afb9bSAndroid Build Coastguard Worker
220*663afb9bSAndroid Build Coastguard Worker snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s --timeout 0 %s%s",
221*663afb9bSAndroid Build Coastguard Worker commandname, verbosity_flag, group->prefix, testcase->name);
222*663afb9bSAndroid Build Coastguard Worker
223*663afb9bSAndroid Build Coastguard Worker memset(&si, 0, sizeof(si));
224*663afb9bSAndroid Build Coastguard Worker memset(&info, 0, sizeof(info));
225*663afb9bSAndroid Build Coastguard Worker si.cb = sizeof(si);
226*663afb9bSAndroid Build Coastguard Worker
227*663afb9bSAndroid Build Coastguard Worker ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
228*663afb9bSAndroid Build Coastguard Worker 0, NULL, NULL, &si, &info);
229*663afb9bSAndroid Build Coastguard Worker if (!ok) {
230*663afb9bSAndroid Build Coastguard Worker printf("CreateProcess failed!\n");
231*663afb9bSAndroid Build Coastguard Worker return FAIL;
232*663afb9bSAndroid Build Coastguard Worker }
233*663afb9bSAndroid Build Coastguard Worker ret = WaitForSingleObject(info.hProcess,
234*663afb9bSAndroid Build Coastguard Worker (opt_timeout ? opt_timeout * 1000U : INFINITE));
235*663afb9bSAndroid Build Coastguard Worker
236*663afb9bSAndroid Build Coastguard Worker if (ret == WAIT_OBJECT_0) {
237*663afb9bSAndroid Build Coastguard Worker GetExitCodeProcess(info.hProcess, &ret);
238*663afb9bSAndroid Build Coastguard Worker } else if (ret == WAIT_TIMEOUT) {
239*663afb9bSAndroid Build Coastguard Worker printf("timeout\n");
240*663afb9bSAndroid Build Coastguard Worker } else {
241*663afb9bSAndroid Build Coastguard Worker printf("Wait failed\n");
242*663afb9bSAndroid Build Coastguard Worker }
243*663afb9bSAndroid Build Coastguard Worker CloseHandle(info.hProcess);
244*663afb9bSAndroid Build Coastguard Worker CloseHandle(info.hThread);
245*663afb9bSAndroid Build Coastguard Worker if (ret == 0)
246*663afb9bSAndroid Build Coastguard Worker return OK;
247*663afb9bSAndroid Build Coastguard Worker else if (ret == MAGIC_EXITCODE)
248*663afb9bSAndroid Build Coastguard Worker return SKIP;
249*663afb9bSAndroid Build Coastguard Worker else
250*663afb9bSAndroid Build Coastguard Worker return FAIL;
251*663afb9bSAndroid Build Coastguard Worker #else
252*663afb9bSAndroid Build Coastguard Worker int outcome_pipe[2];
253*663afb9bSAndroid Build Coastguard Worker pid_t pid;
254*663afb9bSAndroid Build Coastguard Worker (void)group;
255*663afb9bSAndroid Build Coastguard Worker
256*663afb9bSAndroid Build Coastguard Worker if (pipe(outcome_pipe))
257*663afb9bSAndroid Build Coastguard Worker perror("opening pipe");
258*663afb9bSAndroid Build Coastguard Worker
259*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity>0)
260*663afb9bSAndroid Build Coastguard Worker printf("[forking] ");
261*663afb9bSAndroid Build Coastguard Worker pid = fork();
262*663afb9bSAndroid Build Coastguard Worker #ifdef FORK_BREAKS_GCOV
263*663afb9bSAndroid Build Coastguard Worker vproc_transaction_begin(0);
264*663afb9bSAndroid Build Coastguard Worker #endif
265*663afb9bSAndroid Build Coastguard Worker if (!pid) {
266*663afb9bSAndroid Build Coastguard Worker /* child. */
267*663afb9bSAndroid Build Coastguard Worker int test_r, write_r;
268*663afb9bSAndroid Build Coastguard Worker char b[1];
269*663afb9bSAndroid Build Coastguard Worker close(outcome_pipe[0]);
270*663afb9bSAndroid Build Coastguard Worker test_r = testcase_run_bare_(testcase);
271*663afb9bSAndroid Build Coastguard Worker assert(0<=(int)test_r && (int)test_r<=2);
272*663afb9bSAndroid Build Coastguard Worker b[0] = "NYS"[test_r];
273*663afb9bSAndroid Build Coastguard Worker write_r = (int)write(outcome_pipe[1], b, 1);
274*663afb9bSAndroid Build Coastguard Worker if (write_r != 1) {
275*663afb9bSAndroid Build Coastguard Worker perror("write outcome to pipe");
276*663afb9bSAndroid Build Coastguard Worker exit(1);
277*663afb9bSAndroid Build Coastguard Worker }
278*663afb9bSAndroid Build Coastguard Worker exit(0);
279*663afb9bSAndroid Build Coastguard Worker return FAIL; /* unreachable */
280*663afb9bSAndroid Build Coastguard Worker } else {
281*663afb9bSAndroid Build Coastguard Worker /* parent */
282*663afb9bSAndroid Build Coastguard Worker int status, r, exitcode;
283*663afb9bSAndroid Build Coastguard Worker char b[1];
284*663afb9bSAndroid Build Coastguard Worker /* Close this now, so that if the other side closes it,
285*663afb9bSAndroid Build Coastguard Worker * our read fails. */
286*663afb9bSAndroid Build Coastguard Worker close(outcome_pipe[1]);
287*663afb9bSAndroid Build Coastguard Worker r = (int)read(outcome_pipe[0], b, 1);
288*663afb9bSAndroid Build Coastguard Worker if (r == 0) {
289*663afb9bSAndroid Build Coastguard Worker printf("[Lost connection!] ");
290*663afb9bSAndroid Build Coastguard Worker return FAIL;
291*663afb9bSAndroid Build Coastguard Worker } else if (r != 1) {
292*663afb9bSAndroid Build Coastguard Worker perror("read outcome from pipe");
293*663afb9bSAndroid Build Coastguard Worker }
294*663afb9bSAndroid Build Coastguard Worker waitpid(pid, &status, 0);
295*663afb9bSAndroid Build Coastguard Worker exitcode = WEXITSTATUS(status);
296*663afb9bSAndroid Build Coastguard Worker close(outcome_pipe[0]);
297*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity>1)
298*663afb9bSAndroid Build Coastguard Worker printf("%s%s: exited with %i (%i)\n", group->prefix, testcase->name, exitcode, status);
299*663afb9bSAndroid Build Coastguard Worker if (exitcode != 0)
300*663afb9bSAndroid Build Coastguard Worker {
301*663afb9bSAndroid Build Coastguard Worker printf("[atexit failure!] ");
302*663afb9bSAndroid Build Coastguard Worker return FAIL;
303*663afb9bSAndroid Build Coastguard Worker }
304*663afb9bSAndroid Build Coastguard Worker return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
305*663afb9bSAndroid Build Coastguard Worker }
306*663afb9bSAndroid Build Coastguard Worker #endif
307*663afb9bSAndroid Build Coastguard Worker }
308*663afb9bSAndroid Build Coastguard Worker
309*663afb9bSAndroid Build Coastguard Worker #endif /* !NO_FORKING */
310*663afb9bSAndroid Build Coastguard Worker
311*663afb9bSAndroid Build Coastguard Worker int
testcase_run_one(const struct testgroup_t * group,const struct testcase_t * testcase)312*663afb9bSAndroid Build Coastguard Worker testcase_run_one(const struct testgroup_t *group,
313*663afb9bSAndroid Build Coastguard Worker const struct testcase_t *testcase)
314*663afb9bSAndroid Build Coastguard Worker {
315*663afb9bSAndroid Build Coastguard Worker enum outcome outcome;
316*663afb9bSAndroid Build Coastguard Worker
317*663afb9bSAndroid Build Coastguard Worker if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
318*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity>0)
319*663afb9bSAndroid Build Coastguard Worker printf("%s%s: %s\n",
320*663afb9bSAndroid Build Coastguard Worker group->prefix, testcase->name,
321*663afb9bSAndroid Build Coastguard Worker (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
322*663afb9bSAndroid Build Coastguard Worker ++n_skipped;
323*663afb9bSAndroid Build Coastguard Worker return SKIP;
324*663afb9bSAndroid Build Coastguard Worker }
325*663afb9bSAndroid Build Coastguard Worker
326*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity>0 && !opt_forked) {
327*663afb9bSAndroid Build Coastguard Worker printf("%s%s: ", group->prefix, testcase->name);
328*663afb9bSAndroid Build Coastguard Worker } else {
329*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity==0) printf(".");
330*663afb9bSAndroid Build Coastguard Worker cur_test_prefix = group->prefix;
331*663afb9bSAndroid Build Coastguard Worker cur_test_name = testcase->name;
332*663afb9bSAndroid Build Coastguard Worker }
333*663afb9bSAndroid Build Coastguard Worker
334*663afb9bSAndroid Build Coastguard Worker #ifndef NO_FORKING
335*663afb9bSAndroid Build Coastguard Worker if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
336*663afb9bSAndroid Build Coastguard Worker outcome = testcase_run_forked_(group, testcase);
337*663afb9bSAndroid Build Coastguard Worker } else {
338*663afb9bSAndroid Build Coastguard Worker #else
339*663afb9bSAndroid Build Coastguard Worker {
340*663afb9bSAndroid Build Coastguard Worker #endif
341*663afb9bSAndroid Build Coastguard Worker outcome = testcase_run_bare_(testcase);
342*663afb9bSAndroid Build Coastguard Worker }
343*663afb9bSAndroid Build Coastguard Worker
344*663afb9bSAndroid Build Coastguard Worker if (outcome == OK) {
345*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity>0 && !opt_forked)
346*663afb9bSAndroid Build Coastguard Worker puts(opt_verbosity==1?"OK":"");
347*663afb9bSAndroid Build Coastguard Worker } else if (outcome == SKIP) {
348*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity>0 && !opt_forked)
349*663afb9bSAndroid Build Coastguard Worker puts("SKIPPED");
350*663afb9bSAndroid Build Coastguard Worker } else {
351*663afb9bSAndroid Build Coastguard Worker if (!opt_forked)
352*663afb9bSAndroid Build Coastguard Worker printf("\n [%s FAILED]\n", testcase->name);
353*663afb9bSAndroid Build Coastguard Worker }
354*663afb9bSAndroid Build Coastguard Worker
355*663afb9bSAndroid Build Coastguard Worker if (opt_forked) {
356*663afb9bSAndroid Build Coastguard Worker exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
357*663afb9bSAndroid Build Coastguard Worker return 1; /* unreachable */
358*663afb9bSAndroid Build Coastguard Worker } else {
359*663afb9bSAndroid Build Coastguard Worker return (int)outcome;
360*663afb9bSAndroid Build Coastguard Worker }
361*663afb9bSAndroid Build Coastguard Worker }
362*663afb9bSAndroid Build Coastguard Worker
363*663afb9bSAndroid Build Coastguard Worker int
364*663afb9bSAndroid Build Coastguard Worker tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag)
365*663afb9bSAndroid Build Coastguard Worker {
366*663afb9bSAndroid Build Coastguard Worker int i, j;
367*663afb9bSAndroid Build Coastguard Worker size_t length = LONGEST_TEST_NAME;
368*663afb9bSAndroid Build Coastguard Worker char fullname[LONGEST_TEST_NAME];
369*663afb9bSAndroid Build Coastguard Worker int found=0;
370*663afb9bSAndroid Build Coastguard Worker if (strstr(arg, ".."))
371*663afb9bSAndroid Build Coastguard Worker length = strstr(arg,"..")-arg;
372*663afb9bSAndroid Build Coastguard Worker for (i=0; groups[i].prefix; ++i) {
373*663afb9bSAndroid Build Coastguard Worker for (j=0; groups[i].cases[j].name; ++j) {
374*663afb9bSAndroid Build Coastguard Worker struct testcase_t *testcase = &groups[i].cases[j];
375*663afb9bSAndroid Build Coastguard Worker snprintf(fullname, sizeof(fullname), "%s%s",
376*663afb9bSAndroid Build Coastguard Worker groups[i].prefix, testcase->name);
377*663afb9bSAndroid Build Coastguard Worker if (!flag) { /* Hack! */
378*663afb9bSAndroid Build Coastguard Worker printf(" %s", fullname);
379*663afb9bSAndroid Build Coastguard Worker if (testcase->flags & TT_OFF_BY_DEFAULT)
380*663afb9bSAndroid Build Coastguard Worker puts(" (Off by default)");
381*663afb9bSAndroid Build Coastguard Worker else if (testcase->flags & TT_SKIP)
382*663afb9bSAndroid Build Coastguard Worker puts(" (DISABLED)");
383*663afb9bSAndroid Build Coastguard Worker else
384*663afb9bSAndroid Build Coastguard Worker puts("");
385*663afb9bSAndroid Build Coastguard Worker }
386*663afb9bSAndroid Build Coastguard Worker if (!strncmp(fullname, arg, length)) {
387*663afb9bSAndroid Build Coastguard Worker if (set)
388*663afb9bSAndroid Build Coastguard Worker testcase->flags |= flag;
389*663afb9bSAndroid Build Coastguard Worker else
390*663afb9bSAndroid Build Coastguard Worker testcase->flags &= ~flag;
391*663afb9bSAndroid Build Coastguard Worker ++found;
392*663afb9bSAndroid Build Coastguard Worker }
393*663afb9bSAndroid Build Coastguard Worker }
394*663afb9bSAndroid Build Coastguard Worker }
395*663afb9bSAndroid Build Coastguard Worker return found;
396*663afb9bSAndroid Build Coastguard Worker }
397*663afb9bSAndroid Build Coastguard Worker
398*663afb9bSAndroid Build Coastguard Worker static void
399*663afb9bSAndroid Build Coastguard Worker usage(struct testgroup_t *groups, int list_groups)
400*663afb9bSAndroid Build Coastguard Worker {
401*663afb9bSAndroid Build Coastguard Worker puts("Options are: [--verbose|--quiet|--terse] [--no-fork] [--timeout <sec>]");
402*663afb9bSAndroid Build Coastguard Worker puts(" Specify tests by name, or using a prefix ending with '..'");
403*663afb9bSAndroid Build Coastguard Worker puts(" To skip a test, prefix its name with a colon.");
404*663afb9bSAndroid Build Coastguard Worker puts(" To enable a disabled test, prefix its name with a plus.");
405*663afb9bSAndroid Build Coastguard Worker puts(" Use --list-tests for a list of tests.");
406*663afb9bSAndroid Build Coastguard Worker if (list_groups) {
407*663afb9bSAndroid Build Coastguard Worker puts("Known tests are:");
408*663afb9bSAndroid Build Coastguard Worker tinytest_set_flag_(groups, "..", 1, 0);
409*663afb9bSAndroid Build Coastguard Worker }
410*663afb9bSAndroid Build Coastguard Worker exit(0);
411*663afb9bSAndroid Build Coastguard Worker }
412*663afb9bSAndroid Build Coastguard Worker
413*663afb9bSAndroid Build Coastguard Worker static int
414*663afb9bSAndroid Build Coastguard Worker process_test_alias(struct testgroup_t *groups, const char *test)
415*663afb9bSAndroid Build Coastguard Worker {
416*663afb9bSAndroid Build Coastguard Worker int i, j, n, r;
417*663afb9bSAndroid Build Coastguard Worker for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
418*663afb9bSAndroid Build Coastguard Worker if (!strcmp(cfg_aliases[i].name, test)) {
419*663afb9bSAndroid Build Coastguard Worker n = 0;
420*663afb9bSAndroid Build Coastguard Worker for (j = 0; cfg_aliases[i].tests[j]; ++j) {
421*663afb9bSAndroid Build Coastguard Worker r = process_test_option(groups, cfg_aliases[i].tests[j]);
422*663afb9bSAndroid Build Coastguard Worker if (r<0)
423*663afb9bSAndroid Build Coastguard Worker return -1;
424*663afb9bSAndroid Build Coastguard Worker n += r;
425*663afb9bSAndroid Build Coastguard Worker }
426*663afb9bSAndroid Build Coastguard Worker return n;
427*663afb9bSAndroid Build Coastguard Worker }
428*663afb9bSAndroid Build Coastguard Worker }
429*663afb9bSAndroid Build Coastguard Worker printf("No such test alias as @%s!",test);
430*663afb9bSAndroid Build Coastguard Worker return -1;
431*663afb9bSAndroid Build Coastguard Worker }
432*663afb9bSAndroid Build Coastguard Worker
433*663afb9bSAndroid Build Coastguard Worker static int
434*663afb9bSAndroid Build Coastguard Worker process_test_option(struct testgroup_t *groups, const char *test)
435*663afb9bSAndroid Build Coastguard Worker {
436*663afb9bSAndroid Build Coastguard Worker int flag = TT_ENABLED_;
437*663afb9bSAndroid Build Coastguard Worker int n = 0;
438*663afb9bSAndroid Build Coastguard Worker if (test[0] == '@') {
439*663afb9bSAndroid Build Coastguard Worker return process_test_alias(groups, test + 1);
440*663afb9bSAndroid Build Coastguard Worker } else if (test[0] == ':') {
441*663afb9bSAndroid Build Coastguard Worker ++test;
442*663afb9bSAndroid Build Coastguard Worker flag = TT_SKIP;
443*663afb9bSAndroid Build Coastguard Worker } else if (test[0] == '+') {
444*663afb9bSAndroid Build Coastguard Worker ++test;
445*663afb9bSAndroid Build Coastguard Worker ++n;
446*663afb9bSAndroid Build Coastguard Worker if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
447*663afb9bSAndroid Build Coastguard Worker printf("No such test as %s!\n", test);
448*663afb9bSAndroid Build Coastguard Worker return -1;
449*663afb9bSAndroid Build Coastguard Worker }
450*663afb9bSAndroid Build Coastguard Worker } else {
451*663afb9bSAndroid Build Coastguard Worker ++n;
452*663afb9bSAndroid Build Coastguard Worker }
453*663afb9bSAndroid Build Coastguard Worker if (!tinytest_set_flag_(groups, test, 1, flag)) {
454*663afb9bSAndroid Build Coastguard Worker printf("No such test as %s!\n", test);
455*663afb9bSAndroid Build Coastguard Worker return -1;
456*663afb9bSAndroid Build Coastguard Worker }
457*663afb9bSAndroid Build Coastguard Worker return n;
458*663afb9bSAndroid Build Coastguard Worker }
459*663afb9bSAndroid Build Coastguard Worker
460*663afb9bSAndroid Build Coastguard Worker void
461*663afb9bSAndroid Build Coastguard Worker tinytest_set_aliases(const struct testlist_alias_t *aliases)
462*663afb9bSAndroid Build Coastguard Worker {
463*663afb9bSAndroid Build Coastguard Worker cfg_aliases = aliases;
464*663afb9bSAndroid Build Coastguard Worker }
465*663afb9bSAndroid Build Coastguard Worker
466*663afb9bSAndroid Build Coastguard Worker int
467*663afb9bSAndroid Build Coastguard Worker tinytest_main(int c, const char **v, struct testgroup_t *groups)
468*663afb9bSAndroid Build Coastguard Worker {
469*663afb9bSAndroid Build Coastguard Worker int i, j, n=0;
470*663afb9bSAndroid Build Coastguard Worker
471*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
472*663afb9bSAndroid Build Coastguard Worker const char *sp = strrchr(v[0], '.');
473*663afb9bSAndroid Build Coastguard Worker const char *extension = "";
474*663afb9bSAndroid Build Coastguard Worker if (!sp || stricmp(sp, ".exe"))
475*663afb9bSAndroid Build Coastguard Worker extension = ".exe"; /* Add an exe so CreateProcess will work */
476*663afb9bSAndroid Build Coastguard Worker snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
477*663afb9bSAndroid Build Coastguard Worker commandname[MAX_PATH]='\0';
478*663afb9bSAndroid Build Coastguard Worker #endif
479*663afb9bSAndroid Build Coastguard Worker for (i=1; i<c; ++i) {
480*663afb9bSAndroid Build Coastguard Worker if (v[i][0] == '-') {
481*663afb9bSAndroid Build Coastguard Worker if (!strcmp(v[i], "--RUNNING-FORKED")) {
482*663afb9bSAndroid Build Coastguard Worker opt_forked = 1;
483*663afb9bSAndroid Build Coastguard Worker } else if (!strcmp(v[i], "--no-fork")) {
484*663afb9bSAndroid Build Coastguard Worker opt_nofork = 1;
485*663afb9bSAndroid Build Coastguard Worker } else if (!strcmp(v[i], "--quiet")) {
486*663afb9bSAndroid Build Coastguard Worker opt_verbosity = -1;
487*663afb9bSAndroid Build Coastguard Worker verbosity_flag = "--quiet";
488*663afb9bSAndroid Build Coastguard Worker } else if (!strcmp(v[i], "--verbose")) {
489*663afb9bSAndroid Build Coastguard Worker opt_verbosity = 2;
490*663afb9bSAndroid Build Coastguard Worker verbosity_flag = "--verbose";
491*663afb9bSAndroid Build Coastguard Worker } else if (!strcmp(v[i], "--terse")) {
492*663afb9bSAndroid Build Coastguard Worker opt_verbosity = 0;
493*663afb9bSAndroid Build Coastguard Worker verbosity_flag = "--terse";
494*663afb9bSAndroid Build Coastguard Worker } else if (!strcmp(v[i], "--help")) {
495*663afb9bSAndroid Build Coastguard Worker usage(groups, 0);
496*663afb9bSAndroid Build Coastguard Worker } else if (!strcmp(v[i], "--list-tests")) {
497*663afb9bSAndroid Build Coastguard Worker usage(groups, 1);
498*663afb9bSAndroid Build Coastguard Worker } else if (!strcmp(v[i], "--timeout")) {
499*663afb9bSAndroid Build Coastguard Worker ++i;
500*663afb9bSAndroid Build Coastguard Worker if (i >= c) {
501*663afb9bSAndroid Build Coastguard Worker fprintf(stderr, "--timeout requires argument\n");
502*663afb9bSAndroid Build Coastguard Worker return -1;
503*663afb9bSAndroid Build Coastguard Worker }
504*663afb9bSAndroid Build Coastguard Worker opt_timeout = (unsigned)atoi(v[i]);
505*663afb9bSAndroid Build Coastguard Worker } else {
506*663afb9bSAndroid Build Coastguard Worker fprintf(stderr, "Unknown option %s. Try --help\n", v[i]);
507*663afb9bSAndroid Build Coastguard Worker return -1;
508*663afb9bSAndroid Build Coastguard Worker }
509*663afb9bSAndroid Build Coastguard Worker } else {
510*663afb9bSAndroid Build Coastguard Worker int r = process_test_option(groups, v[i]);
511*663afb9bSAndroid Build Coastguard Worker if (r<0)
512*663afb9bSAndroid Build Coastguard Worker return -1;
513*663afb9bSAndroid Build Coastguard Worker n += r;
514*663afb9bSAndroid Build Coastguard Worker }
515*663afb9bSAndroid Build Coastguard Worker }
516*663afb9bSAndroid Build Coastguard Worker if (!n)
517*663afb9bSAndroid Build Coastguard Worker tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
518*663afb9bSAndroid Build Coastguard Worker
519*663afb9bSAndroid Build Coastguard Worker #ifdef _IONBF
520*663afb9bSAndroid Build Coastguard Worker setvbuf(stdout, NULL, _IONBF, 0);
521*663afb9bSAndroid Build Coastguard Worker #endif
522*663afb9bSAndroid Build Coastguard Worker
523*663afb9bSAndroid Build Coastguard Worker ++in_tinytest_main;
524*663afb9bSAndroid Build Coastguard Worker for (i = 0; groups[i].prefix; ++i) {
525*663afb9bSAndroid Build Coastguard Worker struct testgroup_t *group = &groups[i];
526*663afb9bSAndroid Build Coastguard Worker for (j = 0; group->cases[j].name; ++j) {
527*663afb9bSAndroid Build Coastguard Worker struct testcase_t *testcase = &group->cases[j];
528*663afb9bSAndroid Build Coastguard Worker int test_attempts = 3;
529*663afb9bSAndroid Build Coastguard Worker int test_ret_err;
530*663afb9bSAndroid Build Coastguard Worker
531*663afb9bSAndroid Build Coastguard Worker if (!(testcase->flags & TT_ENABLED_))
532*663afb9bSAndroid Build Coastguard Worker continue;
533*663afb9bSAndroid Build Coastguard Worker
534*663afb9bSAndroid Build Coastguard Worker for (;;) {
535*663afb9bSAndroid Build Coastguard Worker test_ret_err = testcase_run_one(group, testcase);
536*663afb9bSAndroid Build Coastguard Worker
537*663afb9bSAndroid Build Coastguard Worker if (test_ret_err == OK)
538*663afb9bSAndroid Build Coastguard Worker break;
539*663afb9bSAndroid Build Coastguard Worker if (!(testcase->flags & TT_RETRIABLE))
540*663afb9bSAndroid Build Coastguard Worker break;
541*663afb9bSAndroid Build Coastguard Worker printf("\n [RETRYING %s (%i)]\n", testcase->name, test_attempts);
542*663afb9bSAndroid Build Coastguard Worker if (!test_attempts--)
543*663afb9bSAndroid Build Coastguard Worker break;
544*663afb9bSAndroid Build Coastguard Worker }
545*663afb9bSAndroid Build Coastguard Worker
546*663afb9bSAndroid Build Coastguard Worker switch (test_ret_err) {
547*663afb9bSAndroid Build Coastguard Worker case OK: ++n_ok; break;
548*663afb9bSAndroid Build Coastguard Worker case SKIP: ++n_skipped; break;
549*663afb9bSAndroid Build Coastguard Worker default: ++n_bad; break;
550*663afb9bSAndroid Build Coastguard Worker }
551*663afb9bSAndroid Build Coastguard Worker }
552*663afb9bSAndroid Build Coastguard Worker }
553*663afb9bSAndroid Build Coastguard Worker
554*663afb9bSAndroid Build Coastguard Worker --in_tinytest_main;
555*663afb9bSAndroid Build Coastguard Worker
556*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity==0)
557*663afb9bSAndroid Build Coastguard Worker puts("");
558*663afb9bSAndroid Build Coastguard Worker
559*663afb9bSAndroid Build Coastguard Worker if (n_bad)
560*663afb9bSAndroid Build Coastguard Worker printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
561*663afb9bSAndroid Build Coastguard Worker n_bad+n_ok,n_skipped);
562*663afb9bSAndroid Build Coastguard Worker else if (opt_verbosity >= 1)
563*663afb9bSAndroid Build Coastguard Worker printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
564*663afb9bSAndroid Build Coastguard Worker
565*663afb9bSAndroid Build Coastguard Worker return (n_bad == 0) ? 0 : 1;
566*663afb9bSAndroid Build Coastguard Worker }
567*663afb9bSAndroid Build Coastguard Worker
568*663afb9bSAndroid Build Coastguard Worker int
569*663afb9bSAndroid Build Coastguard Worker tinytest_get_verbosity_(void)
570*663afb9bSAndroid Build Coastguard Worker {
571*663afb9bSAndroid Build Coastguard Worker return opt_verbosity;
572*663afb9bSAndroid Build Coastguard Worker }
573*663afb9bSAndroid Build Coastguard Worker
574*663afb9bSAndroid Build Coastguard Worker void
575*663afb9bSAndroid Build Coastguard Worker tinytest_set_test_failed_(void)
576*663afb9bSAndroid Build Coastguard Worker {
577*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity <= 0 && cur_test_name) {
578*663afb9bSAndroid Build Coastguard Worker if (opt_verbosity==0) puts("");
579*663afb9bSAndroid Build Coastguard Worker printf("%s%s: ", cur_test_prefix, cur_test_name);
580*663afb9bSAndroid Build Coastguard Worker cur_test_name = NULL;
581*663afb9bSAndroid Build Coastguard Worker }
582*663afb9bSAndroid Build Coastguard Worker cur_test_outcome = FAIL;
583*663afb9bSAndroid Build Coastguard Worker }
584*663afb9bSAndroid Build Coastguard Worker
585*663afb9bSAndroid Build Coastguard Worker void
586*663afb9bSAndroid Build Coastguard Worker tinytest_set_test_skipped_(void)
587*663afb9bSAndroid Build Coastguard Worker {
588*663afb9bSAndroid Build Coastguard Worker if (cur_test_outcome==OK)
589*663afb9bSAndroid Build Coastguard Worker cur_test_outcome = SKIP;
590*663afb9bSAndroid Build Coastguard Worker }
591*663afb9bSAndroid Build Coastguard Worker
592*663afb9bSAndroid Build Coastguard Worker char *
593*663afb9bSAndroid Build Coastguard Worker tinytest_format_hex_(const void *val_, unsigned long len)
594*663afb9bSAndroid Build Coastguard Worker {
595*663afb9bSAndroid Build Coastguard Worker const unsigned char *val = val_;
596*663afb9bSAndroid Build Coastguard Worker char *result, *cp;
597*663afb9bSAndroid Build Coastguard Worker size_t i;
598*663afb9bSAndroid Build Coastguard Worker
599*663afb9bSAndroid Build Coastguard Worker if (!val)
600*663afb9bSAndroid Build Coastguard Worker return strdup("null");
601*663afb9bSAndroid Build Coastguard Worker if (!(result = malloc(len*2+1)))
602*663afb9bSAndroid Build Coastguard Worker return strdup("<allocation failure>");
603*663afb9bSAndroid Build Coastguard Worker cp = result;
604*663afb9bSAndroid Build Coastguard Worker for (i=0;i<len;++i) {
605*663afb9bSAndroid Build Coastguard Worker *cp++ = "0123456789ABCDEF"[val[i] >> 4];
606*663afb9bSAndroid Build Coastguard Worker *cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
607*663afb9bSAndroid Build Coastguard Worker }
608*663afb9bSAndroid Build Coastguard Worker *cp = 0;
609*663afb9bSAndroid Build Coastguard Worker return result;
610*663afb9bSAndroid Build Coastguard Worker }
611