~ubuntu-branches/ubuntu/hardy/sigscheme/hardy-proposed

« back to all changes in this revision

Viewing changes to test-c2/sscm-test.h

  • Committer: Bazaar Package Importer
  • Author(s): NIIBE Yutaka
  • Date: 2007-01-29 15:31:24 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20070129153124-j5fcqyrwcfbczma7
Tags: 0.7.4-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*=====================================================================-*-c-*-
2
 
 *  Filename : sscm-test.h
3
 
 *  About    : scheme C-level testing utilities
4
 
 *
5
 
 *  Copyright (C) 2006 Jun Inoue <jun.lambda@gmail.com>
6
 
 *
7
 
 *  All rights reserved.
8
 
 *
9
 
 *  Redistribution and use in source and binary forms, with or without
10
 
 *  modification, are permitted provided that the following conditions
11
 
 *  are met:
12
 
 *
13
 
 *  1. Redistributions of source code must retain the above copyright
14
 
 *     notice, this list of conditions and the following disclaimer.
15
 
 *  2. Redistributions in binary form must reproduce the above copyright
16
 
 *     notice, this list of conditions and the following disclaimer in the
17
 
 *     documentation and/or other materials provided with the distribution.
18
 
 *  3. Neither the name of authors nor the names of its contributors
19
 
 *     may be used to endorse or promote products derived from this software
20
 
 *     without specific prior written permission.
21
 
 *
22
 
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
23
 
 *  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24
 
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25
 
 *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
26
 
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27
 
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28
 
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29
 
 *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30
 
 *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31
 
 *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32
 
 *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
 
===========================================================================*/
34
 
 
35
 
#ifndef SSCM_TEST_H
36
 
#define SSCM_TEST_H
37
 
 
38
 
 
39
 
#include <sigscheme/sigscheme.h>
40
 
 
41
 
#include <string.h>
42
 
#include <stdio.h>
43
 
#include <stdlib.h>
44
 
 
45
 
typedef struct _tst_suite_info tst_suite_info;
46
 
typedef struct _tst_case_info tst_case_info;
47
 
 
48
 
/* ------------------------------
49
 
 * Output
50
 
 */
51
 
 
52
 
static char *
53
 
tst_format(const char *msg, ...)
54
 
{
55
 
    va_list va;
56
 
    char *buf;
57
 
    int len;
58
 
    va_start(va, msg);
59
 
 
60
 
    len = vsnprintf(NULL, 0, msg, va);
61
 
    if (len < 0)
62
 
        abort();
63
 
    buf = malloc (len + 1);
64
 
    if (!buf)
65
 
        abort();
66
 
    vsnprintf (buf, len + 1, msg, va);
67
 
 
68
 
    va_end(va);
69
 
    return buf;
70
 
}
71
 
 
72
 
static void
73
 
tst_puts(tst_suite_info *_, tst_case_info *__, const char *msg)
74
 
{
75
 
    fputs (msg, stderr);
76
 
}
77
 
 
78
 
 
79
 
 
80
 
/* ------------------------------
81
 
 * Test case
82
 
 */
83
 
 
84
 
struct _tst_case_info {
85
 
    void (*fn)(tst_suite_info*, tst_case_info*);
86
 
    const char *desc;
87
 
    int done;
88
 
    int succ;
89
 
    int fail;
90
 
    int abortp;
91
 
};
92
 
 
93
 
 
94
 
#define TST_TRAMPOLINE(id) id##_
95
 
 
96
 
/* If you're preprocessing with collect.sh, this macro and its
97
 
 * arguments has to be written in one line.  C macros can't be used in
98
 
 * either argument.  ID is the function name of the test case, DSC is
99
 
 * a description of the test case and must be a string
100
 
 * literal. */
101
 
#define TST_CASE(id, dsc)                               \
102
 
static void id(tst_suite_info *, tst_case_info *, int); \
103
 
static void                                             \
104
 
TST_TRAMPOLINE(id)(tst_suite_info *TST_SUITE_INFO,      \
105
 
                   tst_case_info  *TST_CASE_INFO)       \
