~sergei.glushchenko/percona-xtrabackup/bug711166_part-1.9

« back to all changes in this revision

Viewing changes to src/libarchive/cpio/test/main.c

merge parallel compression branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2003-2009 Tim Kientzle
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 * 2. Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in the
 
12
 *    documentation and/or other materials provided with the distribution.
 
13
 *
 
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
17
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
24
 */
 
25
 
 
26
#include "test.h"
 
27
#include <errno.h>
 
28
#include <locale.h>
 
29
#include <stdarg.h>
 
30
#include <time.h>
 
31
 
 
32
/*
 
33
 * This same file is used pretty much verbatim for all test harnesses.
 
34
 *
 
35
 * The next few lines are the only differences.
 
36
 * TODO: Move this into a separate configuration header, have all test
 
37
 * suites share one copy of this file.
 
38
 */
 
39
__FBSDID("$FreeBSD: src/usr.bin/cpio/test/main.c,v 1.3 2008/08/24 04:58:22 kientzle Exp $");
 
40
#define KNOWNREF        "test_option_f.cpio.uu"
 
41
#define ENVBASE "BSDCPIO" /* Prefix for environment variables. */
 
42
#define PROGRAM "bsdcpio" /* Name of program being tested. */
 
43
#undef LIBRARY            /* Not testing a library. */
 
44
#undef  EXTRA_DUMP           /* How to dump extra data */
 
45
/* How to generate extra version info. */
 
46
#define EXTRA_VERSION    (systemf("%s --version", testprog) ? "" : "")
 
47
 
 
48
/*
 
49
 *
 
50
 * Windows support routines
 
51
 *
 
52
 * Note: Configuration is a tricky issue.  Using HAVE_* feature macros
 
53
 * in the test harness is dangerous because they cover up
 
54
 * configuration errors.  The classic example of this is omitting a
 
55
 * configure check.  If libarchive and libarchive_test both look for
 
56
 * the same feature macro, such errors are hard to detect.  Platform
 
57
 * macros (e.g., _WIN32 or __GNUC__) are a little better, but can
 
58
 * easily lead to very messy code.  It's best to limit yourself
 
59
 * to only the most generic programming techniques in the test harness
 
60
 * and thus avoid conditionals altogether.  Where that's not possible,
 
61
 * try to minimize conditionals by grouping platform-specific tests in
 
62
 * one place (e.g., test_acl_freebsd) or by adding new assert()
 
63
 * functions (e.g., assertMakeHardlink()) to cover up platform
 
64
 * differences.  Platform-specific coding in libarchive_test is often
 
65
 * a symptom that some capability is missing from libarchive itself.
 
66
 */
 
67
#if defined(_WIN32) && !defined(__CYGWIN__)
 
68
#include <io.h>
 
69
#include <windows.h>
 
70
#ifndef F_OK
 
71
#define F_OK (0)
 
72
#endif
 
73
#ifndef S_ISDIR
 
74
#define S_ISDIR(m)  ((m) & _S_IFDIR)
 
75
#endif
 
76
#ifndef S_ISREG
 
77
#define S_ISREG(m)  ((m) & _S_IFREG)
 
78
#endif
 
79
#if !defined(__BORLANDC__)
 
80
#define access _access
 
81
#define chdir _chdir
 
82
#endif
 
83
#ifndef fileno
 
84
#define fileno _fileno
 
85
#endif
 
86
/*#define fstat _fstat64*/
 
87
#if !defined(__BORLANDC__)
 
88
#define getcwd _getcwd
 
89
#endif
 
90
#define lstat stat
 
91
/*#define lstat _stat64*/
 
92
/*#define stat _stat64*/
 
93
#define rmdir _rmdir
 
94
#if !defined(__BORLANDC__)
 
95
#define strdup _strdup
 
96
#define umask _umask
 
97
#endif
 
98
#define int64_t __int64
 
99
#endif
 
100
 
 
101
#if defined(HAVE__CrtSetReportMode)
 
102
# include <crtdbg.h>
 
103
#endif
 
104
 
 
105
#if defined(_WIN32) && !defined(__CYGWIN__)
 
106
void *GetFunctionKernel32(const char *name)
 
107
{
 
108
        static HINSTANCE lib;
 
109
        static int set;
 
110
        if (!set) {
 
111
                set = 1;
 
112
                lib = LoadLibrary("kernel32.dll");
 
113
        }
 
114
        if (lib == NULL) {
 
115
                fprintf(stderr, "Can't load kernel32.dll?!\n");
 
116
                exit(1);
 
117
        }
 
118
        return (void *)GetProcAddress(lib, name);
 
119
}
 
120
 
 
121
static int
 
122
my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags)
 
123
{
 
124
        static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD);
 
125
        static int set;
 
126
        if (!set) {
 
127
                set = 1;
 
128
                f = GetFunctionKernel32("CreateSymbolicLinkA");
 
129
        }
 
130
        return f == NULL ? 0 : (*f)(linkname, target, flags);
 
131
}
 
132
 
 
133
static int
 
134
my_CreateHardLinkA(const char *linkname, const char *target)
 
135
{
 
136
        static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES);
 
137
        static int set;
 
138
        if (!set) {
 
139
                set = 1;
 
140
                f = GetFunctionKernel32("CreateHardLinkA");
 
141
        }
 
142
        return f == NULL ? 0 : (*f)(linkname, target, NULL);
 
143
}
 
144
 
 
145
int
 
146
my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi)
 
147
{
 
148
        HANDLE h;
 
149
        int r;
 
150
 
 
151
        memset(bhfi, 0, sizeof(*bhfi));
 
152
        h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL,
 
153
                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
154
        if (h == INVALID_HANDLE_VALUE)
 
155
                return (0);
 
156
        r = GetFileInformationByHandle(h, bhfi);
 
157
        CloseHandle(h);
 
158
        return (r);
 
159
}
 
160
#endif
 
161
 
 
162
#if defined(HAVE__CrtSetReportMode)
 
163
static void
 
164
invalid_parameter_handler(const wchar_t * expression,
 
165
    const wchar_t * function, const wchar_t * file,
 
166
    unsigned int line, uintptr_t pReserved)
 
167
{
 
168
        /* nop */
 
169
}
 
170
#endif
 
171
 
 
172
/*
 
173
 *
 
174
 * OPTIONS FLAGS
 
175
 *
 
176
 */
 
177
 
 
178
/* Enable core dump on failure. */
 
179
static int dump_on_failure = 0;
 
180
/* Default is to remove temp dirs and log data for successful tests. */
 
181
static int keep_temp_files = 0;
 
182
/* Default is to just report pass/fail for each test. */
 
183
static int verbosity = 0;
 
184
#define VERBOSITY_SUMMARY_ONLY -1 /* -q */
 
185
#define VERBOSITY_PASSFAIL 0   /* Default */
 
186
#define VERBOSITY_LIGHT_REPORT 1 /* -v */
 
187
#define VERBOSITY_FULL 2 /* -vv */
 
188
/* A few places generate even more output for verbosity > VERBOSITY_FULL,
 
189
 * mostly for debugging the test harness itself. */
 
190
/* Cumulative count of assertion failures. */
 
191
static int failures = 0;
 
192
/* Cumulative count of reported skips. */
 
193
static int skips = 0;
 
194
/* Cumulative count of assertions checked. */
 
195
static int assertions = 0;
 
196
 
 
197
/* Directory where uuencoded reference files can be found. */
 
198
static const char *refdir;
 
199
 
 
200
/*
 
201
 * Report log information selectively to console and/or disk log.
 
202
 */
 
203
static int log_console = 0;
 
204
static FILE *logfile;
 
205
static void
 
206
vlogprintf(const char *fmt, va_list ap)
 
207
{
 
208
#ifdef va_copy
 
209
        va_list lfap;
 
210
        va_copy(lfap, ap);
 
211
#endif
 
212
        if (log_console)
 
213
                vfprintf(stdout, fmt, ap);
 
214
        if (logfile != NULL)
 
215
#ifdef va_copy
 
216
                vfprintf(logfile, fmt, lfap);
 
217
        va_end(lfap);
 
218
#else
 
219
                vfprintf(logfile, fmt, ap);
 
220
#endif
 
221
}
 
222
 
 
223
static void
 
224
logprintf(const char *fmt, ...)
 
225
{
 
226
        va_list ap;
 
227
        va_start(ap, fmt);
 
228
        vlogprintf(fmt, ap);
 
229
        va_end(ap);
 
230
}
 
231
 
 
232
/* Set up a message to display only if next assertion fails. */
 
233
static char msgbuff[4096];
 
234
static const char *msg, *nextmsg;
 
235
void
 
236
failure(const char *fmt, ...)
 
237
{
 
238
        va_list ap;
 
239
        va_start(ap, fmt);
 
240
        vsprintf(msgbuff, fmt, ap);
 
241
        va_end(ap);
 
242
        nextmsg = msgbuff;
 
243
}
 
244
 
 
245
/*
 
246
 * Copy arguments into file-local variables.
 
247
 * This was added to permit vararg assert() functions without needing
 
248
 * variadic wrapper macros.  Turns out that the vararg capability is almost
 
249
 * never used, so almost all of the vararg assertions can be simplified
 
250
 * by removing the vararg capability and reworking the wrapper macro to
 
251
 * pass __FILE__, __LINE__ directly into the function instead of using
 
252
 * this hook.  I suspect this machinery is used so rarely that we
 
253
 * would be better off just removing it entirely.  That would simplify
 
254
 * the code here noticably.
 
255
 */
 
256
static const char *test_filename;
 
257
static int test_line;
 
258
static void *test_extra;
 
259
void assertion_setup(const char *filename, int line)
 
260
{
 
261
        test_filename = filename;
 
262
        test_line = line;
 
263
}
 
264
 
 
265
/* Called at the beginning of each assert() function. */
 
266
static void
 
267
assertion_count(const char *file, int line)
 
268
{
 
269
        (void)file; /* UNUSED */
 
270
        (void)line; /* UNUSED */
 
271
        ++assertions;
 
272
        /* Proper handling of "failure()" message. */
 
273
        msg = nextmsg;
 
274
        nextmsg = NULL;
 
275
        /* Uncomment to print file:line after every assertion.
 
276
         * Verbose, but occasionally useful in tracking down crashes. */
 
277
        /* printf("Checked %s:%d\n", file, line); */
 
278
}
 
