1 /*
2  *  sput - Simple, Portable Unit Testing Framework for C/C++ v1.2.0
3  *
4  *  Copyright (c) 2011-2012 Lingua-Systems Software GmbH
5  *
6  *  All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions are
10  *  met:
11  *
12  *   * Redistributions of source code must retain the above copyright notice,
13  *     this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *
18  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 #ifndef HAVE_SPUT_H
33 #define HAVE_SPUT_H
34 
35 
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39 
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 
46 
47 /* =======================================================================
48  *                             definitions
49  * ======================================================================= */
50 
51 #define SPUT_VERSION_MAJOR      1
52 #define SPUT_VERSION_MINOR      2
53 #define SPUT_VERSION_PATCH      0
54 #define SPUT_VERSION_STRING     "1.2.0"
55 
56 #define SPUT_DEFAULT_SUITE_NAME "Unlabeled Suite"
57 #define SPUT_DEFAULT_CHECK_NAME "Unlabeled Check"
58 
59 #define SPUT_INITIALIZED        0x06 /* ACK */
60 
61 
62 /* =======================================================================
63  *                        sput global variable
64  * ======================================================================= */
65 
66 static struct
67 {
68     FILE *out;
69     char  initialized;
70 
71     struct
72     {
73         unsigned long checks;
74         unsigned long suites;
75         unsigned long ok;
76         unsigned long nok;
77     } overall;
78 
79     struct
80     {
81         const char   *name;
82         unsigned long nr;
83         unsigned long checks;
84         unsigned long ok;
85         unsigned long nok;
86     } suite;
87 
88     struct
89     {
90         const char   *name;
91         unsigned long nr;
92     } test;
93 
94     struct
95     {
96         const char   *name;
97         const char   *cond;
98         const char   *type;
99         unsigned long line;
100     } check;
101 
102     struct
103     {
104         time_t start;
105         time_t end;
106     } time;
107 } __sput;
108 
109 
110 /* =======================================================================
111  *                        sput internal macros
112  * ======================================================================= */
113 
114 #define _sput_die_unless_initialized()                                     \
115     if (__sput.initialized != SPUT_INITIALIZED)                            \
116     {                                                                      \
117         fputs("sput_start_testing() omitted\n", stderr);                   \
118         exit(EXIT_FAILURE);                                                \
119     }
120 
121 
122 #define _sput_die_unless_suite_set()                                       \
123     if (! __sput.suite.name)                                               \
124     {                                                                      \
125         fputs("sput_enter_suite() omitted\n", __sput.out);                 \
126         exit(EXIT_FAILURE);                                                \
127     }
128 
129 
130 #define _sput_die_unless_test_set()                                        \
131     if (! __sput.test.name)                                                \
132     {                                                                      \
133         fputs("sput_run_test() omitted\n", __sput.out);                    \
134         exit(EXIT_FAILURE);                                                \
135     }
136 
137 
138 #define _sput_check_failed()                                               \
139     {                                                                      \
140         _sput_die_unless_initialized();                                    \
141         _sput_die_unless_suite_set();                                      \
142         \
143         __sput.suite.nok++;                                                \
144         \
145         fprintf(__sput.out,                                                \
146                 "[%lu:%lu]  %s:#%lu  \"%s\"  FAIL\n"                       \
147                 "!    Type:      %s\n"                                     \
148                 "!    Condition: %s\n"                                     \
149                 "!    Line:      %lu\n",                                   \
150                 __sput.suite.nr, __sput.suite.checks, __sput.test.name,    \
151                 __sput.test.nr, __sput.check.name, __sput.check.type,      \
152                 __sput.check.cond, __sput.check.line);                     \
153     }
154 
155 
156 #define _sput_check_succeeded()                                            \
157     {                                                                      \
158         _sput_die_unless_initialized();                                    \
159         _sput_die_unless_suite_set();                                      \
160         \
161         __sput.suite.ok++;                                                 \
162         \
163         fprintf(__sput.out,                                                \
164                 "[%lu:%lu]  %s:#%lu  \"%s\"  pass\n",                      \
165                 __sput.suite.nr, __sput.suite.checks,                      \
166                 __sput.test.name,                                          \
167                 __sput.test.nr,                                            \
168                 __sput.check.name);                                        \
169     }
170 
171 
172 /* =======================================================================
173  *                            user macros
174  * ======================================================================= */
175 
176 #define sput_start_testing()                                               \
177     do {                                                                   \
178         memset(&__sput, 0, sizeof(__sput));                                \
179         \
180         __sput.out         = stdout;                                       \
181         __sput.time.start  = time(NULL);                                   \
182         __sput.initialized = SPUT_INITIALIZED;                             \
183     } while (0)
184 
185 
186 #define sput_leave_suite()                                                 \
187     do {                                                                   \
188         float failp = 0.0f;                                                \
189         \
190         _sput_die_unless_initialized();                                    \
191         _sput_die_unless_suite_set();                                      \
192         \
193         failp = __sput.suite.checks ? (float)                              \
194                 ((__sput.suite.nok * 100.0) / __sput.suite.checks) :       \
195                 0.0f;                                                      \
196         \
197         fprintf(__sput.out,                                                \
198                 "\n--> %lu check(s), %lu ok, %lu failed (%.2f%%)\n",       \
199                 __sput.suite.checks, __sput.suite.ok, __sput.suite.nok,    \
200                 failp);                                                    \
201         \
202         __sput.overall.checks += __sput.suite.checks;                      \
203         __sput.overall.ok     += __sput.suite.ok;                          \
204         __sput.overall.nok    += __sput.suite.nok;                         \
205         \
206         memset(&__sput.suite, 0, sizeof(__sput.suite));                    \
207     } while (0)
208 
209 
210 #define sput_get_return_value()                                            \
211     (__sput.overall.nok > 0 ? EXIT_FAILURE : EXIT_SUCCESS)
212 
213 
214 #define sput_enter_suite(_name)                                            \
215     do {                                                                   \
216         _sput_die_unless_initialized();                                    \
217         \
218         if (__sput.suite.name)                                             \
219         {                                                                  \
220             sput_leave_suite();                                            \
221         }                                                                  \
222         \
223         __sput.suite.name = _name ? _name : SPUT_DEFAULT_SUITE_NAME;       \
224         \
225         __sput.suite.nr = ++__sput.overall.suites;                         \
226         \
227         fprintf(__sput.out, "\n== Entering suite #%lu, \"%s\" ==\n\n",     \
228                 __sput.suite.nr, __sput.suite.name);                       \
229     } while (0)
230 
231 
232 #define sput_finish_testing()                                              \
233     do {                                                                   \
234         float failp = 0.0f;                                                \
235         \
236         _sput_die_unless_initialized();                                    \
237         \
238         if (__sput.suite.name)                                             \
239         {                                                                  \
240             sput_leave_suite();                                            \
241         }                                                                  \
242         \
243         failp = __sput.overall.checks ? (float)                            \
244                 ((__sput.overall.nok * 100.0) / __sput.overall.checks) :   \
245                 0.0f;                                                      \
246         \
247         __sput.time.end = time(NULL);                                      \
248         \
249         fprintf(__sput.out,                                                \
250                 "\n==> %lu check(s) in %lu suite(s) finished after %.2f "  \
251                 "second(s),\n"                                             \
252                 "    %lu succeeded, %lu failed (%.2f%%)\n"                 \
253                 "\n[%s]\n",                                                \
254                 __sput.overall.checks, __sput.overall.suites,              \
255                 difftime(__sput.time.end, __sput.time.start),              \
256                 __sput.overall.ok, __sput.overall.nok, failp,              \
257                 (sput_get_return_value() == EXIT_SUCCESS) ?                \
258                 "SUCCESS" : "FAILURE");                                    \
259     } while (0)
260 
261 
262 #define sput_set_output_stream(_fp)                                        \
263     do {                                                                   \
264         __sput.out = _fp ? _fp : stdout;                                   \
265     } while (0)
266 
267 
268 #define sput_fail_if(_cond, _name)                                         \
269     do {                                                                   \
270         _sput_die_unless_initialized();                                    \
271         _sput_die_unless_suite_set();                                      \
272         _sput_die_unless_test_set();                                       \
273         \
274         __sput.check.name = _name ? _name : SPUT_DEFAULT_CHECK_NAME;       \
275         __sput.check.line = __LINE__;                                      \
276         __sput.check.cond = #_cond;                                        \
277         __sput.check.type = "fail-if";                                     \
278         __sput.test.nr++;                                                  \
279         __sput.suite.checks++;                                             \
280         \
281         if ((_cond))                                                       \
282         {                                                                  \
283             _sput_check_failed();                                          \
284         }                                                                  \
285         else                                                               \
286         {                                                                  \
287             _sput_check_succeeded();                                       \
288         }                                                                  \
289     } while (0)
290 
291 
292 #define sput_fail_unless(_cond, _name)                                     \
293     do {                                                                   \
294         _sput_die_unless_initialized();                                    \
295         _sput_die_unless_suite_set();                                      \
296         _sput_die_unless_test_set();                                       \
297         \
298         __sput.check.name = _name ? _name : SPUT_DEFAULT_CHECK_NAME;       \
299         __sput.check.line = __LINE__;                                      \
300         __sput.check.cond = #_cond;                                        \
301         __sput.check.type = "fail-unless";                                 \
302         __sput.test.nr++;                                                  \
303         __sput.suite.checks++;                                             \
304         \
305         if (! (_cond))                                                     \
306         {                                                                  \
307             _sput_check_failed();                                          \
308         }                                                                  \
309         else                                                               \
310         {                                                                  \
311             _sput_check_succeeded();                                       \
312         }                                                                  \
313     } while (0)
314 
315 
316 #define sput_run_test(_func)                                               \
317     do {                                                                   \
318         _sput_die_unless_initialized();                                    \
319         _sput_die_unless_suite_set();                                      \
320         \
321         memset(&__sput.test, 0, sizeof(__sput.test));                      \
322         __sput.test.name = #_func;                                         \
323         \
324         _func();                                                           \
325     } while (0)
326 
327 
328 #ifdef __cplusplus
329 }
330 #endif
331 
332 
333 #endif /* HAVE_SPUT_H */
334 
335 
336 /*
337 vim: sts=4 sw=4 ts=4 ai et ft=c
338 */
339