Imported Upstream version 0.10.0
[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 <assert.h>
32 #include <setjmp.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <math.h>
37
38 #include "cutest.h"
39 #include "memory.h"
40
41 #define HUGE_STRING_LEN 8192
42 #define STRING_MAX              256
43
44 #define asprintf_or_die(strp, fmt, args ...)                            \
45     if (asprintf(strp, fmt, ## args) == -1) {                           \
46         fprintf(stderr, "Fatal error (probably out of memory)\n");      \
47         abort();                                                        \
48     }
49
50 void die_oom(void) {
51     printf("Ran out of memory. Send more\n");
52     exit(2);
53 }
54
55 /*-------------------------------------------------------------------------*
56  * CuTest
57  *-------------------------------------------------------------------------*/
58
59 void CuTestInit(CuTest* t, const char* name, TestFunction function) {
60         t->name = strdup(name);
61         t->failed = 0;
62         t->ran = 0;
63         t->message = NULL;
64         t->function = function;
65         t->jumpBuf = NULL;
66 }
67
68 CuTest* CuTestNew(const char* name, TestFunction function) {
69         CuTest* tc = NULL;
70     if (ALLOC(tc) < 0)
71         die_oom();
72         CuTestInit(tc, name, function);
73         return tc;
74 }
75
76 void CuTestRun(CuTest* tc, TestFunction setup, TestFunction teardown) {
77         jmp_buf buf;
78
79     if (getenv("CUTEST") && STRNEQ(getenv("CUTEST"), tc->name))
80         return;
81         tc->jumpBuf = &buf;
82         if (setjmp(buf) == 0) {
83         if (setup)
84             (setup)(tc);
85                 tc->ran = 1;
86                 (tc->function)(tc);
87         }
88     if (teardown && setjmp(buf) == 0) {
89         (teardown)(tc);
90     }
91         tc->jumpBuf = 0;
92 }
93
94 static void CuFailInternal(CuTest* tc, const char* file, int line,
95                            const char *string) {
96         char *buf = NULL;
97
98         asprintf_or_die(&buf, "%s:%d: %s", file, line, string);
99
100         tc->failed = 1;
101         tc->message = buf;
102         if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
103 }
104
105 void CuFail_Line(CuTest* tc, const char* file, int line,
106                  const char* message2, const char* message) {
107     char *string = NULL;
108
109         if (message2 != NULL) {
110                 asprintf_or_die(&string, "%s:%s", message2, message);
111         } else {
112         string = strdup(message);
113     }
114         CuFailInternal(tc, file, line, string);
115 }
116
117 void CuAssert_Line(CuTest* tc, const char* file, int line,
118                    const char* message, int condition) {
119         if (condition) return;
120         CuFail_Line(tc, file, line, NULL, message);
121 }
122
123 void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line,
124                                const char* message,
125                                const char* expected, const char* actual) {
126         char *string = NULL;
127
128         if ((expected == NULL && actual == NULL) ||
129             (expected != NULL && actual != NULL &&
130              strcmp(expected, actual) == 0))
131         {
132             return;
133         }
134
135         if (message != NULL) {
136         asprintf_or_die(&string, "%s: expected <%s> but was <%s>", message,
137                         expected, actual);
138         } else {
139         asprintf_or_die(&string, "expected <%s> but was <%s>", expected, actual);
140     }
141         CuFailInternal(tc, file, line, string);
142 }
143
144 void CuAssertStrNotEqual_LineMsg(CuTest* tc, const char* file, int line,
145                                  const char* message,
146                                  const char* expected, const char* actual) {
147         char *string = NULL;
148
149     if (expected != NULL && actual != NULL && strcmp(expected, actual) != 0)
150         return;
151
152         if (message != NULL) {
153         asprintf_or_die(&string, "%s: expected <%s> but was <%s>", message,
154                         expected, actual);
155         } else {
156         asprintf_or_die(&string, "expected <%s> but was <%s>", expected, actual);
157     }
158         CuFailInternal(tc, file, line, string);
159 }
160
161 void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line,
162                                const char* message,
163                                int expected, int actual) {
164         char buf[STRING_MAX];
165         if (expected == actual) return;
166         sprintf(buf, "expected <%d> but was <%d>", expected, actual);
167         CuFail_Line(tc, file, line, message, buf);
168 }
169
170 void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line,
171                                const char* message,
172                                double expected, double actual, double delta) {
173         char buf[STRING_MAX];
174         if (fabs(expected - actual) <= delta) return;
175         sprintf(buf, "expected <%lf> but was <%lf>", expected, actual);
176         CuFail_Line(tc, file, line, message, buf);
177 }
178
179 void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line,
180                                const char* message,
181                                const void* expected, const void* actual) {
182         char buf[STRING_MAX];
183         if (expected == actual) return;
184         sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
185         CuFail_Line(tc, file, line, message, buf);
186 }
187
188 void CuAssertPtrNotEqual_LineMsg(CuTest* tc, const char* file, int line,
189                                  const char* message,
190                                  const void* expected, const void* actual) {
191         char buf[STRING_MAX];
192         if (expected != actual) return;
193         sprintf(buf, "expected pointer <0x%p> to be different from <0x%p>",
194             expected, actual);
195         CuFail_Line(tc, file, line, message, buf);
196 }
197
198
199 /*-------------------------------------------------------------------------*
200  * CuSuite
201  *-------------------------------------------------------------------------*/
202
203 void CuSuiteInit(CuSuite* testSuite) {
204         testSuite->count = 0;
205         testSuite->failCount = 0;
206 }
207
208 CuSuite* CuSuiteNew(void) {
209         CuSuite* testSuite = NULL;
210     if (ALLOC(testSuite) < 0)
211         die_oom();
212         CuSuiteInit(testSuite);
213         return testSuite;
214 }
215
216 void CuSuiteSetup(CuSuite *testSuite,
217                   TestFunction setup, TestFunction teardown) {
218     testSuite->setup = setup;
219     testSuite->teardown = teardown;
220 }
221
222 void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) {
223         assert(testSuite->count < MAX_TEST_CASES);
224         testSuite->list[testSuite->count] = testCase;
225         testSuite->count++;
226 }
227
228 void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) {
229         int i;
230         for (i = 0 ; i < testSuite2->count ; ++i)
231         {
232             CuTest* testCase = testSuite2->list[i];
233             CuSuiteAdd(testSuite, testCase);
234         }
235 }
236
237 void CuSuiteRun(CuSuite* testSuite) {
238         int i;
239         for (i = 0 ; i < testSuite->count ; ++i)
240         {
241             CuTest* testCase = testSuite->list[i];
242             CuTestRun(testCase, testSuite->setup, testSuite->teardown);
243             if (testCase->failed) { testSuite->failCount += 1; }
244         }
245 }
246
247 static void string_append(char **s, const char *p) {
248     if (*s == NULL) {
249         *s = strdup(p);
250     } else {
251         int len = strlen(*s) + strlen(p) + 1;
252         *s = realloc(*s, len);
253         if (*s == NULL)
254             die_oom();
255         strcat(*s, p);
256     }
257 }
258
259 void CuSuiteSummary(CuSuite* testSuite, char **summary) {
260         int i;
261
262         for (i = 0 ; i < testSuite->count ; ++i)
263         {
264             CuTest* testCase = testSuite->list[i];
265             string_append(summary, testCase->failed ? "F" : ".");
266         }
267         string_append(summary, "\n\n");
268 }
269
270 void CuSuiteDetails(CuSuite* testSuite, char **details) {
271         int i;
272         int failCount = 0;
273     char *s = NULL;
274
275         if (testSuite->failCount == 0)
276         {
277             int passCount = testSuite->count - testSuite->failCount;
278             const char* testWord = passCount == 1 ? "test" : "tests";
279             asprintf_or_die(&s, "OK (%d %s)\n", passCount, testWord);
280             string_append(details, s);
281             free(s);
282         } else {
283                 if (testSuite->failCount == 1)
284                         string_append(details, "There was 1 failure:\n");
285                 else {
286             asprintf_or_die(&s, "There were %d failures:\n",
287                             testSuite->failCount);
288             string_append(details, s);
289             free(s);
290         }
291                 for (i = 0 ; i < testSuite->count ; ++i) {
292                         CuTest* testCase = testSuite->list[i];
293                         if (testCase->failed) {
294                                 failCount++;
295                                 asprintf_or_die(&s, "%d) %s:\n%s\n",
296                          failCount, testCase->name, testCase->message);
297                 string_append(details, s);
298                 free(s);
299                         }
300                 }
301                 string_append(details, "\n!!!FAILURES!!!\n");
302
303                 asprintf_or_die(&s, "Runs: %d ",   testSuite->count);
304         string_append(details, s);
305         free(s);
306
307         asprintf_or_die(&s, "Passes: %d ",
308                         testSuite->count - testSuite->failCount);
309         string_append(details, s);
310         free(s);
311
312                 asprintf_or_die(&s, "Fails: %d\n",  testSuite->failCount);
313         string_append(details, s);
314         free(s);
315         }
316 }
317
318 /*
319  * Test utilities
320  */
321 void run(CuTest *tc, const char *format, ...) {
322     char *command;
323     va_list args;
324     int r;
325
326     va_start(args, format);
327     r = vasprintf(&command, format, args);
328     va_end (args);
329     if (r < 0)
330         CuFail(tc, "Failed to format command (out of memory)");
331     r = system(command);
332     if (r < 0 || (WIFEXITED(r) && WEXITSTATUS(r) != 0)) {
333         char *msg;
334         r = asprintf(&msg, "Command %s failed with status %d\n",
335                      command, WEXITSTATUS(r));
336         CuFail(tc, msg);
337         free(msg);
338     }
339     free(command);
340 }
341
342 /*
343  * Local variables:
344  *  indent-tabs-mode: nil
345  *  c-indent-level: 4
346  *  c-basic-offset: 4
347  *  tab-width: 4
348  * End:
349  */