~ubuntu-branches/ubuntu/hardy/uim/hardy

« back to all changes in this revision

Viewing changes to sigscheme/test-c/sscm-test.h

  • Committer: Bazaar Package Importer
  • Author(s): Masahito Omote
  • Date: 2007-04-21 03:46:09 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20070421034609-gpcurkutp8vaysqj
Tags: 1:1.4.1-3
* Switch to dh_gtkmodules for the gtk 2.10 transition (Closes:
  #419318)
  - debian/control: Add ${misc:Depends} and remove libgtk2.0-bin on
    uim-gtk2.0.
  - debian/uim-gtk2.0.post{inst,rm}: Removed.

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
 *  Copyright (c) 2007 SigScheme Project <uim AT freedesktop.org>
 
7
 *
 
8
 *  All rights reserved.
 
9
 *
 
10
 *  Redistribution and use in source and binary forms, with or without
 
11
 *  modification, are permitted provided that the following conditions
 
12
 *  are met:
 
13
 *
 
14
 *  1. Redistributions of source code must retain the above copyright
 
15
 *     notice, this list of conditions and the following disclaimer.
 
16
 *  2. Redistributions in binary form must reproduce the above copyright
 
17
 *     notice, this list of conditions and the following disclaimer in the
 
18
 *     documentation and/or other materials provided with the distribution.
 
19
 *  3. Neither the name of authors nor the names of its contributors
 
20
 *     may be used to endorse or promote products derived from this software
 
21
 *     without specific prior written permission.
 
22
 *
 
23
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 
24
 *  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
25
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
26
 *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 
27
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
28
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
29
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
30
 *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
31
 *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
32
 *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
33
 *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
34
===========================================================================*/
 
35
 
 
36
#ifndef SSCM_TEST_H
 
37
#define SSCM_TEST_H
 
38
 
 
39
 
 
40
#include <sigscheme/sigscheme.h>
 
41
 
 
42
#include <string.h>
 
43
#include <stdio.h>
 
44
#include <stdlib.h>
 
45
#include <stdarg.h>
 
46
 
 
47
typedef struct _tst_suite_info tst_suite_info;
 
48
typedef struct _tst_case_info tst_case_info;
 
49
 
 
50
/* ------------------------------
 
51
 * Output
 
52
 */
 
53
 
 
54
static char *tst_format(const char *msg, ...) SCM_UNUSED;
 
55
static void tst_puts(tst_suite_info *_, tst_case_info *__,
 
56
                     const char *msg) SCM_UNUSED;
 
57
 
 
58
static char *
 
59
tst_format(const char *msg, ...)
 
60
{
 
61
    va_list va;
 
62
    char *buf;
 
63
    int len;
 
64
 
 
65
    va_start(va, msg);
 
66
    len = vsnprintf(NULL, 0, msg, va);
 
67
    if (len < 0)
 
68
        abort();
 
69
    va_end(va);
 
70
 
 
71
    /*
 
72
     * C99: 7.15 Variable arguments <stdarg.h>
 
73
     *
 
74
     * The object ap may be passed as an argument to another function; if that
 
75
     * function invokes the va_arg macro with parameter ap, the value of ap in
 
76
     * the calling function is indeterminate and shall be passed to the va_end
 
77
     * macro prior to any further reference to ap.
 
78
     */
 
79
    /* x86_64-unknown-linux-gnu crashes if this va_start() is not invoked */
 
80
    va_start(va, msg);
 
81
    buf = malloc (len + 1);
 
82
    if (!buf)
 
83
        abort();
 
84
    vsnprintf (buf, len + 1, msg, va);
 
85
    va_end(va);
 
86
 
 
87
    return buf;
 
88
}
 
89
 
 
90
static void
 
91
tst_puts(tst_suite_info *_, tst_case_info *__, const char *msg)
 
92
{
 
93
    fputs (msg, stderr);
 
94
}
 
95
 
 
96
 
 
97
 
 
98
/* ------------------------------
 
99
 * Test case
 
100
 */
 
101
 
 
102
struct _tst_case_info {
 
103
    void (*fn)(tst_suite_info*, tst_case_info*);
 
104
    const char *desc;
 
105
    int done;
 
106
    int succ;
 
107
    int fail;
 
108
    int abortp;
 
109
};
 
110
 
 
111
 
 
112
#define TST_TRAMPOLINE(id) id##_
 
113
 
 
114
/* Add TST_PARAMS_DECL to the params list of auxiliary functions if
 
115
 * you need to use TST_*() macros in them.  Call those functions with
 
116
 * TST_PARAMS in the corresponding position. */
 
117
#define TST_PARAMS_DECL    tst_suite_info *TST_SUITE_INFO,      \
 
118
                           tst_case_info  *TST_CASE_INFO,       \
 
119
                           int TST_FAILED
 
120
#define TST_PARAMS         TST_SUITE_INFO, TST_CASE_INFO, TST_FAILED
 
121
 
 
122
/* If you're preprocessing with collect.sh, this macro and its
 
123
 * arguments has to be written in one line.  C macros can't be used in
 
124
 * either argument.  ID is the function name of the test case, DSC is
 
125
 * a description of the test case and must be a string
 
126
 * literal. */
 
127
#define TST_CASE(id, dsc)                               \
 
128
static void id(TST_PARAMS_DECL);                        \
 
129
static void                                             \
 
130
TST_TRAMPOLINE(id)(tst_suite_info *TST_SUITE_INFO,      \
 
131
                   tst_case_info  *TST_CASE_INFO)       \
 
132
{                                                       \
 
133
    int TST_FAILED = 0;                                 \
 
134
    TST_CASE_INFO->desc = dsc;                          \
 
135
    id(TST_PARAMS);                                     \
 
136
}                                                       \
 
137
static void                                             \
 
138
id(TST_PARAMS_DECL)
 
139
 
 
140
 
 
141
/* ------------------------------
 
142
 * Invocation
 
143
 */
 
144
 
 
145
struct _tst_suite_info {
 
146
    void (*logger)(tst_suite_info *, tst_case_info *, const char *);
 
147
    tst_case_info *results;
 
148
    struct {
 
149
        int cases;
 
150
        int done;               /* Number of individual tests. */
 
151
        int succ;
 
152
        int fail;
 
153
        int aborts;
 
154
    } stats;
 
155
};
 
156
 
 
157
#define TST_DEFAULT_SUITE_SETUP                 \
 
158
    {                                           \
 
159
        tst_puts, NULL, {0}                     \
 
160
    }
 
161
 
 
162
#define TST_DEFAULT_SUITE_CLEANUP(suite)        \
 
163
    do {                                        \
 
164
        free((suite).results);                  \
 
165
    } while(0)
 
166
 
 
167
 
 
168
#ifdef TST_EXCLUDE_THIS
 
169
#define TST_LIST_BEGIN()                        \
 
170
int                                             \
 
171
main ()                                         \
 
172
{                                               \
 
173
    puts ("Nothing to test.");                  \
 
174
    return 0;                                   \
 
175
}
 
176
#define TST_REGISTER(fn)        /* Empty */
 
177
#define TST_LIST_END()          /* Empty */
 
178
 
 
179
#else  /* !defined (TST_EXCLUDE_THIS) */
 
180
 
 
181
typedef struct _tst_run_args tst_run_args;
 
182
struct _tst_run_args {
 
183
    void (*fn)(tst_suite_info *, tst_case_info *);
 
184
    tst_suite_info *suite;
 
185
    tst_case_info *tcase;
 
186
};
 
187
 
 
188
#define TST_RUN(fn, s, c)  tst_run((fn), (s), (c))
 
189
static void *tst_run_internal(tst_run_args *args);
 
190
static void
 
191
tst_run(void (*fn)(tst_suite_info *, tst_case_info *),
 
192
        tst_suite_info *suite, tst_case_info *tcase)
 
193
{
 
194
    tst_run_args args;
 
195
 
 
196
    args.fn = fn;
 
197
    args.suite = suite;
 
198
    args.tcase = tcase;
 
199
    scm_call_with_gc_ready_stack((ScmGCGateFunc)tst_run_internal, &args);
 
200
}
 
201
 
 
202
static void *
 
203
tst_run_internal(tst_run_args *args)
 
204
{
 
205
    (*args->fn)(args->suite, args->tcase);
 
206
    return NULL;
 
207
}
 
208
 
 
209
static int tst_main(tst_suite_info *suite);
 
210
 
 
211
#define TST_LIST_BEGIN()                                \
 
212
/* Returns 1 if any test case fails, otherwise 0. */    \
 
213
static int                                              \
 
214
tst_main(tst_suite_info *suite)                         \
 
215
{                                                       \
 
216
    tst_case_info cases[] = {
 
217
 
 
218
#define TST_REGISTER(fn) { TST_TRAMPOLINE(fn) },
 
219
 
 
220
#define TST_LIST_END()                                          \
 
221
        { 0 } /* Dummy in case no test case is present. */      \
 
222
    };                                                          \
 
223
    size_t i;                                                   \
 
224
                                                                \
 
225
    puts("testing " __FILE__ "...");                                    \
 
226
    for (i = 0; cases[i].fn; i++) {                             \
 
227
        TST_RUN(cases[i].fn, suite, &cases[i]);                 \
 
228
        tst_analyze(suite, &cases[i]);                          \
 
229
    }                                                           \
 
230
    tst_summarize(suite);                                       \
 
231
                                                                \
 
232
    suite->results = malloc(sizeof(cases));                     \
 
233
    memcpy(suite->results, cases, sizeof(cases));               \
 
234
                                                                \
 
235
    return !!suite->stats.fail;                                 \
 
236
}                                                               \
 
237
TST_MAIN()
 
238
 
 
239
#ifdef TST_HAVE_MAIN
 
240
#define TST_MAIN()              /* Empty. */
 
241
#else  /* not have main() */
 
242
#define TST_MAIN()                                      \
 
243
int                                                     \
 
244
main(int argc, char *argv[])                            \
 
245
{                                                       \
 
246
    tst_suite_info suite = TST_DEFAULT_SUITE_SETUP;     \
 
247
    scm_initialize(NULL);                               \
 
248
    tst_main(&suite);                                   \
 
249
    scm_finalize();                                     \
 
250
    TST_DEFAULT_SUITE_CLEANUP(suite);                   \
 
251
    return !!suite.stats.fail;                          \
 
252
}
 
253
#endif /* not have main() */
 
254
 
 
255
 
 
256
static void
 
257
tst_analyze(tst_suite_info *suite, tst_case_info *result)
 
258
{
 
259
    suite->stats.done += result->done;
 
260
    suite->stats.succ += result->succ;
 
261
    suite->stats.fail += result->fail;
 
262
    ++suite->stats.cases;
 
263
    if (result->abortp) {
 
264
        ++suite->stats.aborts;
 
265
        suite->logger(suite, result,
 
266
                      tst_format("* ABORTED: %s\n", result->desc));
 
267
    } else {
 
268
        suite->logger(suite, result,
 
269
                      tst_format("%s: %s\n",
 
270
                                 result->fail ? "* FAILED"
 
271
                                              : "    OK",
 
272
                                 result->desc));
 
273
    }
 
274
}
 
275
 
 
276
static void
 
277
tst_summarize(tst_suite_info *suite)
 
278
{
 
279
    suite->logger(suite, NULL,
 
280
                  tst_format("%d test cases, %d aborted.  %d individual "
 
281
                             "tests, %d succeeded and %d failed.\n",
 
282
                             suite->stats.cases, suite->stats.aborts,
 
283
                             suite->stats.done,
 
284
                             suite->stats.succ, suite->stats.fail));
 
285
}
 
286
 
 
287
static int tst_count SCM_UNUSED;
 
288
 
 
289
static const char *tst_name(const char *testcase_desc, int serial) SCM_UNUSED;
 
290
 
 
291
static const char *
 
292
tst_name(const char *testcase_desc, int serial)
 
293
{
 
294
    static char *name = NULL;
 
295
 
 
296
    free(name);
 
297
    name = tst_format("%s #%d", testcase_desc, serial);
 
298
 
 
299
    return name;
 
300
}
 
301
 
 
302
 
 
303
#endif /* !defined (TST_EXCLUDE_THIS) */
 
304
 
 
305
 
 
306
 
 
307
/* ------------------------------
 
308
 * Tests
 
309
 */
 
310
#define TST_LOG(msg)  TST_SUITE_INFO->logger(TST_SUITE_INFO,    \
 
311
                                             TST_CASE_INFO,     \
 
312
                                             msg)
 
