forked from asmjit/asmjit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
broken.h
145 lines (118 loc) · 3.99 KB
/
broken.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// [Broken]
// Lightweight Unit Testing for C++.
//
// [License]
// Public Domain (Unlicense)
// [Guard]
#ifndef BROKEN_INTERNAL_H
#define BROKEN_INTERNAL_H
// [Dependencies]
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ============================================================================
// [Broken - Detection]
// ============================================================================
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
# if (__GNUC__ * 1000 + __GNUC_MINOR__) >= 3004
# define BROKEN_NOINLINE __attribute__((__noinline__))
# endif
#elif defined(__clang__)
# if __has_attribute(__noinline__)
# define BROKEN_NOINLINE __attribute__((__noinline__))
# endif
#elif defined(_MSC_VER)
# define __declspec(noinline)
#endif
#if !defined(BROKEN_NOINLINE)
# define BROKEN_NOINLINE
#endif
// Hide everything when using Doxygen. Ideally this can be protected by a macro,
// but there is not globally and widely used one across multiple projects.
//! \internal
//! \{
// ============================================================================
// [Broken - API]
// ============================================================================
struct BrokenAPI {
//! Entry point of a unit test defined by `UNIT` macro.
typedef void (*Entry)(void);
//! Test defined by `UNIT` macro.
struct Unit {
const char* name;
Entry entry;
size_t finished;
Unit* next;
};
//! Automatic unit registration by using static initialization.
struct AutoUnit : Unit {
inline AutoUnit(const char* _name, Entry _entry) {
name = _name;
entry = _entry;
finished = false;
next = NULL;
BrokenAPI::add(this);
}
};
//! Register a new unit test (called automatically by `AutoUnit` and `UNIT`).
static void add(Unit* unit);
//! Set output file to a `file`.
static void setOutputFile(FILE* file);
//! Set the current context to `file` and `line`.
//!
//! This is called by `EXPECT` macro to set the correct `file` and `line`,
//! because `EXPECT` macro internally calls `expect()` function, which does
//! change the original file & line to non-interesting `broken.h`.
static int setContext(const char* file, int line);
//! Initialize `Broken` framework.
//!
//! Returns `true` if `run()` should be called.
static int run(int argc, const char* argv[],
Entry onBeforeRun = (Entry)NULL,
Entry onAfterRun = (Entry)NULL);
//! Used internally by `EXPECT` macro.
template<typename T>
BROKEN_NOINLINE static int expect(const T& exp, const char* fmt = NULL, ...) {
if (exp)
return 1;
va_list ap;
va_start(ap, fmt);
fail(fmt, ap);
va_end(ap);
return 0;
}
//! Log message, adds automatically new line if not present.
static int info(const char* fmt, ...);
//! Called on `EXPECT()` failure.
static int fail(const char* fmt, va_list ap);
};
// ============================================================================
// [Broken - Macros]
// ============================================================================
//! Define a unit test.
//!
//! `_Name_` can only contain ASCII characters, numbers and underscore. It has
//! the same rules as identifiers in C and C++.
#define UNIT(_Name_) \
static void unit_##_Name_##_entry(void); \
\
static ::BrokenAPI::AutoUnit unit_##_Name_##_autoinit( \
#_Name_, unit_##_Name_##_entry); \
\
static void unit_##_Name_##_entry(void)
//! #define INFO(...)
//!
//! Informative message printed to `stdout`.
#define INFO ::BrokenAPI::setContext(__FILE__, __LINE__) && ::BrokenAPI::info
//! #define INFO(_Exp_ [, _Format_ [, ...]])
//!
//! Expect `_Exp_` to be true or evaluates to true, fail otherwise.
#define EXPECT ::BrokenAPI::setContext(__FILE__, __LINE__) && ::BrokenAPI::expect
// ============================================================================
// [Broken - Cleanup]
// ============================================================================
#undef BROKEN_NOINLINE
//! \}
// [Guard]
#endif // BROKEN_INTERNAL_H