source: branches/profile/UNIT_TESTER/test_global.h

Last change on this file was 12153, checked in by westram, 10 years ago
  • as we depend on glib now
    • use G_BREAKPOINT instead of SEGV to trigger assertions
    • continue using ARB_SIGSEGV
      • from inside unittests
      • when SIMPLE_ARB_ASSERT is defined
File size: 7.7 KB
Line 
1// ================================================================= //
2//                                                                   //
3//   File      : test_global.h                                       //
4//   Purpose   : special assertion handling if arb is compiled       //
5//               with unit-tests                                     //
6//                                                                   //
7//   Coded by Ralf Westram (coder@reallysoft.de) in September 2010   //
8//   Institute of Microbiology (Technical University Munich)         //
9//   http://www.arb-home.de/                                         //
10//                                                                   //
11// ================================================================= //
12
13#ifndef TEST_GLOBAL_H
14#define TEST_GLOBAL_H
15
16// do not include here - just test
17// insert includes at ../INCLUDE/arb_assert.h@WhyIncludeHere
18#ifndef _STDARG_H
19#ifndef __STDARG_H
20#error Need cstdarg included
21#endif
22#endif
23#if !defined(_STDIO_H) && !defined(_STDIO_H_)
24#error Need cstdio included
25#endif
26#if !defined(_STDLIB_H) && !defined(_STDLIB_H_)
27#error Need cstdlib included
28#endif
29#if !defined(_ERRNO_H) && !defined(_SYS_ERRNO_H_)
30#error Need cerrno included
31#endif
32#if !defined(_STRING_H) && !defined(_STRING_H_)
33#error Need cstring included
34#endif
35
36#ifdef UNIT_TESTS
37
38# if defined(DEVEL_RELEASE)
39#  error Unit testing not allowed in release
40# endif
41
42# ifdef __cplusplus
43
44#  define SET_ASSERTION_FAILED_FLAG() arb_test::test_data().assertion_failed = true 
45#  define PRINT_ASSERTION_FAILED_MSG(cond) arb_test::GlobalTestData::assertfailmsg(__FILE__, __LINE__, #cond) 
46
47# else
48#  define SET_ASSERTION_FAILED_FLAG() // impossible in C (assertions in C code will be handled like normal SEGV)
49#  define PRINT_ASSERTION_FAILED_MSG(cond)                      \
50    do {                                                        \
51        fflush(stdout);                                         \
52        fflush(stderr);                                         \
53        fprintf(stderr, "%s:%i: Assertion '%s' failed [C]\n",   \
54                __FILE__, __LINE__, #cond);                     \
55        fflush(stderr);                                         \
56    } while(0)
57# endif
58
59#define SEGV_INSIDE_TEST_STOP_OTHERWISE(backtrace)              \
60    do {                                                        \
61        if (RUNNING_TEST()) {                                   \
62            ARB_SIGSEGV(backtrace);                             \
63        }                                                       \
64        else {                                                  \
65            ARB_STOP(backtrace);                                \
66        }                                                       \
67    } while(0)
68
69# define TRIGGER_ASSERTION(backtrace)                           \
70    do {                                                        \
71        SET_ASSERTION_FAILED_FLAG();                            \
72        SEGV_INSIDE_TEST_STOP_OTHERWISE(backtrace);             \
73    } while(0)
74
75namespace arb_test {
76    class FlushedOutputNoLF {
77        inline void flushall() { fflush(stdout); fflush(stderr); }
78    public:
79        FlushedOutputNoLF() { flushall(); }
80        ~FlushedOutputNoLF() { flushall(); }
81    };
82    struct FlushedOutput : public FlushedOutputNoLF {
83        ~FlushedOutput() { fputc('\n', stderr); }
84    };
85
86    enum FlagAction {
87        FLAG_RAISE,
88        FLAG_IS_RAISED,
89    };
90
91    inline const char *fakeenv(const char *var) {
92        // override some environment variables for unittests
93        if (strcmp(var, "HOME") == 0) return "./homefake"; // normally should be $ARBHOME/UNIT_TESTER/run/homefake
94        return NULL;
95    }
96
97
98    class GlobalTestData {
99        typedef bool (*FlagCallback)(FlagAction action, const char *name);
100
101        FlagCallback flag_cb;
102
103        GlobalTestData()
104            : flag_cb(NULL),
105              annotation(NULL),
106              show_warnings(true),
107              assertion_failed(false),
108              running_test(false),
109              warnings(0)
110        {}
111        ~GlobalTestData() {
112            unannotate();
113        }
114        GlobalTestData(const GlobalTestData&); // do not synthesize
115        GlobalTestData& operator=(const GlobalTestData&); // do not synthesize
116
117        static GlobalTestData *instance(bool erase) {
118            static GlobalTestData *data = 0;             // singleton
119            if (erase) {
120                delete data;
121                data = 0;
122            }
123            else if (!data) {
124                static int allocation_count = 0;
125                arb_assert(allocation_count == 0); // allocating GlobalTestData twice is a bug!
126                allocation_count++;
127
128                data = new GlobalTestData;
129            }
130            return data;
131        }
132
133        char *annotation; // shown in assertion-failure message
134
135        void unannotate() {
136            free(annotation);
137            annotation = NULL;
138        }
139
140    public:
141        bool show_warnings;
142        bool assertion_failed;
143        bool running_test;
144        bool entered_mutex_loop; // helper to avoid race-condition
145
146        // counters
147        size_t warnings;
148
149        void raiseLocalFlag(const char *name) const {
150            if (flag_cb) {
151                flag_cb(FLAG_RAISE, name);
152            }
153            else {
154                fputs("cannot raise local flag (called from outside test-code?)\n", stderr);
155            }
156        }
157        void init(FlagCallback fc) { flag_cb = fc; }
158
159        bool not_covered_by_test() const { return !running_test; }
160
161        static GlobalTestData& get_instance() { return *instance(false); }
162        static void erase_instance() { instance(true); }
163
164        void annotate(const char *annotation_) {
165            unannotate();
166            annotation = annotation_ ? strdup(annotation_) : NULL;
167        }
168        const char *get_annotation() const { return annotation; }
169
170        static void print_annotation() {
171            char*& annotation = get_instance().annotation;
172            if (annotation) fprintf(stderr, " (%s)", annotation);
173        }
174
175        static void assertfailmsg(const char *filename, int lineno, const char *condition) {
176            FlushedOutput yes;
177            fprintf(stderr, "%s:%i: Assertion '%s' failed", filename, lineno, condition);
178            print_annotation();
179        }
180    };
181
182    inline GlobalTestData& test_data() { return GlobalTestData::get_instance(); }
183};
184
185// --------------------------------------------------------------------------------
186
187#define TEST_ANNOTATE(annotation) arb_test::test_data().annotate(annotation)
188#define RUNNING_TEST()            arb_test::test_data().running_test
189
190// special assert for unit tests (additionally to SEGV it sets a global flag)
191#define test_assert(cond,backtrace)             \
192    do {                                        \
193        if (!(cond)) {                          \
194            PRINT_ASSERTION_FAILED_MSG(cond);   \
195            TRIGGER_ASSERTION(backtrace);       \
196        }                                       \
197    } while(0)
198
199// Redefine arb_assert with test_assert when compiling for unit tests.
200//
201// Always request a backtrace because these assertions are unexpected and
202// might require to recompile tests w/o deadlockguard just to determine
203// the callers (using a debugger).
204
205# if defined(ASSERTION_USED)
206#  undef arb_assert
207#  define arb_assert(cond) test_assert(cond, true)
208# endif
209
210#define UNCOVERED() test_assert(arb_test::test_data().not_covered_by_test(), false)
211// the opposite (i.e. COVERED()) would be quite nice, but is not trivial or even impossible
212
213#else // !UNIT_TESTS
214#error test_global.h may only be included if UNIT_TESTS is defined
215#endif
216
217#else
218#error test_global.h included twice
219#endif // TEST_GLOBAL_H
Note: See TracBrowser for help on using the repository browser.