106
 
{                                                       \
107
 
    TST_CASE_INFO->desc = dsc;                          \
108
 
    id(TST_SUITE_INFO, TST_CASE_INFO, 0);               \
109
 
}                                                       \
110
 
static void                                             \
111
 
id(tst_suite_info *TST_SUITE_INFO,                      \
112
 
   tst_case_info *TST_CASE_INFO,                        \
113
 
   int TST_FAILED)
114
 
 
115
 
 
116
 
/* ------------------------------
117
 
 * Invocation
118
 
 */
119
 
 
120
 
struct _tst_suite_info {
121
 
    void (*logger)(tst_suite_info *, tst_case_info *, const char *);
122
 
    tst_case_info *results;
123
 
    struct {
124
 
        int cases;
125
 
        int done;               /* Number of individual tests. */
126
 
        int succ;
127
 
        int fail;
128
 
        int aborts;
129
 
    } stats;
130
 
};
131
 
 
132
 
#define TST_DEFAULT_SUITE_SETUP                 \
133
 
    {                                           \
134
 
        tst_puts, NULL, {0}                     \
135
 
    }
136
 
 
137
 
#define TST_DEFAULT_SUITE_CLEANUP(suite)        \
138
 
    do {                                        \
139
 
        free((suite).results);                  \
140
 
    } while(0)
141
 
 
142
 
 
143
 
#ifdef TST_EXCLUDE_THIS
144
 
#define TST_LIST_BEGIN()                        \
145
 
int                                             \
146
 
main ()                                         \
147
 
{                                               \
148
 
    puts ("Nothing to test.");                  \
149
 
    return 0;                                   \
150
 
}
151
 
#define TST_REGISTER(fn)        /* Empty */
152
 
#define TST_LIST_END()          /* Empty */
153
 
 
154
 
#else  /* !defined (TST_EXCLUDE_THIS) */
155
 
 
156
 
#define TST_RUN(fn, s, c)  SCM_GC_PROTECTED_CALL_VOID((fn), ((s), (c)))
157
 
 
158
 
 
159
 
#define TST_LIST_BEGIN()                                \
160
 
/* Returns 1 if any test case fails, otherwise 0. */    \
161
 
static int                                              \
162
 
tst_main(tst_suite_info *suite)                         \
163
 
{                                                       \
164
 
    tst_case_info cases[] = {
165
 
 
166
 
#define TST_REGISTER(fn) { TST_TRAMPOLINE(fn) },
167
 
 
168
 
#define TST_LIST_END()                                          \
169
 
        { 0 } /* Dummy in case no test case is present. */      \
170
 
    };                                                          \
171
 
    size_t i;                                                   \
172
 
                                                                \
173
 
    puts("testing " __FILE__ "...");                                    \
174
 
    for (i = 0; cases[i].fn; i++) {                             \
175
 
        TST_RUN(cases[i].fn, suite, &cases[i]);                 \
176
 
        tst_analyze(suite, &cases[i]);                          \
177
 
    }                                                           \
178
 
    tst_summarize(suite);                                       \
179
 
                                                                \
180
 
    suite->results = malloc(sizeof(cases));                     \
181
 
    memcpy(suite->results, cases, sizeof(cases));               \
182
 
                                                                \
183
 
    return !!suite->stats.fail;                                 \
184
 
}                                                               \
185
 
TST_MAIN()
186
 
 
187
 
#ifdef TST_HAVE_MAIN
188
 
#define TST_MAIN()              /* Empty. */
189
 
#else  /* not have main() */
190
 
#define TST_MAIN()                                      \
191
 
int                                                     \
192
 
main(int argc, char *argv[])                            \
193
 
{                                                       \
194
 
    tst_suite_info suite = TST_DEFAULT_SUITE_SETUP;     \
195
 
    scm_initialize(NULL);                               \
196
 
    tst_main(&suite);                                   \
197
 
    scm_finalize();                                     \
198
 
    TST_DEFAULT_SUITE_CLEANUP(suite);                   \
199
 
    return !!suite.stats.fail;                          \
200
 
}
201
 