313
#define TST_FAIL(msg) (++TST_CASE_INFO->done,   \
 
314
                       ++TST_CASE_INFO->fail,   \
 
315
                       TST_LOG(msg),            \
 
316
                       TST_FAILED = 1,          \
 
317
                       0)
 
318
#define TST_SUCC()    (++TST_CASE_INFO->done,   \
 
319
                       ++TST_CASE_INFO->succ,   \
 
320
                       TST_FAILED = 0,          \
 
321
                       1)
 
322
 
 
323
#define TST_NAME() (tst_name(TST_CASE_INFO->desc, TST_CASE_INFO->done + 1))
 
324
 
 
325
#define TST_ABORT()   do { TST_CASE_INFO->abortp = 1; return; } while (0)
 
326
 
 
327
#define TST_ASSERT(cond) if (!(cond)) TST_ABORT()
 
328
 
 
329
#define TST_COND(cond, desc)                            \
 
330
    (((cond)                                            \
 
331
      ||                                                \
 
332
      TST_FAIL(tst_format(__FILE__ ":%d: %s failed.\n", \
 
333
                          __LINE__, desc)))             \
 
334
     && TST_SUCC())
 
335
 
 
336
#define TST_TRUE(exp, desc)  TST_COND((exp), desc)
 
337
#define TST_FALSE(exp, desc) TST_COND(!(exp), desc)
 