279
 
 
280
/*
 
281
 * For each test source file, we remember how many times each
 
282
 * assertion was reported.  Cleared before each new test,
 
283
 * used by test_summarize().
 
284
 */
 
285
static struct line {
 
286
        int count;
 
287
        int skip;
 
288
}  failed_lines[10000];
 
289
 
 
290
/* Count this failure, setup up log destination and handle initial report. */
 
291
static void
 
292
failure_start(const char *filename, int line, const char *fmt, ...)
 
293
{
 
294
        va_list ap;
 
295
 
 
296
        /* Record another failure for this line. */
 
297
        ++failures;
 
298
        /* test_filename = filename; */
 
299
        failed_lines[line].count++;
 
300
 
 
301
        /* Determine whether to log header to console. */
 
302
        switch (verbosity) {
 
303
        case VERBOSITY_FULL:
 
304
                log_console = 1;
 
305
                break;
 
306
        case VERBOSITY_LIGHT_REPORT:
 
307
                log_console = (failed_lines[line].count < 2);
 
308
                break;
 
309
        default:
 
310
                log_console = 0;
 
311
        }
 
312
 
 
313
        /* Log file:line header for this failure */
 
314
        va_start(ap, fmt);
 
315
#if _MSC_VER
 
316
        logprintf("%s(%d): ", filename, line);
 
317
#else
 
318
        logprintf("%s:%d: ", filename, line);
 
319
#endif
 
320
        vlogprintf(fmt, ap);
 
321
        va_end(ap);
 
322
        logprintf("\n");
 
323
 
 
324
        if (msg != NULL && msg[0] != '\0') {
 
325
                logprintf("   Description: %s\n", msg);
 
326
                msg = NULL;
 
327
        }
 
328
 
 
329
        /* Determine whether to log details to console. */
 
330
        if (verbosity == VERBOSITY_LIGHT_REPORT)
 
331
                log_console = 0;
 
332
}
 
333
 
 
334
/* Complete reporting of failed tests. */
 
335
/*
 
336
 * The 'extra' hook here is used by libarchive to include libarchive
 
337
 * error messages with assertion failures.  It could also be used
 
338
 * to add strerror() output, for example.  Just define the EXTRA_DUMP()
 
339
 * macro appropriately.
 
340
 */
 
341
static void
 
342
failure_finish(void *extra)
 
343
{
 
344
        (void)extra; /* UNUSED (maybe) */
 
345
#ifdef EXTRA_DUMP
 
346
        if (extra != NULL)
 
347
                logprintf("   detail: %s\n", EXTRA_DUMP(extra));
 
348
#endif
 
349
 
 
350
        if (dump_on_failure) {
 
351
                fprintf(stderr,
 
352
                    " *** forcing core dump so failure can be debugged ***\n");
 
353
                *(char *)(NULL) = 0;
 
354
                exit(1);
 
355
        }
 
356
}
 
357
 
 
358
/* Inform user that we're skipping some checks. */
 
359
void
 
360
test_skipping(const char *fmt, ...)
 
361
{
 
362
        char buff[1024];
 
363
        va_list ap;
 
364
 
 
365
        va_start(ap, fmt);
 
366
        vsprintf(buff, fmt, ap);
 
367
        va_end(ap);
 
368
        /* failure_start() isn't quite right, but is awfully convenient. */
 
369
        failure_start(test_filename, test_line, "SKIPPING: %s", buff);
 
370
        --failures; /* Undo failures++ in failure_start() */
 
371
        /* Don't failure_finish() here. */
 
372
        /* Mark as skip, so doesn't count as failed test. */
 
373
        failed_lines[test_line].skip = 1;
 
374
        ++skips;
 
375
}
 
376
 
 
377
/*
 
378
 *
 
379
 * ASSERTIONS
 
380
 *
 
381
 */
 
382
 
 
383
/* Generic assert() just displays the failed condition. */
 
384
int
 
385
assertion_assert(const char *file, int line, int value,
 
386
    const char *condition, void *extra)
 
387
{
 
388
        assertion_count(file, line);
 
389
        if (!value) {
 
390
                failure_start(file, line, "Assertion failed: %s", condition);
 
391
                failure_finish(extra);
 
392
        }
 
393
        return (value);
 
394
}
 
395
 
 
396
/* chdir() and report any errors */
 
397
int
 
398
assertion_chdir(const char *file, int line, const char *pathname)
 
399
{
 
400
        assertion_count(file, line);
 
401
        if (chdir(pathname) == 0)
 
402
                return (1);
 
403
        failure_start(file, line, "chdir(\"%s\")", pathname);
 
404
        failure_finish(NULL);
 
405
        return (0);
 
406
 
 
407
}
 
408
 
 
409
/* Verify two integers are equal. */
 
410
int
 
411
assertion_equal_int(const char *file, int line,
 
412
    long long v1, const char *e1, long long v2, const char *e2, void *extra)
 
413
{
 
414
        assertion_count(file, line);
 
415
        if (v1 == v2)
 
416
                return (1);
 
417
        failure_start(file, line, "%s != %s", e1, e2);
 
418
        logprintf("      %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1);
 
419
        logprintf("      %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2);
 
420
        failure_finish(extra);
 
421
        return (0);
 
422
}
 
423
 
 
424
static void strdump(const char *e, const char *p)
 
425
{
 
426
        const char *q = p;
 
427
 
 
428
        logprintf("      %s = ", e);
 
429
        if (p == NULL) {
 
430
                logprintf("NULL");
 
431
                return;
 
432
        }
 
433
        logprintf("\"");
 
434
        while (*p != '\0') {
 
435
                unsigned int c = 0xff & *p++;
 
436
                switch (c) {
 
437
                case '\a': printf("\a"); break;
 
438
                case '\b': printf("\b"); break;
 
439
                case '\n': printf("\n"); break;
 
440
                case '\r': printf("\r"); break;
 
441
                default:
 
442
                        if (c >= 32 && c < 127)
 
443
                                logprintf("%c", c);
 
444
                        else
 
445
                                logprintf("\\x%02X", c);
 
446
                }
 
447
        }
 
448
        logprintf("\"");
 
449
        logprintf(" (length %d)\n", q == NULL ? -1 : (int)strlen(q));
 
450
}
 
451
 
 
452
/* Verify two strings are equal, dump them if not. */
 
453
int
 
454
assertion_equal_string(const char *file, int line,
 
455
    const char *v1, const char *e1,
 
456
    const char *v2, const char *e2,
 
457
    void *extra)
 
458
{
 
459
        assertion_count(file, line);
 
460
        if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0))
 
461
                return (1);
 
462
        failure_start(file, line, "%s != %s", e1, e2);
 
463
        strdump(e1, v1);
 
464
        strdump(e2, v2);
 
465
        failure_finish(extra);
 
466
        return (0);
 
467
}
 
468
 
 
469
static void
 
470
wcsdump(const char *e, const wchar_t *w)
 
471
{
 
472
        logprintf("      %s = ", e);
 
473
        if (w == NULL) {
 
474
                logprintf("(null)");
 
475
                return;
 
476
        }
 
477
        logprintf("\"");
 
478
        while (*w != L'\0') {
 
479
                unsigned int c = *w++;
 
480
                if (c >= 32 && c < 127)
 
481
                        logprintf("%c", c);
 
482
                else if (c < 256)
 
483
                        logprintf("\\x%02X", c);
 
484
                else if (c < 0x10000)
 
485
                        logprintf("\\u%04X", c);
 
486
                else
 
487
                        logprintf("\\U%08X", c);
 
488
        }
 
489
        logprintf("\"\n");
 
490
}
 
491
 
 
492
#ifndef HAVE_WCSCMP
 
493
static int
 
494
wcscmp(const wchar_t *s1, const wchar_t *s2)
 
495
{
 
496
 
 
497
        while (*s1 == *s2++) {
 
498
                if (*s1++ == L'\0')
 
499
                        return 0;
 
500
        }
 
501
        if (*s1 > *--s2)
 
502
                return 1;
 
503
        else
 
504
                return -1;
 
505
}
 
506
#endif
 
507
 
 
508
/* Verify that two wide strings are equal, dump them if not. */
 
509
int
 
510
assertion_equal_wstring(const char *file, int line,
 
511
    const wchar_t *v1, const char *e1,
 
512
    const wchar_t *v2, const char *e2,
 
513
    void *extra)
 
514
{
 
515
        assertion_count(file, line);
 
516
        if (v1 == v2 || wcscmp(v1, v2) == 0)
 
517
                return (1);
 
518
        failure_start(file, line, "%s != %s", e1, e2);
 
519
        wcsdump(e1, v1);
 
520
        wcsdump(e2, v2);
 
521
        failure_finish(extra);
 
522
        return (0);
 
523
}
 
524
 
 
525
/*
 
526
 * Pretty standard hexdump routine.  As a bonus, if ref != NULL, then
 
527
 * any bytes in p that differ from ref will be highlighted with '_'
 
528
 * before and after the hex value.
 
529
 */
 
530
static void
 
531
hexdump(const char *p, const char *ref, size_t l, size_t offset)
 
532
{
 
533
        size_t i, j;
 
534
        char sep;
 
535
 
 
536
        if (p == NULL) {
 
537
                logprintf("(null)\n");
 
538
                return;
 
539
        }
 
540
        for(i=0; i < l; i+=16) {
 
541
                logprintf("%04x", (unsigned)(i + offset));
 
542
                sep = ' ';
 
543
                for (j = 0; j < 16 && i + j < l; j++) {
 
544
                        if (ref != NULL && p[i + j] != ref[i + j])
 
545
                                sep = '_';
 
546
                        logprintf("%c%02x", sep, 0xff & (int)p[i+j]);
 
547
                        if (ref != NULL && p[i + j] == ref[i + j])
 
548
                                sep = ' ';
 
549
                }
 
550
                for (; j < 16; j++) {
 
551
                        logprintf("%c  ", sep);
 
552
                        sep = ' ';
 
553
                }
 
554
                logprintf("%c", sep);
 
555
                for (j=0; j < 16 && i + j < l; j++) {
 
556
                        int c = p[i + j];
 
557
                        if (c >= ' ' && c <= 126)
 
558
                                logprintf("%c", c);
 
559
                        else
 
560
                                logprintf(".");
 
561
                }
 
562
                logprintf("\n");
 
563
        }
 
564
}
 