#endif /* not have main() */
202
 
 
203
 
 
204
 
static void
205
 
tst_analyze(tst_suite_info *suite, tst_case_info *result)
206
 
{
207
 
    suite->stats.done += result->done;
208
 
    suite->stats.succ += result->succ;
209
 
    suite->stats.fail += result->fail;
210
 
    ++suite->stats.cases;
211
 
    if (result->abortp) {
212
 
        ++suite->stats.aborts;
213
 
        suite->logger(suite, result,
214
 
                      tst_format("* ABORTED: %s\n", result->desc));
215
 
    } else {
216
 
        suite->logger(suite, result,
217
 
                      tst_format("%s: %s\n",
218
 
                                 result->fail ? "* FAILED"
219
 
                                              : "    OK",
220
 
                                 result->desc));
221
 
    }
222
 
}
223
 
 
224
 
static void
225
 
tst_summarize(tst_suite_info *suite)
226
 
{
227
 
    suite->logger(suite, NULL,
228
 
                  tst_format("%d test cases, %d aborted.  %d individual "
229
 
                             "tests, %d succeeded and %d failed.\n",
230
 
                             suite->stats.cases, suite->stats.aborts,
231
 
                             suite->stats.done,
232
 
                             suite->stats.succ, suite->stats.fail));
233
 
}
234
 
 
235
 
 
236
 
 
237
 
#endif /* !defined (TST_EXCLUDE_THIS) */
238
 
 
239
 
 
240
 
 
241
 
/* ------------------------------
242
 
 * Tests
243
 
 */
244
 
#define TST_LOG(msg)  TST_SUITE_INFO->logger(TST_SUITE_INFO,    \
245
 
                                             TST_CASE_INFO,     \
246
 
                                             msg)
247
 
#define TST_FAIL(msg) (++TST_CASE_INFO->done,   \
248
 
                       ++TST_CASE_INFO->fail,   \
249
 
                       TST_LOG(msg),            \
250
 
                       TST_FAILED = 1,          \
251
 
                       0)
252
 
#define TST_SUCC()    (++TST_CASE_INFO->done,   \
253
 
                       ++TST_CASE_INFO->succ,   \
254
 
                       TST_FAILED = 0,          \
255
 
                       1)
256
 
 
257
 
#define TST_ABORT()   do { TST_CASE_INFO->abortp = 1; return; } while (0)
258
 
 
259
 
#define TST_ASSERT(cond) if (!(cond)) TST_ABORT()
260
 
 
261
 
#define TST_COND(cond, desc)                            \
262
 
    (((cond)                                            \
263
 
      ||                                                \
264
 
      TST_FAIL(tst_format(__FILE__ ":%d: %s failed.\n", \
265
 
                          __LINE__, desc)))             \
266
 
     && TST_SUCC())
267
 
 
268
 
#define TST_EQUALITY(eqp, type, fmt, expect, actual, desc)      \
269
 
do {                                                            \
270
 
    type _x = (expect);                                         \
271
 
    type _a = (actual);                                         \
272
 
    if (!eqp(_x, _a)) {                                         \
273
 
        TST_FAIL(tst_format(__FILE__ ":%d: %s failed.\n"        \
274
 
                            "  expected: " fmt "\n"             \
275
 
                            "  but got : " fmt "\n",            \
276
 
                            __LINE__, desc, _x, _a));           \
277
 
    } else {                                                    \
278
 
        TST_SUCC();                                             \
279
 
    }                                                           \
280
 
} while (0)
281
 
 
282
 
/* Comparators. */
283
 
#define TST_C_EQUAL(a, b)    ((a) == (b))
284
 
#define TST_STR_EQUAL(a, b)  (!strcmp((a), (b)))
285
 
 
286
 
 
287
 
/* Equality tests. */
288
 
#if HAVE_INTMAX_T
289
 
