source: tags/old_import_filter/UNIT_TESTER/test_global.h

Last change on this file was 8616, checked in by westram, 12 years ago

merge from e4fix [8190] [8196] [8198] [8197] [8199] [8221] [8226]

  • callallcallbacks
    • allow repeated calls for all orders
    • avoid infinite descent into recursive filters
    • avoid config managers
  • fixes via callallcallbacks
    • some un-/over-handled errors
    • missing transaction
  • make
    • optionally keep preprocesser output
  • tests
    • only explain broken/wanted expectations if warning was shown
    • added TEST_EXPECT__BROKENIF
  • spelling
    • intervall → interval
File size: 6.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#ifndef _STDIO_H
24#error Need cstdio included
25#endif
26#ifndef _STDLIB_H
27#error Need cstdlib included
28#endif
29#ifndef _ERRNO_H
30#error Need cerrno included
31#endif
32#ifndef _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 TRIGGER_ASSERTION(backtrace)           \
60    do {                                        \
61        SET_ASSERTION_FAILED_FLAG();            \
62        ARB_SIGSEGV(backtrace);                 \
63    } while(0)
64
65namespace arb_test {
66    class FlushedOutputNoLF {
67        inline void flushall() { fflush(stdout); fflush(stderr); }
68    public:
69        FlushedOutputNoLF() { flushall(); }
70        ~FlushedOutputNoLF() { flushall(); }
71    };
72    struct FlushedOutput : public FlushedOutputNoLF {
73        ~FlushedOutput() { fputc('\n', stderr); }
74    };
75
76    enum FlagAction {
77        FLAG_RAISE,
78        FLAG_IS_RAISED,
79    };
80
81    class GlobalTestData {
82        typedef bool (*FlagCallback)(FlagAction action, const char *name);
83
84        FlagCallback flag_cb;
85
86        GlobalTestData()
87            : flag_cb(NULL),
88              annotation(NULL),
89              show_warnings(true),
90              assertion_failed(false),
91              running_test(false),
92              warnings(0)
93        {}
94        ~GlobalTestData() {
95            unannotate();
96        }
97        GlobalTestData(const GlobalTestData&); // do not synthesize
98        GlobalTestData& operator=(const GlobalTestData&); // do not synthesize
99
100        static GlobalTestData *instance(bool erase) {
101            static GlobalTestData *data = 0;             // singleton
102            if (erase) {
103                delete data;
104                data = 0;
105            }
106            else if (!data) {
107                static int allocation_count = 0;
108                arb_assert(allocation_count == 0); // allocating GlobalTestData twice is a bug!
109                allocation_count++;
110
111                data = new GlobalTestData;
112            }
113            return data;
114        }
115
116        char *annotation; // shown in assertion-failure message
117
118        void unannotate() {
119            free(annotation);
120            annotation = NULL;
121        }
122
123    public:
124        bool show_warnings;
125        bool assertion_failed;
126        bool running_test;
127        bool entered_mutex_loop; // helper to avoid race-condition
128
129        // counters
130        size_t warnings;
131
132        void raiseLocalFlag(const char *name) const {
133            if (flag_cb) {
134                flag_cb(FLAG_RAISE, name);
135            }
136            else {
137                fputs("cannot raise local flag (called from outside test-code?)\n", stderr);
138            }
139        }
140        void init(FlagCallback fc) { flag_cb = fc; }
141
142        bool not_covered_by_test() const { return !running_test; }
143
144        static GlobalTestData& get_instance() { return *instance(false); }
145        static void erase_instance() { instance(true); }
146
147        void annotate(const char *annotation_) {
148            unannotate();
149            annotation = annotation_ ? strdup(annotation_) : NULL;
150        }
151        const char *get_annotation() const { return annotation; }
152
153        static void print_annotation() {
154            char*& annotation = get_instance().annotation;
155            if (annotation) fprintf(stderr, " (%s)", annotation);
156        }
157
158        static void assertfailmsg(const char *filename, int lineno, const char *condition) {
159            FlushedOutput yes;
160            fprintf(stderr, "%s:%i: Assertion '%s' failed", filename, lineno, condition);
161            print_annotation();
162        }
163    };
164
165    inline GlobalTestData& test_data() { return GlobalTestData::get_instance(); }
166};
167
168// --------------------------------------------------------------------------------
169
170#define TEST_ANNOTATE_ASSERT(annotation) arb_test::test_data().annotate(annotation)
171#define RUNNING_TEST()                   arb_test::test_data().running_test
172
173// special assert for unit tests (additionally to SEGV it sets a global flag)
174#define test_assert(cond,backtrace)             \
175    do {                                        \
176        if (!(cond)) {                          \
177            PRINT_ASSERTION_FAILED_MSG(cond);   \
178            TRIGGER_ASSERTION(backtrace);       \
179        }                                       \
180    } while(0)
181
182// Redefine arb_assert with test_assert when compiling for unit tests.
183//
184// Always request a backtrace because these assertions are unexpected and
185// might require to recompile tests w/o deadlockguard just to determine
186// the callers (using a debugger).
187
188# if defined(ASSERTION_USED)
189#  undef arb_assert
190#  define arb_assert(cond) test_assert(cond, true)
191# endif
192
193#define UNCOVERED() test_assert(arb_test::test_data().not_covered_by_test(), false)
194// the opposite (i.e. COVERED()) would be quite nice, but is not trivial or even impossible
195
196#else // !UNIT_TESTS
197#error test_global.h may only be included if UNIT_TESTS is defined
198#endif
199
200#else
201#error test_global.h included twice
202#endif // TEST_GLOBAL_H
Note: See TracBrowser for help on using the repository browser.