565
 
 
566
/* Verify that two blocks of memory are the same, display the first
 
567
 * block of differences if they're not. */
 
568
int
 
569
assertion_equal_mem(const char *file, int line,
 
570
    const void *_v1, const char *e1,
 
571
    const void *_v2, const char *e2,
 
572
    size_t l, const char *ld, void *extra)
 
573
{
 
574
        const char *v1 = (const char *)_v1;
 
575
        const char *v2 = (const char *)_v2;
 
576
        size_t offset;
 
577
 
 
578
        assertion_count(file, line);
 
579
        if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0))
 
580
                return (1);
 
581
 
 
582
        failure_start(file, line, "%s != %s", e1, e2);
 
583
        logprintf("      size %s = %d\n", ld, (int)l);
 
584
        /* Dump 48 bytes (3 lines) so that the first difference is
 
585
         * in the second line. */
 
586
        offset = 0;
 
587
        while (l > 64 && memcmp(v1, v2, 32) == 0) {
 
588
                /* Two lines agree, so step forward one line. */
 
589
                v1 += 16;
 
590
                v2 += 16;
 
591
                l -= 16;
 
592
                offset += 16;
 
593
        }
 
594
        logprintf("      Dump of %s\n", e1);
 
595
        hexdump(v1, v2, l < 64 ? l : 64, offset);
 
596
        logprintf("      Dump of %s\n", e2);
 
597
        hexdump(v2, v1, l < 64 ? l : 64, offset);
 
598
        logprintf("\n");
 
599
        failure_finish(extra);
 
600
        return (0);
 
601
}
 
602
 
 
603
/* Verify that the named file exists and is empty. */
 
604
int
 
605
assertion_empty_file(const char *f1fmt, ...)
 
606
{
 
607
        char buff[1024];
 
608
        char f1[1024];
 
609
        struct stat st;
 
610
        va_list ap;
 
611
        ssize_t s;
 
612
        FILE *f;
 
613
 
 
614
        assertion_count(test_filename, test_line);
 
615
        va_start(ap, f1fmt);
 
616
        vsprintf(f1, f1fmt, ap);
 
617
        va_end(ap);
 
618
 
 
619
        if (stat(f1, &st) != 0) {
 
620
                failure_start(test_filename, test_line, "Stat failed: %s", f1);
 
621
                failure_finish(NULL);
 
622
                return (0);
 
623
        }
 
624
        if (st.st_size == 0)
 
625
                return (1);
 
626
 
 
627
        failure_start(test_filename, test_line, "File should be empty: %s", f1);
 
628
        logprintf("    File size: %d\n", (int)st.st_size);
 
629
        logprintf("    Contents:\n");
 
630
        f = fopen(f1, "rb");
 
631
        if (f == NULL) {
 
632
                logprintf("    Unable to open %s\n", f1);
 
633
        } else {
 
634
                s = ((off_t)sizeof(buff) < st.st_size) ?
 
635
                    (ssize_t)sizeof(buff) : (ssize_t)st.st_size;
 
636
                s = fread(buff, 1, s, f);
 
637
                hexdump(buff, NULL, s, 0);
 
638
                fclose(f);
 
639
        }
 
640
        failure_finish(NULL);
 
641
        return (0);
 
642
}
 
643
 
 
644
/* Verify that the named file exists and is not empty. */
 
645
int
 
646
assertion_non_empty_file(const char *f1fmt, ...)
 
647
{
 
648
        char f1[1024];
 
649
        struct stat st;
 
650
        va_list ap;
 
651
 
 
652
        assertion_count(test_filename, test_line);
 
653
        va_start(ap, f1fmt);
 
654
        vsprintf(f1, f1fmt, ap);
 
655
        va_end(ap);
 
656
 
 
657
        if (stat(f1, &st) != 0) {
 
658
                failure_start(test_filename, test_line, "Stat failed: %s", f1);
 
659
                failure_finish(NULL);
 
660
                return (0);
 
661
        }
 
662
        if (st.st_size == 0) {
 
663
                failure_start(test_filename, test_line, "File empty: %s", f1);
 
664
                failure_finish(NULL);
 
665
                return (0);
 
666
        }
 
667
        return (1);
 
668
}
 
669
 
 
670
/* Verify that two files have the same contents. */
 
671
/* TODO: hexdump the first bytes that actually differ. */
 
672
int
 
673
assertion_equal_file(const char *fn1, const char *f2pattern, ...)
 
674
{
 
675
        char fn2[1024];
 
676
        va_list ap;
 
677
        char buff1[1024];
 
678
        char buff2[1024];
 
679
        FILE *f1, *f2;
 
680
        int n1, n2;
 
681
 
 
682
        assertion_count(test_filename, test_line);
 
683
        va_start(ap, f2pattern);
 
684
        vsprintf(fn2, f2pattern, ap);
 
685
        va_end(ap);
 
686
 
 
687
        f1 = fopen(fn1, "rb");
 
688
        f2 = fopen(fn2, "rb");
 
689
        for (;;) {
 
690
                n1 = fread(buff1, 1, sizeof(buff1), f1);
 
691
                n2 = fread(buff2, 1, sizeof(buff2), f2);
 
692
                if (n1 != n2)
 
693
                        break;
 
694
                if (n1 == 0 && n2 == 0) {
 
695
                        fclose(f1);
 
696
                        fclose(f2);
 
697
                        return (1);
 
698
                }
 
699
                if (memcmp(buff1, buff2, n1) != 0)
 
700
                        break;
 
701
        }
 
702
        fclose(f1);
 
703
        fclose(f2);
 
704
        failure_start(test_filename, test_line, "Files not identical");
 
705
        logprintf("  file1=\"%s\"\n", fn1);
 
706
        logprintf("  file2=\"%s\"\n", fn2);
 
707
        failure_finish(test_extra);
 
708
        return (0);
 
709
}
 
710
 
 
711
/* Verify that the named file does exist. */
 
712
int
 
713
assertion_file_exists(const char *fpattern, ...)
 
714
{
 
715
        char f[1024];
 
716
        va_list ap;
 
717
 
 
718
        assertion_count(test_filename, test_line);
 
719
        va_start(ap, fpattern);
 
720
        vsprintf(f, fpattern, ap);
 
721
        va_end(ap);
 
722
 
 
723
#if defined(_WIN32) && !defined(__CYGWIN__)
 
724
        if (!_access(f, 0))
 
725
                return (1);
 
726
#else
 
727
        if (!access(f, F_OK))
 
728
                return (1);
 
729
#endif
 
730
        failure_start(test_filename, test_line, "File should exist: %s", f);
 
731
        failure_finish(test_extra);
 
732
        return (0);
 
733
}
 
734
 
 
735
/* Verify that the named file doesn't exist. */
 
736
int
 
737
assertion_file_not_exists(const char *fpattern, ...)
 
738
{
 
739
        char f[1024];
 
740
        va_list ap;
 
741
 
 
742
        assertion_count(test_filename, test_line);
 
743
        va_start(ap, fpattern);
 
744
        vsprintf(f, fpattern, ap);
 
745
        va_end(ap);
 
746
 
 
747
#if defined(_WIN32) && !defined(__CYGWIN__)
 
748
        if (_access(f, 0))
 
749
                return (1);
 
750
#else
 
751
        if (access(f, F_OK))
 
752
                return (1);
 
753
#endif
 
754
        failure_start(test_filename, test_line, "File should not exist: %s", f);
 
755
        failure_finish(test_extra);
 
756
        return (0);
 
757
}
 
758
 
 
759
/* Compare the contents of a file to a block of memory. */
 
760
int
 
761
assertion_file_contents(const void *buff, int s, const char *fpattern, ...)
 
762
{
 
763
        char fn[1024];
 
764
        va_list ap;
 
765
        char *contents;
 
766
        FILE *f;
 
767
        int n;
 
768
 
 
769
        assertion_count(test_filename, test_line);
 
770
        va_start(ap, fpattern);
 
771
        vsprintf(fn, fpattern, ap);
 
772
        va_end(ap);
 
773
 
 
774
        f = fopen(fn, "rb");
 
775
        if (f == NULL) {
 
776
                failure_start(test_filename, test_line,
 
777
                    "File should exist: %s", fn);
 
778
                failure_finish(test_extra);
 
779
                return (0);
 
780
        }
 
781
        contents = malloc(s * 2);
 
782
        n = fread(contents, 1, s * 2, f);
 
783
        fclose(f);
 
784
        if (n == s && memcmp(buff, contents, s) == 0) {
 
785
                free(contents);
 
786
                return (1);
 
787
        }
 
788
        failure_start(test_filename, test_line, "File contents don't match");
 
789
        logprintf("  file=\"%s\"\n", fn);
 
790
        if (n > 0)
 
791
                hexdump(contents, buff, n > 512 ? 512 : n, 0);
 
792
        else {
 
793
                logprintf("  File empty, contents should be:\n");
 
794
                hexdump(buff, NULL, s > 512 ? 512 : n, 0);
 
795
        }
 
796
        failure_finish(test_extra);
 
797
        free(contents);
 
798
        return (0);
 
799
}
 
800
 
 
801
/* Check the contents of a text file, being tolerant of line endings. */
 
802
int
 
803
assertion_text_file_contents(const char *buff, const char *fn)
 
804
{
 
805
        char *contents;
 
806
        const char *btxt, *ftxt;
 
807
        FILE *f;
 
808
        int n, s;
 
809
 
 
810
        assertion_count(test_filename, test_line);
 
811
        f = fopen(fn, "r");
 
812
        if (f == NULL) {
 
813
                failure_start(test_filename, test_line,
 
814
                    "File doesn't exist: %s", fn);
 
815
                failure_finish(test_extra);
 
816
                return (0);
 
817
        }
 
818
        s = strlen(buff);
 
819
        contents = malloc(s * 2 + 128);
 
820
        n = fread(contents, 1, s * 2 + 128 - 1, f);
 
821
        if (n >= 0)
 
822
                contents[n] = '\0';
 
823
        fclose(f);
 
824
        /* Compare texts. */
 
825
        btxt = buff;
 
826
        ftxt = (const char *)contents;
 
827
        while (*btxt != '\0' && *ftxt != '\0') {
 
828
                if (*btxt == *ftxt) {
 
829
                        ++btxt;
 
830
                        ++ftxt;
 
831
                        continue;
 
832
                }
 
833
                if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') {
 
834
                        /* Pass over different new line characters. */
 
835
                        ++btxt;
 
836
                        ftxt += 2;
 
837
                        continue;
 
838
                }
 
839
                break;
 
840
        }
 