#define TST_EQ_INT(x, a, desc)  TST_EQUALITY(TST_C_EQUAL, intmax_t, \
290
 
                                             "%jd", x, a, desc)
291
 
#define TST_EQ_UINT(x, a, desc) TST_EQUALITY(TST_C_EQUAL, uintmax_t, \
292
 
                                             "%ujd", x, a, desc)
293
 
#define TST_NEQ_INT(x, a, desc)  TST_EQUALITY(!TST_C_EQUAL, intmax_t, \
294
 
                                              "%jd", x, a, desc)
295
 
#define TST_NEQ_UINT(x, a, desc) TST_EQUALITY(!TST_C_EQUAL, uintmax_t, \
296
 
                                              "%ujd", x, a, desc)
297
 
#else  /* not have intmax_t */
298
 
#define TST_EQ_INT(x, a, desc)  TST_EQUALITY(TST_C_EQUAL, long, \
299
 
                                             "%ld", x, a, desc)
300
 
#define TST_EQ_UINT(x, a, desc) TST_EQUALITY(TST_C_EQUAL, unsigned long, \
301
 
                                             "%uld", x, a, desc)
302
 
#define TST_NEQ_INT(x, a, desc)  TST_EQUALITY(!TST_C_EQUAL, long, \
303
 
                                             "%ld", x, a, desc)
304
 
#define TST_NEQ_UINT(x, a, desc) TST_EQUALITY(!TST_C_EQUAL, unsigned long, \
305
 
                                             "%uld", x, a, desc)
306
 
#endif /* not have intmax_t */
307
 
 
308
 
#define TST_EQ_STR(x, a, desc)  TST_EQUALITY(TST_STR_EQUAL, char*,      \
309
 
                                             "%s", x, a, desc)
310
 
#define TST_NEQ_STR(x, a, desc)  TST_EQUALITY(!TST_STR_EQUAL, char*,    \
311
 
                                              "%s", x, a, desc)
312
 
#define TST_EQ_PTR(x, a, desc)  TST_EQUALITY(TST_C_EQUAL, void*,        \
313
 
                                             "%p", x, a, desc)
314
 
#define TST_NEQ_PTR(x, a, desc)  TST_EQUALITY(!TST_C_EQUAL, void*,      \
315
 
                                              "%p", x, a, desc)
316
 
#define TST_EQ_OBJ(x, a, desc)  TST_EQUALITY(SCM_EQ, scm_uintobj_t,     \
317
 
                                             "%lx", (scm_uintobj_t)x,   \
318
 
                                             (scm_uintobj_t)a, desc)
319
 
#define TST_NEQ_OBJ(x, a, desc)  TST_EQUALITY(!SCM_EQ, scm_uintobj_t,   \
320
 
                                              "%lx", (scm_uintobj_t)x,  \
321
 
                                              (scm_uintobj_t)a, desc)
322
 
 
323
 
/* Function pointers are a bit tricky. */
324
 
typedef void (*tst_funcptr_t)();
325
 
#define TST_EQ_FPTR(x, a, desc)                                         \
326
 
    TST_EQUALITY(TST_C_EQUAL, tst_funcptr_t, "%p",                      \
327
 
                 (0 ? (tst_funcptr_t)((x) == (a)) /* Typecheck */       \
328
 
                    : (tst_funcptr_t)(x)),                              \
329
 
                 (tst_funcptr_t)(a), desc)
330
 
 
331
 
#define TST_NEQ_FPTR(x, a, desc)                                        \
332
 
    TST_EQUALITY(!TST_C_EQUAL, tst_funcptr_t, "%p",                     \
333
 
                 (0 ? (tst_funcptr_t)((x) == (a)) /* Typecheck */       \
334
 
                    : (tst_funcptr_t)(x)),                              \
335
 
                 (tst_funcptr_t)(a), desc)
336
 
 
337
 
#define TST_EQ  TST_EQ_OBJ
338
 
#define TST_NEQ TST_NEQ_OBJ
339
 
 
340
 
 
341
 
#endif /* !def SSCM_TEST_H */