Bump to 1.14.1
[platform/upstream/augeas.git] / tests / cutest.c
1 /*
2  * This code is based on CuTest by Asim Jalis
3  * http://sourceforge.net/projects/cutest/
4  *
5  * The license for the original code is
6  * LICENSE
7  *
8  * Copyright (c) 2003 Asim Jalis
9  *
10  * This software is provided 'as-is', without any express or implied
11  * warranty. In no event will the authors be held liable for any damages
12  * arising from the use of this software.
13  *
14  * Permission is granted to anyone to use this software for any purpose,
15  * including commercial applications, and to alter it and redistribute it
16  * freely, subject to the following restrictions:
17  *
18  * 1. The origin of this software must not be misrepresented; you must not
19  * claim that you wrote the original software. If you use this software in
20  * a product, an acknowledgment in the product documentation would be
21  * appreciated but is not required.
22  *
23  * 2. Altered source versions must be plainly marked as such, and must not be
24  * misrepresented as being the original software.
25  *
26  * 3. This notice may not be removed or altered from any source distribution.
27  */
28
29 #include <config.h>
30
31 #include <sys/wait.h>
32 #include <assert.h>
33 #include <setjmp.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <math.h>
38
39 #include "cutest.h"
40 #include "memory.h"
41
42 #define HUGE_STRING_LEN 8192
43 #define STRING_MAX      256
44
45 #define asprintf_or_die(strp, fmt, args ...)                            \
46     if (asprintf(strp, fmt, ## args) == -1) {                           \
47         fprintf(stderr, "Fatal error (probably out of memory)\n");      \
48         abort();                                                        \
49     }
50
51 void die_oom(void) {
52     printf("Ran out of memory. Send more\n");
53     exit(2);
54 }
55
56 /*-------------------------------------------------------------------------*
57  * CuTest
58  *-------------------------------------------------------------------------*/
59
60 void CuTestInit(CuTest* t, const char* name, TestFunction function) {
61     t->name = strdup(name);
62     t->failed = 0;
63     t->ran = 0;
64     t->message = NULL;
65     t->function = function;
66     t->jumpBuf = NULL;
67 }
68
69 CuTest* CuTestNew(const char* name, TestFunction function) {
70     CuTest* tc = NULL;
71     if (ALLOC(tc) < 0)
72         die_oom();
73     CuTestInit(tc, name, function);
74     return tc;
75 }
76
77 void CuTestRun(CuTest* tc, TestFunction setup, TestFunction teardown) {
78     jmp_buf buf;
79
80     if (getenv("CUTEST") && STRNEQ(getenv("CUTEST"), tc->name))
81         return;
82     tc->jumpBuf = &buf;
83     if (setjmp(buf) == 0) {
84         if (setup)
85             (setup)(tc);
86         tc->ran = 1;
87         (tc->function)(tc);
88     }
89     if (teardown && setjmp(buf) == 0) {
90         (teardown)(tc);
91     }
92     tc->jumpBuf = 0;
93 }
94
95 static void CuFailInternal(CuTest* tc, const char* file, int line,
96                            const char *string) {
97     char *buf = NULL;
98
99     asprintf_or_die(&buf, "%s:%d: %s", file, line, string);
100
101     tc->failed = 1;
102     tc->message = buf;
103     if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
104 }
105
106 void CuFail_Line(CuTest* tc, const char* file, int line,
107                  const char* message2, const char* message) {
108     char *string = NULL;
109
110     if (message2 != NULL) {
111         asprintf_or_die(&string, "%s:%s", message2, message);
112     } else {
113         string = strdup(message);
114     }
115     CuFailInternal(tc, file, line, string);
116 }
117
118 void CuAssert_Line(CuTest* tc, const char* file, int line,
119                    const char* message, int condition) {
120     if (condition) return;
121     CuFail_Line(tc, file, line, NULL, message);
122 }
123
124 void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line,
125                                const char* message,
126                                const char* expected, const char* actual) {
127     char *string = NULL;
128
129     if ((expected == NULL && actual == NULL) ||
130         (expected != NULL && actual != NULL &&
131          strcmp(expected, actual) == 0))
132         {
133             return;
134         }
135
136     if (message != NULL) {
137         asprintf_or_die(&string, "%s: expected <%s> but was <%s>", message,
138                         expected, actual);
139     } else {
140         asprintf_or_die(&string, "expected <%s> but was <%s>", expected, actual);
141     }
142     CuFailInternal(tc, file, line, string);
143 }
144
145 void CuAssertStrNotEqual_LineMsg(CuTest* tc, const char* file, int line,
146                                  const char* message,
147                                  const char* expected, const char* actual) {
148     char *string = NULL;
149
150     if (expected != NULL && actual != NULL && strcmp(expected, actual) != 0)
151         return;
152
153     if (message != NULL) {
154         asprintf_or_die(&string, "%s: expected <%s> but was <%s>", message,
155                         expected, actual);
156     } else {
157         asprintf_or_die(&string, "expected <%s> but was <%s>", expected, actual);
158     }
159     CuFailInternal(tc, file, line, string);
160 }
161
162 void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line,
163                                const char* message,
164                                int expected, int actual) {
165     char buf[STRING_MAX];
166     if (expected == actual) return;
167     sprintf(buf, "expected <%d> but was <%d>", expected, actual);
168     CuFail_Line(tc, file, line, message, buf);
169 }
170
171 void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line,
172                                const char* message,
173                                double expected, double actual, double delta) {
174     char buf[STRING_MAX];
175     if (fabs(expected - actual) <= delta) return;
176     sprintf(buf, "expected <%lf> but was <%lf>", expected, actual);
177     CuFail_Line(tc, file, line, message, buf);
178 }
179
180 void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line,
181                                const char* message,
182                                const void* expected, const void* actual) {
183     char buf[STRING_MAX];
184     if (expected == actual) return;
185     sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
186     CuFail_Line(tc, file, line, message, buf);
187 }
188
189 void CuAssertPtrNotEqual_LineMsg(CuTest* tc, const char* file, int line,
190                                  const char* message,
191                                  const void* expected, const void* actual) {
192     char buf[STRING_MAX];
193     if (expected != actual) return;
194     sprintf(buf, "expected pointer <0x%p> to be different from <0x%p>",
195             expected, actual);
196     CuFail_Line(tc, file, line, message, buf);
197 }
198
199
200 /*-------------------------------------------------------------------------*
201  * CuSuite
202  *-------------------------------------------------------------------------*/
203
204 void CuSuiteInit(CuSuite* testSuite) {
205     testSuite->count = 0;
206     testSuite->failCount = 0;
207 }
208
209 CuSuite* CuSuiteNew(void) {
210     CuSuite* testSuite = NULL;
211     if (ALLOC(testSuite) < 0)
212         die_oom();
213     CuSuiteInit(testSuite);
214     return testSuite;
215 }
216
217 void CuSuiteSetup(CuSuite *testSuite,
218                   TestFunction setup, TestFunction teardown) {
219     testSuite->setup = setup;
220     testSuite->teardown = teardown;
221 }
222
223 void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) {
224     assert(testSuite->count < MAX_TEST_CASES);
225     testSuite->list[testSuite->count] = testCase;
226     testSuite->count++;
227 }
228
229 void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) {
230     int i;
231     for (i = 0 ; i < testSuite2->count ; ++i)
232         {
233             CuTest* testCase = testSuite2->list[i];
234             CuSuiteAdd(testSuite, testCase);
235         }
236 }
237
238 void CuSuiteRun(CuSuite* testSuite) {
239     int i;
240     for (i = 0 ; i < testSuite->count ; ++i)
241         {
242             CuTest* testCase = testSuite->list[i];
243             CuTestRun(testCase, testSuite->setup, testSuite->teardown);
244             if (testCase->failed) { testSuite->failCount += 1; }
245         }
246 }
247
248 static void string_append(char **s, const char *p) {
249     if (*s == NULL) {
250         *s = strdup(p);
251     } else {
252         int len = strlen(*s) + strlen(p) + 1;
253         *s = realloc(*s, len);
254         if (*s == NULL)
255             die_oom();
256         strcat(*s, p);
257     }
258 }
259
260 void CuSuiteSummary(CuSuite* testSuite, char **summary) {
261     int i;
262
263     for (i = 0 ; i < testSuite->count ; ++i)
264         {
265             CuTest* testCase = testSuite->list[i];
266             string_append(summary, testCase->failed ? "F" : ".");
267         }
268     string_append(summary, "\n\n");
269 }
270
271 void CuSuiteDetails(CuSuite* testSuite, char **details) {
272     int i;
273     int failCount = 0;
274     char *s = NULL;
275
276     if (testSuite->failCount == 0)
277         {
278             int passCount = testSuite->count - testSuite->failCount;
279             const char* testWord = passCount == 1 ? "test" : "tests";
280             asprintf_or_die(&s, "OK (%d %s)\n", passCount, testWord);
281             string_append(details, s);
282             free(s);
283         } else {
284         if (testSuite->failCount == 1)
285             string_append(details, "There was 1 failure:\n");
286         else {
287             asprintf_or_die(&s, "There were %d failures:\n",
288                             testSuite->failCount);
289             string_append(details, s);
290             free(s);
291         }
292         for (i = 0 ; i < testSuite->count ; ++i) {
293             CuTest* testCase = testSuite->list[i];
294             if (testCase->failed) {
295                 failCount++;
296                 asprintf_or_die(&s, "%d) %s:\n%s\n",
297                          failCount, testCase->name, testCase->message);
298                 string_append(details, s);
299                 free(s);
300             }
301         }
302         string_append(details, "\n!!!FAILURES!!!\n");
303
304         asprintf_or_die(&s, "Runs: %d ",   testSuite->count);
305         string_append(details, s);
306         free(s);
307
308         asprintf_or_die(&s, "Passes: %d ",
309                         testSuite->count - testSuite->failCount);
310         string_append(details, s);
311         free(s);
312
313         asprintf_or_die(&s, "Fails: %d\n",  testSuite->failCount);
314         string_append(details, s);
315         free(s);
316     }
317 }
318
319 void CuSuiteFree(CuSuite *suite) {
320     for (int i=0; i < suite->count; i++) {
321         CuTest *test = suite->list[i];
322         free(test->name);
323         free(test->message);
324         free(test);
325     }
326     free(suite);
327 }
328 /*
329  * Test utilities
330  */
331 void run(CuTest *tc, const char *format, ...) {
332     char *command;
333     va_list args;
334     int r;
335
336     va_start(args, format);
337     r = vasprintf(&command, format, args);
338     va_end (args);
339     if (r < 0)
340         CuFail(tc, "Failed to format command (out of memory)");
341     r = system(command);
342     if (r < 0 || (WIFEXITED(r) && WEXITSTATUS(r) != 0)) {
343         char *msg;
344         r = asprintf(&msg, "Command %s failed with status %d\n",
345                      command, WEXITSTATUS(r));
346         CuFail(tc, msg);
347         free(msg);
348     }
349     free(command);
350 }
351
352 int should_run(const char *name, int argc, char **argv) {
353     if (argc == 0)
354         return 1;
355     for (int i=0; i < argc; i++)
356         if (STREQ(argv[i], name))
357             return 1;
358     return 0;
359 }
360
361 /*
362  * Local variables:
363  *  indent-tabs-mode: nil
364  *  c-indent-level: 4
365  *  c-basic-offset: 4
366  *  tab-width: 4
367  * End:
368  */