841
        if (*btxt == '\0' && *ftxt == '\0') {
 
842
                free(contents);
 
843
                return (1);
 
844
        }
 
845
        failure_start(test_filename, test_line, "Contents don't match");
 
846
        logprintf("  file=\"%s\"\n", fn);
 
847
        if (n > 0)
 
848
                hexdump(contents, buff, n, 0);
 
849
        else {
 
850
                logprintf("  File empty, contents should be:\n");
 
851
                hexdump(buff, NULL, s, 0);
 
852
        }
 
853
        failure_finish(test_extra);
 
854
        free(contents);
 
855
        return (0);
 
856
}
 
857
 
 
858
/* Test that two paths point to the same file. */
 
859
/* As a side-effect, asserts that both files exist. */
 
860
static int
 
861
is_hardlink(const char *file, int line,
 
862
    const char *path1, const char *path2)
 
863
{
 
864
#if defined(_WIN32) && !defined(__CYGWIN__)
 
865
        BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
 
866
        int r;
 
867
 
 
868
        assertion_count(file, line);
 
869
        r = my_GetFileInformationByName(path1, &bhfi1);
 
870
        if (r == 0) {
 
871
                failure_start(file, line, "File %s can't be inspected?", path1);
 
872
                failure_finish(NULL);
 
873
                return (0);
 
874
        }
 
875
        r = my_GetFileInformationByName(path2, &bhfi2);
 
876
        if (r == 0) {
 
877
                failure_start(file, line, "File %s can't be inspected?", path2);
 
878
                failure_finish(NULL);
 
879
                return (0);
 
880
        }
 
881
        return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
 
882
                && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
 
883
                && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow);
 
884
#else
 
885
        struct stat st1, st2;
 
886
        int r;
 
887
 
 
888
        assertion_count(file, line);
 
889
        r = lstat(path1, &st1);
 
890
        if (r != 0) {
 
891
                failure_start(file, line, "File should exist: %s", path1);
 
892
                failure_finish(NULL);
 
893
                return (0);
 
894
        }
 
895
        r = lstat(path2, &st2);
 
896
        if (r != 0) {
 
897
                failure_start(file, line, "File should exist: %s", path2);
 
898
                failure_finish(NULL);
 
899
                return (0);
 
900
        }
 
901
        return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
 
902
#endif
 
903
}
 
904
 
 
905
int
 
906
assertion_is_hardlink(const char *file, int line,
 
907
    const char *path1, const char *path2)
 
908
{
 
909
        if (is_hardlink(file, line, path1, path2))
 
910
                return (1);
 
911
        failure_start(file, line,
 
912
            "Files %s and %s are not hardlinked", path1, path2);
 
913
        failure_finish(NULL);
 
914
        return (0);
 
915
}
 
916
 
 
917
int
 
918
assertion_is_not_hardlink(const char *file, int line,
 
919
    const char *path1, const char *path2)
 
920
{
 
921
        if (!is_hardlink(file, line, path1, path2))
 
922
                return (1);
 
923
        failure_start(file, line,
 
924
            "Files %s and %s should not be hardlinked", path1, path2);
 
925
        failure_finish(NULL);
 
926
        return (0);
 
927
}
 
928
 
 
929
/* Verify a/b/mtime of 'pathname'. */
 
930
/* If 'recent', verify that it's within last 10 seconds. */
 
931
static int
 
932
assertion_file_time(const char *file, int line,
 
933
    const char *pathname, long t, long nsec, char type, int recent)
 
934
{
 
935
        long long filet, filet_nsec;
 
936
        int r;
 
937
 
 
938
#if defined(_WIN32) && !defined(__CYGWIN__)
 
939
#define EPOC_TIME       (116444736000000000ULL)
 
940
        FILETIME ftime, fbirthtime, fatime, fmtime;
 
941
        ULARGE_INTEGER wintm;
 
942
        HANDLE h;
 
943
        ftime.dwLowDateTime = 0;
 
944
        ftime.dwHighDateTime = 0;
 
945
 
 
946
        assertion_count(file, line);
 
947
        h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
 
948
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
949
        if (h == INVALID_HANDLE_VALUE) {
 
950
                failure_start(file, line, "Can't access %s\n", pathname);
 
951
                failure_finish(NULL);
 
952
                return (0);
 
953
        }
 
954
        r = GetFileTime(h, &fbirthtime, &fatime, &fmtime);
 
955
        switch (type) {
 
956
        case 'a': ftime = fatime; break;
 
957
        case 'b': ftime = fbirthtime; break;
 
958
        case 'm': ftime = fmtime; break;
 
959
        }
 
960
        CloseHandle(h);
 
961
        if (r == 0) {
 
962
                failure_start(file, line, "Can't GetFileTime %s\n", pathname);
 
963
                failure_finish(NULL);
 
964
                return (0);
 
965
        }
 
966
        wintm.LowPart = ftime.dwLowDateTime;
 
967
        wintm.HighPart = ftime.dwHighDateTime;
 
968
        filet = (wintm.QuadPart - EPOC_TIME) / 10000000;
 
969
        filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100;
 
970
        nsec = (nsec / 100) * 100; /* Round the request */
 
971
#else
 
972
        struct stat st;
 
973
 
 
974
        assertion_count(file, line);
 
975
        r = lstat(pathname, &st);
 
976
        if (r != 0) {
 
977
                failure_start(file, line, "Can't stat %s\n", pathname);
 
978
                failure_finish(NULL);
 
979
                return (0);
 
980
        }
 
981
        switch (type) {
 
982
        case 'a': filet = st.st_atime; break;
 
983
        case 'm': filet = st.st_mtime; break;
 
984
        case 'b': filet = 0; break;
 
985
        default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
 
986
                exit(1);
 
987
        }
 
988
#if defined(__FreeBSD__)
 
989
        switch (type) {
 
990
        case 'a': filet_nsec = st.st_atimespec.tv_nsec; break;
 
991
        case 'b': filet = st.st_birthtime;
 
992
                filet_nsec = st.st_birthtimespec.tv_nsec; break;
 
993
        case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break;
 
994
        default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
 
995
                exit(1);
 
996
        }
 
997
        /* FreeBSD generally only stores to microsecond res, so round. */
 
998
        filet_nsec = (filet_nsec / 1000) * 1000;
 
999
        nsec = (nsec / 1000) * 1000;
 
1000
#else
 
1001
        filet_nsec = nsec = 0;  /* Generic POSIX only has whole seconds. */
 
1002
        if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */
 
1003
#if defined(__HAIKU__)
 
1004
        if (type == 'a') return (1); /* Haiku doesn't have atime. */
 
1005
#endif
 
1006
#endif
 
1007
#endif
 
1008
        if (recent) {
 
1009
                /* Check that requested time is up-to-date. */
 
1010
                time_t now = time(NULL);
 
1011
                if (filet < now - 10 || filet > now + 1) {
 
1012
                        failure_start(file, line,
 
1013
                            "File %s has %ctime %ld, %ld seconds ago\n",
 
1014
                            pathname, type, filet, now - filet);
 
1015
                        failure_finish(NULL);
 
1016
                        return (0);
 
1017
                }
 
1018
        } else if (filet != t || filet_nsec != nsec) {
 
1019
                failure_start(file, line,
 
1020
                    "File %s has %ctime %ld.%09ld, expected %ld.%09ld",
 
1021
                    pathname, type, filet, filet_nsec, t, nsec);
 
1022
                failure_finish(NULL);
 
1023
                return (0);
 
1024
        }
 
1025
        return (1);
 
1026
}
 
1027
 
 
1028
/* Verify atime of 'pathname'. */
 
1029
int
 
1030
assertion_file_atime(const char *file, int line,
 
1031
    const char *pathname, long t, long nsec)
 
1032
{
 
1033
        return assertion_file_time(file, line, pathname, t, nsec, 'a', 0);
 
1034
}
 
1035
 
 
1036
/* Verify atime of 'pathname' is up-to-date. */
 
1037
int
 
1038
assertion_file_atime_recent(const char *file, int line, const char *pathname)
 
1039
{
 
1040
        return assertion_file_time(file, line, pathname, 0, 0, 'a', 1);
 
1041
}
 
1042
 
 
1043
/* Verify birthtime of 'pathname'. */
 
1044
int
 
1045
assertion_file_birthtime(const char *file, int line,
 
1046
    const char *pathname, long t, long nsec)
 
1047
{
 
1048
        return assertion_file_time(file, line, pathname, t, nsec, 'b', 0);
 
1049
}
 
1050
 
 
1051
/* Verify birthtime of 'pathname' is up-to-date. */
 
1052
int
 
1053
assertion_file_birthtime_recent(const char *file, int line,
 
1054
    const char *pathname)
 
1055
{
 
1056
        return assertion_file_time(file, line, pathname, 0, 0, 'b', 1);
 
1057
}
 
1058
 
 
1059
/* Verify mtime of 'pathname'. */
 
1060
int
 
1061
assertion_file_mtime(const char *file, int line,
 
1062
    const char *pathname, long t, long nsec)
 
1063
{
 
1064
        return assertion_file_time(file, line, pathname, t, nsec, 'm', 0);
 
1065
}
 
1066
 
 
1067
/* Verify mtime of 'pathname' is up-to-date. */
 
1068
int
 
1069
assertion_file_mtime_recent(const char *file, int line, const char *pathname)
 
1070
{
 
1071
        return assertion_file_time(file, line, pathname, 0, 0, 'm', 1);
 
1072
}
 
1073
 
 
1074
/* Verify number of links to 'pathname'. */
 
1075
int
 
1076
assertion_file_nlinks(const char *file, int line,
 
1077
    const char *pathname, int nlinks)
 
1078
{
 
1079
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1080
        BY_HANDLE_FILE_INFORMATION bhfi;
 
1081
        int r;
 
1082
 
 
1083
        assertion_count(file, line);
 
1084
        r = my_GetFileInformationByName(pathname, &bhfi);
 
1085
        if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks)
 
1086
                return (1);
 
1087
        failure_start(file, line, "File %s has %d links, expected %d",
 
1088
            pathname, bhfi.nNumberOfLinks, nlinks);
 
1089
        failure_finish(NULL);
 
