]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libarchive/test/main.c
Add some options to libarchive_test:
[FreeBSD/FreeBSD.git] / lib / libarchive / test / main.c
1 /*
2  * Copyright (c) 2003-2007 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 /*
27  * Various utility routines useful for test programs.
28  * Each test program is linked against this file.
29  */
30 #include <errno.h>
31 #include <stdarg.h>
32 #include <time.h>
33
34 #include "test.h"
35 __FBSDID("$FreeBSD$");
36
37 /* Default is to crash and try to force a core dump on failure. */
38 static int dump_on_failure = 1;
39 /* Default is to print some basic information about each test. */
40 static int quiet_flag = 0;
41 /* Cumulative count of failures. */
42 static int failures = 0;
43
44 /*
45  * My own implementation of the standard assert() macro emits the
46  * message in the same format as GCC (file:line: message).
47  * It also includes some additional useful information.
48  * This makes it a lot easier to skim through test failures in
49  * Emacs.  ;-)
50  *
51  * It also supports a few special features specifically to simplify
52  * libarchive test harnesses:
53  *    failure(fmt, args) -- Stores a text string that gets
54  *          printed if the following assertion fails, good for
55  *          explaining subtle tests.
56  *    assertA(a, cond) -- If the test fails, also prints out any error
57  *          message stored in archive object 'a'.
58  */
59 static char msg[4096];
60
61
62 /* Common handling of failed tests. */
63 static void
64 test_failed(struct archive *a)
65 {
66         failures ++;
67
68         if (msg[0] != '\0') {
69                 fprintf(stderr, "   Description: %s\n", msg);
70                 msg[0] = '\0';
71         }
72         if (a != NULL) {
73                 fprintf(stderr, "   archive error: %s\n", archive_error_string(a));
74         }
75
76         if (dump_on_failure) {
77                 fprintf(stderr, " *** forcing core dump so failure can be debugged ***\n");
78                 *(char *)(NULL) = 0;
79                 exit(1);
80         }
81 }
82
83 /* Set up a message to display only after a test fails. */
84 void
85 failure(const char *fmt, ...)
86 {
87         va_list ap;
88         va_start(ap, fmt);
89         vsprintf(msg, fmt, ap);
90         va_end(ap);
91 }
92
93 /* Generic assert() just displays the failed condition. */
94 void
95 test_assert(const char *file, int line, int value, const char *condition, struct archive *a)
96 {
97         if (value) {
98                 msg[0] = '\0';
99                 return;
100         }
101         fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
102         fprintf(stderr, "   Condition: %s\n", condition);
103         test_failed(a);
104 }
105
106 /* assertEqualInt() displays the values of the two integers. */
107 void
108 test_assert_equal_int(const char *file, int line,
109     int v1, const char *e1, int v2, const char *e2, struct archive *a)
110 {
111         if (v1 == v2) {
112                 msg[0] = '\0';
113                 return;
114         }
115         fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n",
116             file, line);
117         fprintf(stderr, "      %s=%d\n", e1, v1);
118         fprintf(stderr, "      %s=%d\n", e2, v2);
119         test_failed(a);
120 }
121
122 /* assertEqualString() displays the values of the two strings. */
123 void
124 test_assert_equal_string(const char *file, int line,
125     const char *v1, const char *e1,
126     const char *v2, const char *e2,
127     struct archive *a)
128 {
129         if (v1 == NULL || v2 == NULL) {
130                 if (v1 == v2) {
131                         msg[0] = '\0';
132                         return;
133                 }
134         } else if (strcmp(v1, v2) == 0) {
135                 msg[0] = '\0';
136                 return;
137         }
138         fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n",
139             file, line);
140         fprintf(stderr, "      %s = \"%s\"\n", e1, v1);
141         fprintf(stderr, "      %s = \"%s\"\n", e2, v2);
142         test_failed(a);
143 }
144
145 /* assertEqualWString() displays the values of the two strings. */
146 void
147 test_assert_equal_wstring(const char *file, int line,
148     const wchar_t *v1, const char *e1,
149     const wchar_t *v2, const char *e2,
150     struct archive *a)
151 {
152         if (wcscmp(v1, v2) == 0) {
153                 msg[0] = '\0';
154                 return;
155         }
156         fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n",
157             file, line);
158         fwprintf(stderr, L"      %s = \"%ls\"\n", e1, v1);
159         fwprintf(stderr, L"      %s = \"%ls\"\n", e2, v2);
160         test_failed(a);
161 }
162
163 /*
164  * "list.h" is automatically generated; it just has a lot of lines like:
165  *      DEFINE_TEST(function_name)
166  * The common "test.h" includes it to declare all of the test functions.
167  * We reuse it here to define a list of all tests to run.
168  */
169 #undef DEFINE_TEST
170 #define DEFINE_TEST(n) { n, #n },
171 struct { void (*func)(void); const char *name; } tests[] = {
172         #include "list.h"
173 };
174
175 static int test_run(int i, const char *tmpdir)
176 {
177         int failures_before = failures;
178
179         if (!quiet_flag)
180                 printf("%d: %s\n", i, tests[i].name);
181         /*
182          * Always explicitly chdir() in case the last test moved us to
183          * a strange place.
184          */
185         if (chdir(tmpdir)) {
186                 fprintf(stderr,
187                     "ERROR: Couldn't chdir to temp dir %s\n",
188                     tmpdir);
189                 exit(1);
190         }
191         /* Create a temp directory for this specific test. */
192         if (mkdir(tests[i].name, 0755)) {
193                 fprintf(stderr,
194                     "ERROR: Couldn't create temp dir ``%s''\n",
195                     tests[i].name);
196                 exit(1);
197         }
198         if (chdir(tests[i].name)) {
199                 fprintf(stderr,
200                     "ERROR: Couldn't chdir to temp dir ``%s''\n",
201                     tests[i].name);
202                 exit(1);
203         }
204         (*tests[i].func)();
205         return (failures - failures_before);
206 }
207
208 static void usage(void)
209 {
210         static const int limit = sizeof(tests) / sizeof(tests[0]);
211         int i;
212
213         printf("Usage: libarchive_test [options] <test> <test> ...\n");
214         printf("Default is to run all tests.\n");
215         printf("Otherwise, specify the numbers of the tests you wish to run.\n");
216         printf("Options:\n");
217         printf("  -k  Keep running after failures.\n");
218         printf("      Default: Core dump after any failure.\n");
219         printf("  -q  Quiet.\n");
220         printf("Available tests:\n");
221         for (i = 0; i < limit; i++)
222                 printf("  %d: %s\n", i, tests[i].name);
223         exit(1);
224 }
225
226 int main(int argc, char **argv)
227 {
228         static const int limit = sizeof(tests) / sizeof(tests[0]);
229         int i, tests_run = 0, tests_succeeded = 0, opt;
230         time_t now;
231         char tmpdir[256];
232
233         while ((opt = getopt(argc, argv, "kq")) != -1) {
234                 switch (opt) {
235                 case 'k':
236                         dump_on_failure = 0;
237                         break;
238                 case 'q':
239                         quiet_flag = 1;
240                         break;
241                 case '?':
242                 default:
243                         usage();
244                 }
245         }
246         argc -= optind;
247         argv += optind;
248
249         /*
250          * Create a temp directory for the following tests.
251          * Include the time the tests started as part of the name,
252          * to make it easier to track the results of multiple tests.
253          */
254         now = time(NULL);
255         for (i = 0; i < 1000; i++) {
256                 strftime(tmpdir, sizeof(tmpdir),
257                     "/tmp/libarchive_test.%Y-%m-%dT%H.%M.%S",
258                     localtime(&now));
259                 sprintf(tmpdir + strlen(tmpdir), "-%03d", i);
260                 if (mkdir(tmpdir,0755) == 0)
261                         break;
262                 if (errno == EEXIST)
263                         continue;
264                 fprintf(stderr, "ERROR: Unable to create temp directory %s\n",
265                     tmpdir);
266                 exit(1);
267         }
268
269         printf("Running libarchive tests in: %s\n", tmpdir);
270
271         if (argc == 0) {
272                 /* Default: Run all tests. */
273                 for (i = 0; i < limit; i++) {
274                         if (test_run(i, tmpdir) == 0)
275                                 tests_succeeded++;
276                         tests_run++;
277                 }
278         } else {
279                 while (*(++argv) != NULL) {
280                         i = atoi(*argv);
281                         if (**argv < '0' || **argv > '9' || i < 0 || i >= limit) {
282                                 printf("*** INVALID Test %s\n", *argv);
283                                 usage();
284                         } else {
285                                 if (test_run(i, tmpdir) == 0)
286                                         tests_succeeded++;
287                                 tests_run++;
288                         }
289                 }
290         }
291
292         printf("%d of %d tests succeeded.\n", tests_succeeded, tests_run);
293         return (tests_succeeded == tests_run ? 0 : 1);
294 }