338
 
 
339
#define TST_EQUALITY(eqp, type, fmt, expect, actual, desc)      \
 
340
do {                                                            \
 
341
    type _x = (expect);                                         \
 
342
    type _a = (actual);                                         \
 
343
    if (!eqp(_x, _a)) {                                         \
 
344
        TST_FAIL(tst_format(__FILE__ ":%d: %s failed.\n"        \
 
345
                            "  expected: " fmt "\n"             \
 
346
                            "  but got : " fmt "\n",            \
 
347
                            __LINE__, desc, _x, _a));           \
 
348
    } else {                                                    \
 
349
        TST_SUCC();                                             \
 
350
    }                                                           \
 
351
} while (0)
 
352
 
 
353
/* Comparators. */
 
354
#define TST_C_EQUAL(a, b)    ((a) == (b))
 
355
#define TST_STR_EQUAL(a, b)  (!strcmp((a), (b)))
 
356
 
 
357
 
 
358
/* Equality tests. */
 
359
#if HAVE_INTMAX_T
 
360
#define TST_EQ_INT(x, a, desc)  TST_EQUALITY(TST_C_EQUAL, intmax_t, \
 
361
                                             "%jd", x, a, desc)
 
362
#define TST_EQ_UINT(x, a, desc) TST_EQUALITY(TST_C_EQUAL, uintmax_t, \
 