1090
        return (0);
 
1091
#else
 
1092
        struct stat st;
 
1093
        int r;
 
1094
 
 
1095
        assertion_count(file, line);
 
1096
        r = lstat(pathname, &st);
 
1097
        if (r == 0 && st.st_nlink == nlinks)
 
1098
                        return (1);
 
1099
        failure_start(file, line, "File %s has %d links, expected %d",
 
1100
            pathname, st.st_nlink, nlinks);
 
1101
        failure_finish(NULL);
 
1102
        return (0);
 
1103
#endif
 
1104
}
 
1105
 
 
1106
/* Verify size of 'pathname'. */
 
1107
int
 
1108
assertion_file_size(const char *file, int line, const char *pathname, long size)
 
1109
{
 
1110
        int64_t filesize;
 
1111
        int r;
 
1112
 
 
1113
        assertion_count(file, line);
 
1114
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1115
        {
 
1116
                BY_HANDLE_FILE_INFORMATION bhfi;
 
1117
                r = !my_GetFileInformationByName(pathname, &bhfi);
 
1118
                filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow;
 
1119
        }
 
1120
#else
 
1121
        {
 
1122
                struct stat st;
 
1123
                r = lstat(pathname, &st);
 
1124
                filesize = st.st_size;
 
1125
        }
 
1126
#endif
 
1127
        if (r == 0 && filesize == size)
 
1128
                        return (1);
 
1129
        failure_start(file, line, "File %s has size %ld, expected %ld",
 
1130
            pathname, (long)filesize, (long)size);
 
1131
        failure_finish(NULL);
 
1132
        return (0);
 
1133
}
 
1134
 
 
1135
/* Assert that 'pathname' is a dir.  If mode >= 0, verify that too. */
 
1136
int
 
1137
assertion_is_dir(const char *file, int line, const char *pathname, int mode)
 
1138
{
 
1139
        struct stat st;
 
1140
        int r;
 
1141
 
 
1142
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1143
        (void)mode; /* UNUSED */
 
1144
#endif
 
1145
        assertion_count(file, line);
 
1146
        r = lstat(pathname, &st);
 
1147
        if (r != 0) {
 
1148
                failure_start(file, line, "Dir should exist: %s", pathname);
 
1149
                failure_finish(NULL);
 
1150
                return (0);
 
1151
        }
 
1152
        if (!S_ISDIR(st.st_mode)) {
 
1153
                failure_start(file, line, "%s is not a dir", pathname);
 
1154
                failure_finish(NULL);
 
1155
                return (0);
 
1156
        }
 
1157
#if !defined(_WIN32) || defined(__CYGWIN__)
 
1158
        /* Windows doesn't handle permissions the same way as POSIX,
 
1159
         * so just ignore the mode tests. */
 
1160
        /* TODO: Can we do better here? */
 
1161
        if (mode >= 0 && mode != (st.st_mode & 07777)) {
 
1162
                failure_start(file, line, "Dir %s has wrong mode", pathname);
 
1163
                logprintf("  Expected: 0%3o\n", mode);
 
1164
                logprintf("  Found: 0%3o\n", st.st_mode & 07777);
 
1165
                failure_finish(NULL);
 
1166
                return (0);
 
1167
        }
 
1168
#endif
 
1169
        return (1);
 
1170
}
 
1171
 
 
1172
/* Verify that 'pathname' is a regular file.  If 'mode' is >= 0,
 
1173
 * verify that too. */
 
1174
int
 
1175
assertion_is_reg(const char *file, int line, const char *pathname, int mode)
 
1176
{
 
1177
        struct stat st;
 
1178
        int r;
 
1179
 
 
1180
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1181
        (void)mode; /* UNUSED */
 
1182
#endif
 
1183
        assertion_count(file, line);
 
1184
        r = lstat(pathname, &st);
 
1185
        if (r != 0 || !S_ISREG(st.st_mode)) {
 
1186
                failure_start(file, line, "File should exist: %s", pathname);
 
1187
                failure_finish(NULL);
 
1188
                return (0);
 
1189
        }
 
1190
#if !defined(_WIN32) || defined(__CYGWIN__)
 
1191
        /* Windows doesn't handle permissions the same way as POSIX,
 
1192
         * so just ignore the mode tests. */
 
1193
        /* TODO: Can we do better here? */
 
1194
        if (mode >= 0 && mode != (st.st_mode & 07777)) {
 
1195
                failure_start(file, line, "File %s has wrong mode", pathname);
 
1196
                logprintf("  Expected: 0%3o\n", mode);
 
1197
                logprintf("  Found: 0%3o\n", st.st_mode & 07777);
 
1198
                failure_finish(NULL);
 
1199
                return (0);
 
1200
        }
 
1201
#endif
 
1202
        return (1);
 
1203
}
 
1204
 
 
1205
/* Check whether 'pathname' is a symbolic link.  If 'contents' is
 
1206
 * non-NULL, verify that the symlink has those contents. */
 
1207
static int
 
1208
is_symlink(const char *file, int line,
 
1209
    const char *pathname, const char *contents)
 
1210
{
 
1211
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1212
        (void)pathname; /* UNUSED */
 
1213
        (void)contents; /* UNUSED */
 
1214
        assertion_count(file, line);
 
1215
        /* Windows sort-of has real symlinks, but they're only usable
 
1216
         * by privileged users and are crippled even then, so there's
 
1217
         * really not much point in bothering with this. */
 
1218
        return (0);
 
1219
#else
 
1220
        char buff[300];
 
1221
        struct stat st;
 
1222
        ssize_t linklen;
 
1223
        int r;
 
1224
 
 
1225
        assertion_count(file, line);
 
1226
        r = lstat(pathname, &st);
 
1227
        if (r != 0) {
 
1228
                failure_start(file, line,
 
1229
                    "Symlink should exist: %s", pathname);
 
1230
                failure_finish(NULL);
 
1231
                return (0);
 
1232
        }
 
1233
        if (!S_ISLNK(st.st_mode))
 
1234
                return (0);
 
1235
        if (contents == NULL)
 
1236
                return (1);
 
1237
        linklen = readlink(pathname, buff, sizeof(buff));
 
1238
        if (linklen < 0) {
 
1239
                failure_start(file, line, "Can't read symlink %s", pathname);
 
1240
                failure_finish(NULL);
 
1241
                return (0);
 
1242
        }
 
1243
        buff[linklen] = '\0';
 
1244
        if (strcmp(buff, contents) != 0)
 
1245
                return (0);
 
1246
        return (1);
 
1247
#endif
 
1248
}
 
1249
 
 
1250
/* Assert that path is a symlink that (optionally) contains contents. */
 
1251
int
 
1252
assertion_is_symlink(const char *file, int line,
 
1253
    const char *path, const char *contents)
 
1254
{
 
1255
        if (is_symlink(file, line, path, contents))
 
1256
                return (1);
 
1257
        if (contents)
 
1258
                failure_start(file, line, "File %s is not a symlink to %s",
 
1259
                    path, contents);
 
1260
        else
 
1261
                failure_start(file, line, "File %s is not a symlink", path);
 
1262
        failure_finish(NULL);
 
1263
        return (0);
 
1264
}
 
1265
 
 
1266
 
 
1267
/* Create a directory and report any errors. */
 
1268
int
 
1269
assertion_make_dir(const char *file, int line, const char *dirname, int mode)
 
1270
{
 
1271
        assertion_count(file, line);
 
1272
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1273
        (void)mode; /* UNUSED */
 
1274
        if (0 == _mkdir(dirname))
 
1275
                return (1);
 
1276
#else
 
1277
        if (0 == mkdir(dirname, mode))
 
1278
                return (1);
 
1279
#endif
 
1280
        failure_start(file, line, "Could not create directory %s", dirname);
 
1281
        failure_finish(NULL);
 
1282
        return(0);
 
1283
}
 
1284
 
 
1285
/* Create a file with the specified contents and report any failures. */
 
1286
int
 
1287
assertion_make_file(const char *file, int line,
 
1288
    const char *path, int mode, const char *contents)
 
1289
{
 
1290
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1291
        /* TODO: Rework this to set file mode as well. */
 
1292
        FILE *f;
 
1293
        (void)mode; /* UNUSED */
 
1294
        assertion_count(file, line);
 
1295
        f = fopen(path, "wb");
 
1296
        if (f == NULL) {
 
1297
                failure_start(file, line, "Could not create file %s", path);
 
1298
                failure_finish(NULL);
 
1299
                return (0);
 
1300
        }
 
1301
        if (contents != NULL) {
 
1302
                if (strlen(contents)
 
1303
                    != fwrite(contents, 1, strlen(contents), f)) {
 
1304
                        fclose(f);
 
1305
                        failure_start(file, line,
 
1306
                            "Could not write file %s", path);
 
1307
                        failure_finish(NULL);
 
1308
                        return (0);
 
1309
                }
 
1310
        }
 
1311
        fclose(f);
 
1312
        return (1);
 
1313
#else
 
1314
        int fd;
 
1315
        assertion_count(file, line);
 
1316
        fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644);
 
1317
        if (fd < 0) {
 
1318
                failure_start(file, line, "Could not create %s", path);
 
1319
                failure_finish(NULL);
 
1320
                return (0);
 
1321
        }
 
1322
        if (contents != NULL) {
 
1323
                if ((ssize_t)strlen(contents)
 
1324
                    != write(fd, contents, strlen(contents))) {
 
1325
                        close(fd);
 
1326
                        failure_start(file, line, "Could not write to %s", path);
 
1327
                        failure_finish(NULL);
 
1328
                        return (0);
 
1329
                }
 
1330
        }
 
1331
        close(fd);
 
1332
        return (1);
 
1333
#endif
 
1334
}
 
1335
 
 
1336
/* Create a hardlink and report any failures. */
 
1337
int
 
1338
assertion_make_hardlink(const char *file, int line,
 
1339
    const char *newpath, const char *linkto)
 
1340
{
 
1341
        int succeeded;
 
1342
 
 
1343
        assertion_count(file, line);
 
1344
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1345
        succeeded = my_CreateHardLinkA(newpath, linkto);
 
1346
#elif HAVE_LINK
 
1347
        succeeded = !link(linkto, newpath);
 
1348
#else
 
1349
        succeeded = 0;
 
1350
#endif
 
1351
        if (succeeded)
 
1352
                return (1);
 
1353
        failure_start(file, line, "Could not create hardlink");
 
1354
        logprintf("   New link: %s\n", newpath);
 
1355
        logprintf("   Old name: %s\n", linkto);
 
1356
        failure_finish(NULL);
 
1357
        return(0);
 
1358
}
 
1359
 
 
1360
/* Create a symlink and report any failures. */
 
1361
int
 
1362
assertion_make_symlink(const char *file, int line,
 
1363
    const char *newpath, const char *linkto)
 
1364
{
 
1365
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1366
        int targetIsDir = 0;  /* TODO: Fix this */
 
1367
        assertion_count(file, line);
 
1368
        if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir))
 
1369
                return (1);
 
1370
#elif HAVE_SYMLINK
 
1371
        assertion_count(file, line);
 
1372
        if (0 == symlink(linkto, newpath))
 
1373
                return (1);
 
1374
#endif
 
1375
        failure_start(file, line, "Could not create symlink");
 
1376
        logprintf("   New link: %s\n", newpath);
 
1377
        logprintf("   Old name: %s\n", linkto);
 
1378
        failure_finish(NULL);
 
1379
        return(0);
 
1380
}
 
1381
 
 
1382
/* Set umask, report failures. */
 
1383
int
 
1384
assertion_umask(const char *file, int line, int mask)
 
1385
{
 
1386
        assertion_count(file, line);
 
1387
        (void)file; /* UNUSED */
 
1388
        (void)line; /* UNUSED */
 
1389
        umask(mask);
 
1390
        return (1);
 
1391
}
 
1392
 
 
1393
/*
 
1394
 *
 
1395
 *  UTILITIES for use by tests.
 
1396
 *
 
1397
 */
 
1398
 
 
1399
/*
 
1400
 * Check whether platform supports symlinks.  This is intended
 
1401
 * for tests to use in deciding whether to bother testing symlink
 
1402
 * support; if the platform doesn't support symlinks, there's no point
 
1403
 * in checking whether the program being tested can create them.
 
1404
 *
 
1405
 * Note that the first time this test is called, we actually go out to
 
1406
 * disk to create and verify a symlink.  This is necessary because
 
1407
 * symlink support is actually a property of a particular filesystem
 
1408
 * and can thus vary between directories on a single system.  After
 
1409
 * the first call, this returns the cached result from memory, so it's
 
1410
 * safe to call it as often as you wish.
 
1411
 */
 
1412
int
 
1413
canSymlink(void)
 
1414
{
 
1415
        /* Remember the test result */
 
1416
        static int value = 0, tested = 0;
 
1417
        if (tested)
 
1418
                return (value);
 
1419
 
 
1420
        ++tested;
 
1421
        assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, "a");
 
1422
        /* Note: Cygwin has its own symlink() emulation that does not
 
1423
         * use the Win32 CreateSymbolicLink() function. */
 
1424
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1425
        value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
 
1426
            && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
 
1427
#elif HAVE_SYMLINK
 
1428
        value = (0 == symlink("canSymlink.0", "canSymlink.1"))
 
1429
            && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
 
1430
#endif
 
1431
        return (value);
 
1432
}
 
1433
 
 
1434
/*
 
1435
 * Can this platform run the gzip program?
 
1436
 */
 
1437
/* Platform-dependent options for hiding the output of a subcommand. */
 
1438
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1439
static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
 
1440
#else
 
1441
static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
 
1442
#endif
 
1443
int
 
1444
canGzip(void)
 
1445
{
 
1446
        static int tested = 0, value = 0;
 
1447
        if (!tested) {
 
1448
                tested = 1;
 
1449
                if (systemf("gzip -V %s", redirectArgs) == 0)
 
1450
                        value = 1;
 
1451
        }
 
1452
        return (value);
 
1453
}
 
1454
 
 
1455
/*
 
1456
 * Can this platform run the gunzip program?
 
1457
 */
 
1458
int
 
1459
canGunzip(void)
 
1460
{
 
1461
        static int tested = 0, value = 0;
 
1462
        if (!tested) {
 
1463
                tested = 1;
 
1464
                if (systemf("gunzip -V %s", redirectArgs) == 0)
 
1465
                        value = 1;
 
1466
        }
 
1467
        return (value);
 
1468
}
 
1469
 
 
1470
/*
 
1471
 * Sleep as needed; useful for verifying disk timestamp changes by
 
1472
 * ensuring that the wall-clock time has actually changed before we
 
1473
 * go back to re-read something from disk.
 
1474
 */
 
1475
void
 
1476
sleepUntilAfter(time_t t)
 
1477
{
 
1478
        while (t >= time(NULL))
 
1479
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1480
                Sleep(500);
 
1481
#else
 
1482
                sleep(1);
 
1483
#endif
 
1484
}
 
1485
 
 
1486
/*
 
1487
 * Call standard system() call, but build up the command line using
 
1488
 * sprintf() conventions.
 
1489
 */
 
1490
int
 
1491
systemf(const char *fmt, ...)
 
1492
{
 
1493
        char buff[8192];
 
1494
        va_list ap;
 
1495
        int r;
 
1496
 
 
1497
        va_start(ap, fmt);
 
1498
        vsprintf(buff, fmt, ap);
 
1499
        if (verbosity > VERBOSITY_FULL)
 
1500
                logprintf("Cmd: %s\n", buff);
 
1501
        r = system(buff);
 
1502
        va_end(ap);
 
1503
        return (r);
 
1504
}
 
1505
 
 
1506
/*
 
1507
 * Slurp a file into memory for ease of comparison and testing.
 
1508
 * Returns size of file in 'sizep' if non-NULL, null-terminates
 
1509
 * data in memory for ease of use.
 
1510
 */
 
1511
char *
 
1512
slurpfile(size_t * sizep, const char *fmt, ...)
 
1513
{
 
1514
        char filename[8192];
 
1515
        struct stat st;
 
1516
        va_list ap;
 
1517
        char *p;
 
1518
        ssize_t bytes_read;
 
1519
        FILE *f;
 
1520
        int r;
 
1521
 
 
1522
        va_start(ap, fmt);
 
1523
        vsprintf(filename, fmt, ap);
 
1524
        va_end(ap);
 
1525
 
 
1526
        f = fopen(filename, "rb");
 
1527
        if (f == NULL) {
 
1528
                /* Note: No error; non-existent file is okay here. */
 
1529
                return (NULL);
 
1530
        }
 
1531
        r = fstat(fileno(f), &st);
 
1532
        if (r != 0) {
 
1533
                logprintf("Can't stat file %s\n", filename);
 
1534
                fclose(f);
 
1535
                return (NULL);
 
1536
        }
 
1537
        p = malloc((size_t)st.st_size + 1);
 
1538
        if (p == NULL) {
 
1539
                logprintf("Can't allocate %ld bytes of memory to read file %s\n",
 
1540
                    (long int)st.st_size, filename);
 
1541
                fclose(f);
 
1542
                return (NULL);
 
1543
        }
 
1544
        bytes_read = fread(p, 1, (size_t)st.st_size, f);
 
1545
        if (bytes_read < st.st_size) {
 
1546
                logprintf("Can't read file %s\n", filename);
 
1547
                fclose(f);
 
1548
                free(p);
 
1549
                return (NULL);
 
1550
        }
 
1551
        p[st.st_size] = '\0';
 
1552
        if (sizep != NULL)
 
1553
                *sizep = (size_t)st.st_size;
 
1554
        fclose(f);
 
1555
        return (p);
 
1556
}
 
1557
 
 
1558
/* Read a uuencoded file from the reference directory, decode, and
 
1559
 * write the result into the current directory. */
 
1560
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
 
1561
void
 
1562
extract_reference_file(const char *name)
 
1563
{
 
1564
        char buff[1024];
 
1565
        FILE *in, *out;
 
1566
 
 
1567
        sprintf(buff, "%s/%s.uu", refdir, name);
 
1568
        in = fopen(buff, "r");
 
1569
        failure("Couldn't open reference file %s", buff);
 
1570
        assert(in != NULL);
 
1571
        if (in == NULL)
 
1572
                return;
 
1573
        /* Read up to and including the 'begin' line. */
 
1574
        for (;;) {
 
1575
                if (fgets(buff, sizeof(buff), in) == NULL) {
 
1576
                        /* TODO: This is a failure. */
 
1577
                        return;
 
1578
                }
 
1579
                if (memcmp(buff, "begin ", 6) == 0)
 
1580
                        break;
 
1581
        }
 
1582
        /* Now, decode the rest and write it. */
 
1583
        /* Not a lot of error checking here; the input better be right. */
 
1584
        out = fopen(name, "wb");
 
1585
        while (fgets(buff, sizeof(buff), in) != NULL) {
 
1586
                char *p = buff;
 
1587
                int bytes;
 
1588
 
 
1589
                if (memcmp(buff, "end", 3) == 0)
 
1590
                        break;
 
1591
 
 
1592
                bytes = UUDECODE(*p++);
 
1593
                while (bytes > 0) {
 
1594
                        int n = 0;
 
1595
                        /* Write out 1-3 bytes from that. */
 
1596
                        if (bytes > 0) {
 
1597
                                n = UUDECODE(*p++) << 18;
 
1598
                                n |= UUDECODE(*p++) << 12;
 
1599
                                fputc(n >> 16, out);
 
1600
                                --bytes;
 
1601
                        }
 
1602
                        if (bytes > 0) {
 
1603
                                n |= UUDECODE(*p++) << 6;
 
1604
                                fputc((n >> 8) & 0xFF, out);
 
1605
                                --bytes;
 
1606
                        }
 
1607
                        if (bytes > 0) {
 
1608
                                n |= UUDECODE(*p++);
 
1609
                                fputc(n & 0xFF, out);
 
1610
                                --bytes;
 
1611
                        }
 
1612
                }
 
1613
        }
 
1614
        fclose(out);
 
1615
        fclose(in);
 
1616
}
 
1617
 
 
1618
/*
 
1619
 *
 
1620
 * TEST management
 
1621
 *
 
1622
 */
 
1623
 
 
1624
/*
 
1625
 * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has
 
1626
 * a line like
 
1627
 *      DEFINE_TEST(test_function)
 
1628
 * for each test.
 
1629
 */
 
1630
 
 
1631
/* Use "list.h" to declare all of the test functions. */
 
1632
#undef DEFINE_TEST
 
1633
#define DEFINE_TEST(name) void name(void);
 