363
                                             "%ju", x, a, desc)
 
364
#define TST_NEQ_INT(x, a, desc)  TST_EQUALITY(!TST_C_EQUAL, intmax_t, \
 
365
                                              "%jd", x, a, desc)
 
366
#define TST_NEQ_UINT(x, a, desc) TST_EQUALITY(!TST_C_EQUAL, uintmax_t, \
 
367
                                              "%ju", x, a, desc)
 
368
#else  /* not have intmax_t */
 
369
#define TST_EQ_INT(x, a, desc)  TST_EQUALITY(TST_C_EQUAL, long, \
 
370
                                             "%ld", x, a, desc)
 
371
#define TST_EQ_UINT(x, a, desc) TST_EQUALITY(TST_C_EQUAL, unsigned long, \
 
372
                                             "%lu", x, a, desc)
 
373
#define TST_NEQ_INT(x, a, desc)  TST_EQUALITY(!TST_C_EQUAL, long, \
 
374
                                             "%ld", x, a, desc)
 
375
#define TST_NEQ_UINT(x, a, desc) TST_EQUALITY(!TST_C_EQUAL, unsigned long, \
 
376
                                             "%lu", x, a, desc)
 
377
#endif /* not have intmax_t */
 
378
 
 
379
#define TST_EQ_STR(x, a, desc)  TST_EQUALITY(TST_STR_EQUAL, char*,      \
 
380
                                             "%s", x, a, desc)
 
381
#define TST_NEQ_STR(x, a, desc)  TST_EQUALITY(!TST_STR_EQUAL, char*,    \
 
382
                                              "%s", x, a, desc)
 
383
#define TST_EQ_PTR(x, a, desc)  TST_EQUALITY(TST_C_EQUAL, void*,        \
 
384
                                             "%p", x, a, desc)
 
385
#define TST_NEQ_PTR(x, a, desc)  TST_EQUALITY(!TST_C_EQUAL, void*,      \
 
386
                                              "%p", x, a, desc)
 
387
#define TST_EQ_OBJ(x, a, desc)  TST_EQUALITY(SCM_EQ, scm_uintobj_t,     \
 
388
                                             "%lx", (scm_uintobj_t)x,   \
 
389
                                             (scm_uintobj_t)a, desc)
 