1634
#include "list.h"
 
1635
 
 
1636
/* Use "list.h" to create a list of all tests (functions and names). */
 
1637
#undef DEFINE_TEST
 
1638
#define DEFINE_TEST(n) { n, #n, 0 },
 
1639
struct { void (*func)(void); const char *name; int failures; } tests[] = {
 
1640
        #include "list.h"
 
1641
};
 
1642
 
 
1643
/*
 
1644
 * Summarize repeated failures in the just-completed test.
 
1645
 */
 
1646
static void
 
1647
test_summarize(const char *filename, int failed)
 
1648
{
 
1649
        unsigned int i;
 
1650
 
 
1651
        switch (verbosity) {
 
1652
        case VERBOSITY_SUMMARY_ONLY:
 
1653
                printf(failed ? "E" : ".");
 
1654
                fflush(stdout);
 
1655
                break;
 
1656
        case VERBOSITY_PASSFAIL:
 
1657
                printf(failed ? "FAIL\n" : "ok\n");
 
1658
                break;
 
1659
        }
 
1660
 
 
1661
        log_console = (verbosity == VERBOSITY_LIGHT_REPORT);
 
1662
 
 
1663
        for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) {
 
1664
                if (failed_lines[i].count > 1 && !failed_lines[i].skip)
 
1665
                        logprintf("%s:%d: Summary: Failed %d times\n",
 
1666
                            filename, i, failed_lines[i].count);
 
1667
        }
 
1668
        /* Clear the failure history for the next file. */
 
1669
        memset(failed_lines, 0, sizeof(failed_lines));
 
1670
}
 
1671
 
 
1672
/*
 
1673
 * Actually run a single test, with appropriate setup and cleanup.
 
1674
 */
 
1675
static int
 
1676
test_run(int i, const char *tmpdir)
 
1677
{
 
1678
        char logfilename[64];
 
1679
        int failures_before = failures;
 
1680
        int oldumask;
 
1681
 
 
1682
        switch (verbosity) {
 
1683
        case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */
 
1684
                break;
 
1685
        case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */
 
1686
                printf("%3d: %-50s", i, tests[i].name);
 
1687
                fflush(stdout);
 
1688
                break;
 
1689
        default: /* Title of test, details will follow */
 
1690
                printf("%3d: %s\n", i, tests[i].name);
 
1691
        }
 
1692
 
 
1693
        /* Chdir to the top-level work directory. */
 
1694
        if (!assertChdir(tmpdir)) {
 
1695
                fprintf(stderr,
 
1696
                    "ERROR: Can't chdir to top work dir %s\n", tmpdir);
 
1697
                exit(1);
 
1698
        }
 
1699
        /* Create a log file for this test. */
 
1700
        sprintf(logfilename, "%s.log", tests[i].name);
 
1701
        logfile = fopen(logfilename, "w");
 
1702
        fprintf(logfile, "%s\n\n", tests[i].name);
 
1703
        /* Chdir() to a work dir for this specific test. */
 
1704
        if (!assertMakeDir(tests[i].name, 0755)
 
1705
            || !assertChdir(tests[i].name)) {
 
1706
                fprintf(stderr,
 
1707
                    "ERROR: Can't chdir to work dir %s/%s\n",
 
1708
                    tmpdir, tests[i].name);
 
1709
                exit(1);
 
1710
        }
 
1711
        /* Explicitly reset the locale before each test. */
 
1712
        setlocale(LC_ALL, "C");
 
1713
        /* Record the umask before we run the test. */
 
1714
        umask(oldumask = umask(0));
 
1715
        /*
 
1716
         * Run the actual test.
 
1717
         */
 
1718
        (*tests[i].func)();
 
1719
        /*
 
1720
         * Clean up and report afterwards.
 
1721
         */
 
1722
        /* Restore umask */
 
1723
        umask(oldumask);
 
1724
        /* Reset locale. */
 
1725
        setlocale(LC_ALL, "C");
 
1726
        /* Reset directory. */
 
1727
        if (!assertChdir(tmpdir)) {
 
1728
                fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n",
 
1729
                    tmpdir);
 
1730
                exit(1);
 
1731
        }
 
1732
        /* Report per-test summaries. */
 
1733
        tests[i].failures = failures - failures_before;
 
1734
        test_summarize(test_filename, tests[i].failures);
 
1735
        /* Close the per-test log file. */
 
1736
        fclose(logfile);
 
1737
        logfile = NULL;
 
1738
        /* If there were no failures, we can remove the work dir and logfile. */
 
1739
        if (tests[i].failures == 0) {
 
1740
                if (!keep_temp_files && assertChdir(tmpdir)) {
 
1741
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1742
                        /* Make sure not to leave empty directories.
 
1743
                         * Sometimes a processing of closing files used by tests
 
1744
                         * is not done, then rmdir will be failed and it will
 
1745
                         * leave a empty test directory. So we should wait a few
 
1746
                         * seconds and retry rmdir. */
 
1747
                        int r, t;
 
1748
                        for (t = 0; t < 10; t++) {
 
1749
                                if (t > 0)
 
1750
                                        Sleep(1000);
 
1751
                                r = systemf("rmdir /S /Q %s", tests[i].name);
 
1752
                                if (r == 0)
 
1753
                                        break;
 
1754
                        }
 
1755
                        systemf("del %s", logfilename);
 
1756
#else
 
1757
                        systemf("rm -rf %s", tests[i].name);
 
1758
                        systemf("rm %s", logfilename);
 
1759
#endif
 
1760
                }
 
1761
        }
 
1762
        /* Return appropriate status. */
 
1763
        return (tests[i].failures);
 
1764
}
 
1765
 
 
1766
/*
 
1767
 *
 
1768
 *
 
1769
 * MAIN and support routines.
 
1770
 *
 
1771
 *
 
1772
 */
 
1773
 
 
1774
static void
 
1775
usage(const char *program)
 
1776
{
 
1777
        static const int limit = sizeof(tests) / sizeof(tests[0]);
 
1778
        int i;
 
1779
 
 
1780
        printf("Usage: %s [options] <test> <test> ...\n", program);
 
1781
        printf("Default is to run all tests.\n");
 
1782
        printf("Otherwise, specify the numbers of the tests you wish to run.\n");
 
1783
        printf("Options:\n");
 
1784
        printf("  -d  Dump core after any failure, for debugging.\n");
 
1785
        printf("  -k  Keep all temp files.\n");
 
1786
        printf("      Default: temp files for successful tests deleted.\n");
 
1787
#ifdef PROGRAM
 
1788
        printf("  -p <path>  Path to executable to be tested.\n");
 
1789
        printf("      Default: path taken from " ENVBASE " environment variable.\n");
 
1790
#endif
 
1791
        printf("  -q  Quiet.\n");
 
1792
        printf("  -r <dir>   Path to dir containing reference files.\n");
 
1793
        printf("      Default: Current directory.\n");
 
1794
        printf("  -v  Verbose.\n");
 
1795
        printf("Available tests:\n");
 
1796
        for (i = 0; i < limit; i++)
 
1797
                printf("  %d: %s\n", i, tests[i].name);
 
1798
        exit(1);
 
1799
}
 
1800
 
 
1801
static char *
 
1802
get_refdir(const char *d)
 
1803
{
 
1804
        char tried[512] = { '\0' };
 
1805
        char buff[128];
 
1806
        char *pwd, *p;
 
1807
 
 
1808
        /* If a dir was specified, try that */
 
1809
        if (d != NULL) {
 
1810
                pwd = NULL;
 
1811
                snprintf(buff, sizeof(buff), "%s", d);
 
1812
                p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
 
1813
                if (p != NULL) goto success;
 
1814
                strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
 
1815
                strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
 
1816
                goto failure;
 
1817
        }
 
1818
 
 
1819
        /* Get the current dir. */
 
1820
        pwd = getcwd(NULL, 0);
 
1821
        while (pwd[strlen(pwd) - 1] == '\n')
 
1822
                pwd[strlen(pwd) - 1] = '\0';
 
1823
 
 
1824
        /* Look for a known file. */
 
1825
        snprintf(buff, sizeof(buff), "%s", pwd);
 
1826
        p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
 
1827
        if (p != NULL) goto success;
 
1828
        strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
 
1829
        strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
 
1830
 
 
1831
        snprintf(buff, sizeof(buff), "%s/test", pwd);
 
1832
        p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
 
1833
        if (p != NULL) goto success;
 
1834
        strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
 
1835
        strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
 
1836
 
 
1837
#if defined(LIBRARY)
 
1838
        snprintf(buff, sizeof(buff), "%s/%s/test", pwd, LIBRARY);
 
1839
#else
 
1840
        snprintf(buff, sizeof(buff), "%s/%s/test", pwd, PROGRAM);
 
1841
#endif
 
1842
        p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
 
1843
        if (p != NULL) goto success;
 
1844
        strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
 
1845
        strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
 
1846
 
 
1847
        if (memcmp(pwd, "/usr/obj", 8) == 0) {
 
1848
                snprintf(buff, sizeof(buff), "%s", pwd + 8);
 
1849
                p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
 
1850
                if (p != NULL) goto success;
 
1851
                strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
 
1852
                strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
 
1853
 
 
1854
                snprintf(buff, sizeof(buff), "%s/test", pwd + 8);
 
1855
                p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
 
1856
                if (p != NULL) goto success;
 
1857
                strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
 
1858
                strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
 
1859
        }
 
1860
 
 
1861
failure:
 
1862
        printf("Unable to locate known reference file %s\n", KNOWNREF);
 
1863
        printf("  Checked following directories:\n%s\n", tried);
 
1864
#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
 
1865
        DebugBreak();
 
1866
#endif
 
1867
        exit(1);
 
1868
 
 
1869
success:
 
1870
        free(p);
 
1871
        free(pwd);
 
1872
        return strdup(buff);
 
1873
}
 
1874
 
 
1875
int
 
1876
main(int argc, char **argv)
 
1877
{
 
1878
        static const int limit = sizeof(tests) / sizeof(tests[0]);
 
1879
        int i, tests_run = 0, tests_failed = 0, option;
 
1880
        time_t now;
 
1881
        char *refdir_alloc = NULL;
 
1882
        const char *progname;
 
1883
        const char *tmp, *option_arg, *p;
 
1884
        char tmpdir[256];
 
1885
        char tmpdir_timestamp[256];
 
1886
 
 
1887
        (void)argc; /* UNUSED */
 
1888
 
 
1889
#if defined(HAVE__CrtSetReportMode)
 
1890
        /* To stop to run the default invalid parameter handler. */
 
1891
        _set_invalid_parameter_handler(invalid_parameter_handler);
 
1892
        /* Disable annoying assertion message box. */
 
1893
        _CrtSetReportMode(_CRT_ASSERT, 0);
 
1894
#endif
 
1895
 
 
1896
        /*
 
1897
         * Name of this program, used to build root of our temp directory
 
1898
         * tree.
 
1899
         */
 
1900
        progname = p = argv[0];
 
1901
        while (*p != '\0') {
 
1902
                /* Support \ or / dir separators for Windows compat. */
 
1903
                if (*p == '/' || *p == '\\')
 
1904
                        progname = p + 1;
 
1905
                ++p;
 
1906
        }
 
1907
 
 
1908
#ifdef PROGRAM
 
1909
        /* Get the target program from environment, if available. */
 
1910
        testprogfile = getenv(ENVBASE);
 
1911
#endif
 
1912
 
 
1913
        if (getenv("TMPDIR") != NULL)
 
1914
                tmp = getenv("TMPDIR");
 
1915
        else if (getenv("TMP") != NULL)
 
1916
                tmp = getenv("TMP");
 
1917
        else if (getenv("TEMP") != NULL)
 
1918
                tmp = getenv("TEMP");
 
1919
        else if (getenv("TEMPDIR") != NULL)
 
1920
                tmp = getenv("TEMPDIR");
 
1921
        else
 
1922
                tmp = "/tmp";
 
1923
 
 
1924
        /* Allow -d to be controlled through the environment. */
 
1925
        if (getenv(ENVBASE "_DEBUG") != NULL)
 
1926
                dump_on_failure = 1;
 
1927
 
 
1928
        /* Get the directory holding test files from environment. */
 
1929
        refdir = getenv(ENVBASE "_TEST_FILES");
 
1930
 
 
1931
        /*
 
1932
         * Parse options, without using getopt(), which isn't available
 
1933
         * on all platforms.
 
1934
         */
 
1935
        ++argv; /* Skip program name */
 
1936
        while (*argv != NULL) {
 
1937
                if (**argv != '-')
 
1938
                        break;
 
1939
                p = *argv++;
 
1940
                ++p; /* Skip '-' */
 
1941
                while (*p != '\0') {
 
1942
                        option = *p++;
 
1943
                        option_arg = NULL;
 
1944
                        /* If 'opt' takes an argument, parse that. */
 
1945
                        if (option == 'p' || option == 'r') {
 
1946
                                if (*p != '\0')
 
1947
                                        option_arg = p;
 
1948
                                else if (*argv == NULL) {
 
1949
                                        fprintf(stderr,
 
1950
                                            "Option -%c requires argument.\n",
 
1951
                                            option);
 
1952
                                        usage(progname);
 
1953
                                } else
 
1954
                                        option_arg = *argv++;
 
1955
                                p = ""; /* End of this option word. */
 
1956
                        }
 
1957
 
 
1958
                        /* Now, handle the option. */
 
1959
                        switch (option) {
 
1960
                        case 'd':
 
1961
                                dump_on_failure = 1;
 
1962
                                break;
 
1963
                        case 'k':
 
1964
                                keep_temp_files = 1;
 
1965
                                break;
 
1966
                        case 'p':
 
1967
#ifdef PROGRAM
 
1968
                                testprogfile = option_arg;
 
1969
#else
 
1970
                                usage(progname);
 
1971
#endif
 
1972
                                break;
 
1973
                        case 'q':
 
1974
                                verbosity--;
 
1975
                                break;
 
1976
                        case 'r':
 
1977
                                refdir = option_arg;
 
1978
                                break;
 
1979
                        case 'v':
 
1980
                                verbosity++;
 
1981
                                break;
 
1982
                        default:
 
1983
                                usage(progname);
 
1984
                        }
 
1985
                }
 
1986
        }
 
1987
 
 
1988
        /*
 
1989
         * Sanity-check that our options make sense.
 
1990
         */
 
1991
#ifdef PROGRAM
 
1992
        if (testprogfile == NULL)
 
1993
                usage(progname);
 
1994
        {
 
1995
                char *testprg;
 
1996
#if defined(_WIN32) && !defined(__CYGWIN__)
 
1997
                /* Command.com sometimes rejects '/' separators. */
 
1998
                testprg = strdup(testprogfile);
 
1999
                for (i = 0; testprg[i] != '\0'; i++) {
 
2000
                        if (testprg[i] == '/')
 
2001
                                testprg[i] = '\\';
 
2002
                }
 
2003
                testprogfile = testprg;
 
2004
#endif
 
2005
                /* Quote the name that gets put into shell command lines. */
 
2006
                testprg = malloc(strlen(testprogfile) + 3);
 
2007
                strcpy(testprg, "\"");
 
2008
                strcat(testprg, testprogfile);
 
2009
                strcat(testprg, "\"");
 
2010
                testprog = testprg;
 
2011
        }
 
2012
#endif
 
2013
 
 
2014
        /*
 
2015
         * Create a temp directory for the following tests.
 
2016
         * Include the time the tests started as part of the name,
 
2017
         * to make it easier to track the results of multiple tests.
 
2018
         */
 
2019
        now = time(NULL);
 
2020
        for (i = 0; ; i++) {
 
2021
                strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp),
 
2022
                    "%Y-%m-%dT%H.%M.%S",
 
2023
                    localtime(&now));
 
2024
                sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname,
 
2025
                    tmpdir_timestamp, i);
 
2026
                if (assertMakeDir(tmpdir,0755))
 
2027
                        break;
 
2028
                if (i >= 999) {
 
2029
                        fprintf(stderr,
 
2030
                            "ERROR: Unable to create temp directory %s\n",
 
2031
                            tmpdir);
 
2032
                        exit(1);
 
2033
                }
 
2034
        }
 
2035
 
 
2036
        /*
 
2037
         * If the user didn't specify a directory for locating
 
2038
         * reference files, try to find the reference files in
 
2039
         * the "usual places."
 
2040
         */
 
2041
        refdir = refdir_alloc = get_refdir(refdir);
 
2042
 
 
2043
        /*
 
2044
         * Banner with basic information.
 
2045
         */
 
2046
        printf("\n");
 
2047
        printf("If tests fail or crash, details will be in:\n");
 
2048
        printf("   %s\n", tmpdir);
 
2049
        printf("\n");
 
2050
        if (verbosity > VERBOSITY_SUMMARY_ONLY) {
 
2051
                printf("Reference files will be read from: %s\n", refdir);
 
2052
#ifdef PROGRAM
 
2053
                printf("Running tests on: %s\n", testprog);
 
2054
#endif
 
2055
                printf("Exercising: ");
 
2056
                fflush(stdout);
 
2057
                printf("%s\n", EXTRA_VERSION);
 
2058
        } else {
 
2059
                printf("Running ");
 
2060
                fflush(stdout);
 
2061
        }
 
2062
 
 
2063
        /*
 
2064
         * Run some or all of the individual tests.
 
2065
         */
 
2066
        if (*argv == NULL) {
 
2067
                /* Default: Run all tests. */
 
2068
                for (i = 0; i < limit; i++) {
 
2069
                        if (test_run(i, tmpdir))
 
2070
                                tests_failed++;
 
2071
                        tests_run++;
 
2072
                }
 
2073
        } else {
 
2074
                while (*(argv) != NULL) {
 
2075
                        if (**argv >= '0' && **argv <= '9') {
 
2076
                                i = atoi(*argv);
 
2077
                                if (i < 0 || i >= limit) {
 
2078
                                        printf("*** INVALID Test %s\n", *argv);
 
2079
                                        free(refdir_alloc);
 
2080
                                        usage(progname);
 
2081
                                        /* usage() never returns */
 
2082
                                }
 
2083
                        } else {
 
2084
                                for (i = 0; i < limit; ++i) {
 
2085
                                        if (strcmp(*argv, tests[i].name) == 0)
 
2086
                                                break;
 
2087
                                }
 
2088
                                if (i >= limit) {
 
2089
                                        printf("*** INVALID Test ``%s''\n",
 
2090
                                               *argv);
 
2091
                                        free(refdir_alloc);
 
2092
                                        usage(progname);
 
2093
                                        /* usage() never returns */
 
2094
                                }
 
2095
                        }
 
2096
                        if (test_run(i, tmpdir))
 
2097
                                tests_failed++;
 
2098
                        tests_run++;
 
2099
                        argv++;
 
2100
                }
 
2101
        }
 
2102
 
 
2103
        /*
 
2104
         * Report summary statistics.
 
2105
         */
 
2106
        if (verbosity > VERBOSITY_SUMMARY_ONLY) {
 
2107
                printf("\n");
 
2108
                printf("Totals:\n");
 
2109
                printf("  Tests run:         %8d\n", tests_run);
 
2110
                printf("  Tests failed:      %8d\n", tests_failed);
 
2111
                printf("  Assertions checked:%8d\n", assertions);
 
2112
                printf("  Assertions failed: %8d\n", failures);
 
2113
                printf("  Skips reported:    %8d\n", skips);
 
2114
        }
 
2115
        if (failures) {
 
2116
                printf("\n");
 
2117
                printf("Failing tests:\n");
 
2118
                for (i = 0; i < limit; ++i) {
 
2119
                        if (tests[i].failures)
 
2120
                                printf("  %d: %s (%d failures)\n", i,
 
2121
                                    tests[i].name, tests[i].failures);
 
2122
                }
 
2123
                printf("\n");
 
2124
                printf("Details for failing tests: %s\n", tmpdir);
 
2125
                printf("\n");
 
2126
        } else {
 
2127
                if (verbosity == VERBOSITY_SUMMARY_ONLY)
 
2128
                        printf("\n");
 
2129
                printf("%d tests passed, no failures\n", tests_run);
 
2130
        }
 
2131
 
 
2132
        free(refdir_alloc);
 
2133
 
 
2134
        /* If the final tmpdir is empty, we can remove it. */
 
2135
        /* This should be the usual case when all tests succeed. */
 
2136
        assertChdir("..");
 
2137
        rmdir(tmpdir);
 
2138
 
 
2139
        return (tests_failed ? 1 : 0);
 
2140
}