390
#define TST_NEQ_OBJ(x, a, desc)  TST_EQUALITY(!SCM_EQ, scm_uintobj_t,   \
 
391
                                              "%lx", (scm_uintobj_t)x,  \
 
392
                                              (scm_uintobj_t)a, desc)
 
393
 
 
394
/* Function pointers are a bit tricky. The '0UL' is needed to suppress warnings
 
395
 * on 64-bit env. */
 
396
typedef void (*tst_funcptr_t)();
 
397
#define TST_EQ_FPTR(x, a, desc)                                              \
 
398
    TST_EQUALITY(TST_C_EQUAL, tst_funcptr_t, "%p",                           \
 
399
                 (0 ? (tst_funcptr_t)(0UL | ((x) == (a))) /* Typecheck */    \
 
400
                    : (tst_funcptr_t)(x)),                                   \
 
401
                 (tst_funcptr_t)(a), desc)
 
402
 
 
403
#define TST_NEQ_FPTR(x, a, desc)                                             \
 
404
    TST_EQUALITY(!TST_C_EQUAL, tst_funcptr_t, "%p",                          \
 
405
                 (0 ? (tst_funcptr_t)(0UL | ((x) == (a))) /* Typecheck */    \
 
406
                    : (tst_funcptr_t)(x)),                                   \
 
407
                 (tst_funcptr_t)(a), desc)
 
408
 
 
409
#define TST_EQ  TST_EQ_OBJ
 
410
#define TST_NEQ TST_NEQ_OBJ
 
411
 
 
412
 
 
413
/* tests with auto-generated description */
 
414
#define TST_TN_SAVE   (tst_count = TST_CASE_INFO->done + 1)
 
415
#define TST_TN_NAME() (tst_name(TST_CASE_INFO->desc, tst_count))
 
416
 
 
417
/* Since TST_FOO(..., tst_name(TST_CASE_INFO->desc, TST_CASE_INFO->done + 1))
 
418
 * returns incorrect serial number, it is saved before evaluating
 
419
 * TST_FAIL() or TST_SUCC(). */
 
420
#define TST_TN_TRUE(exp)      TST_TN_SAVE; TST_TRUE((exp), TST_TN_NAME())
 
421
#define TST_TN_FALSE(exp)     TST_TN_SAVE; TST_FALSE((exp), TST_TN_NAME())
 
422
#define TST_TN_EQ_INT(x, a)   TST_TN_SAVE; TST_EQ_INT((x), (a), TST_TN_NAME())
 
423
#define TST_TN_EQ_UINT(x, a)  TST_TN_SAVE; TST_EQ_UINT((x), (a), TST_TN_NAME())
 
424
#define TST_TN_NEQ_INT(x, a)  TST_TN_SAVE; TST_NEQ_INT((x), (a), TST_TN_NAME())
 
425
#define TST_TN_NEQ_UINT(x, a) TST_TN_SAVE; TST_NEQ_UINT((x), (a), TST_TN_NAME())
 
426
#define TST_TN_EQ_STR(x, a)   TST_TN_SAVE; TST_EQ_STR((x), (a), TST_TN_NAME())
 
427
#define TST_TN_NEQ_STR(x, a)  TST_TN_SAVE; TST_NEQ_STR((x), (a), TST_TN_NAME())
 
428
#define TST_TN_EQ_PTR(x, a)   TST_TN_SAVE; TST_EQ_PTR((x), (a), TST_TN_NAME())
 
429
#define TST_TN_NEQ_PTR(x, a)  TST_TN_SAVE; TST_NEQ_PTR((x), (a), TST_TN_NAME())
 
430
#define TST_TN_EQ_OBJ(x, a)   TST_TN_SAVE; TST_EQ_OBJ((x), (a), TST_TN_NAME())
 
431
#define TST_TN_NEQ_OBJ(x, a)  TST_TN_SAVE; TST_NEQ_OBJ((x), (a), TST_TN_NAME())
 
432
#define TST_TN_EQ_FPTR(x, a)  TST_TN_SAVE; TST_EQ_FPTR((x), (a), TST_TN_NAME())
 
433
#define TST_TN_NEQ_FPTR(x, a) TST_TN_SAVE; TST_NEQ_FPTR((x), (a), TST_TN_NAME())
 
434
#define TST_TN_EQ  TST_TN_EQ_OBJ
 
435
#define TST_TN_NEQ TST_TN_NEQ_OBJ
 
436
 
 
437
#endif /* !def SSCM_TEST_H */