1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #ifndef RUNTIME_PLATFORM_ASSERT_H_ |
6 | #define RUNTIME_PLATFORM_ASSERT_H_ |
7 | |
8 | #include "platform/globals.h" |
9 | #include "platform/memory_sanitizer.h" |
10 | |
11 | #if !defined(DEBUG) && !defined(NDEBUG) |
12 | #error neither DEBUG nor NDEBUG defined |
13 | #elif defined(DEBUG) && defined(NDEBUG) |
14 | #error both DEBUG and NDEBUG defined |
15 | #endif |
16 | |
17 | // TODO(5411406): include sstream for now, once we have a Utils::toString() |
18 | // implemented for all the primitive types we can replace the usage of |
19 | // sstream by Utils::toString() |
20 | #if defined(DEBUG) || defined(TESTING) |
21 | #include <sstream> |
22 | #include <string> |
23 | #endif |
24 | |
25 | namespace dart { |
26 | |
27 | class DynamicAssertionHelper { |
28 | public: |
29 | DynamicAssertionHelper(const char* file, int line) |
30 | : file_(file), line_(line) {} |
31 | |
32 | protected: |
33 | void Print(const char* format, va_list arguments); |
34 | |
35 | const char* const file_; |
36 | const int line_; |
37 | |
38 | DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicAssertionHelper); |
39 | }; |
40 | |
41 | class Assert : public DynamicAssertionHelper { |
42 | public: |
43 | Assert(const char* file, int line) : DynamicAssertionHelper(file, line) {} |
44 | |
45 | DART_NORETURN void Fail(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); |
46 | |
47 | template <typename T> |
48 | T NotNull(const T p); |
49 | }; |
50 | |
51 | class Expect : public DynamicAssertionHelper { |
52 | public: |
53 | Expect(const char* file, int line) : DynamicAssertionHelper(file, line) {} |
54 | |
55 | void Fail(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); |
56 | |
57 | #if defined(TESTING) |
58 | template <typename E, typename A> |
59 | void Equals(const E& expected, const A& actual); |
60 | |
61 | template <typename E, typename A> |
62 | void NotEquals(const E& not_expected, const A& actual); |
63 | |
64 | template <typename E, typename A, typename T> |
65 | void FloatEquals(const E& expected, const A& actual, const T& tol); |
66 | |
67 | void StringEquals(const char* expected, const char* actual); |
68 | |
69 | void IsSubstring(const char* needle, const char* haystack); |
70 | |
71 | void IsNotSubstring(const char* needle, const char* haystack); |
72 | |
73 | template <typename E, typename A> |
74 | void LessThan(const E& left, const A& right); |
75 | |
76 | template <typename E, typename A> |
77 | void LessEqual(const E& left, const A& right); |
78 | |
79 | template <typename E, typename A> |
80 | void GreaterThan(const E& left, const A& right); |
81 | |
82 | template <typename E, typename A> |
83 | void GreaterEqual(const E& left, const A& right); |
84 | |
85 | template <typename T> |
86 | void NotNull(const T p); |
87 | |
88 | template <typename T> |
89 | void Null(const T p); |
90 | #endif |
91 | |
92 | static bool failed() { return failed_; } |
93 | |
94 | private: |
95 | static bool failed_; |
96 | }; |
97 | |
98 | template <typename T> |
99 | T Assert::NotNull(const T p) { |
100 | if (p != NULL) return p; |
101 | Fail("expected: not NULL, found NULL" ); |
102 | return NULL; |
103 | } |
104 | |
105 | #if defined(TESTING) |
106 | // Only allow the expensive (with respect to code size) assertions |
107 | // in testing code. |
108 | template <typename E, typename A> |
109 | void Expect::Equals(const E& expected, const A& actual) { |
110 | if (actual == expected) return; |
111 | std::ostringstream ess, ass; |
112 | ess << expected; |
113 | ass << actual; |
114 | std::string es = ess.str(), as = ass.str(); |
115 | Fail("expected: <%s> but was: <%s>" , es.c_str(), as.c_str()); |
116 | } |
117 | |
118 | template <typename E, typename A> |
119 | void Expect::NotEquals(const E& not_expected, const A& actual) { |
120 | if (actual != not_expected) return; |
121 | std::ostringstream ness; |
122 | ness << not_expected; |
123 | std::string nes = ness.str(); |
124 | Fail("did not expect: <%s>" , nes.c_str()); |
125 | } |
126 | |
127 | template <typename E, typename A, typename T> |
128 | void Expect::FloatEquals(const E& expected, const A& actual, const T& tol) { |
129 | if (((expected - tol) <= actual) && (actual <= (expected + tol))) { |
130 | return; |
131 | } |
132 | std::ostringstream ess, ass, tolss; |
133 | ess << expected; |
134 | ass << actual; |
135 | tolss << tol; |
136 | std::string es = ess.str(), as = ass.str(), tols = tolss.str(); |
137 | Fail("expected: <%s> but was: <%s> (tolerance: <%s>)" , es.c_str(), as.c_str(), |
138 | tols.c_str()); |
139 | } |
140 | |
141 | inline void Expect::StringEquals(const char* expected, const char* actual) { |
142 | if (strcmp(expected, actual) == 0) return; |
143 | Fail("expected:\n<\"%s\">\nbut was:\n<\"%s\">" , expected, actual); |
144 | } |
145 | |
146 | inline void Expect::IsSubstring(const char* needle, const char* haystack) { |
147 | if (strstr(haystack, needle) != nullptr) return; |
148 | Fail("expected <\"%s\"> to be a substring of <\"%s\">" , needle, haystack); |
149 | } |
150 | |
151 | inline void Expect::IsNotSubstring(const char* needle, const char* haystack) { |
152 | if (strstr(haystack, needle) == nullptr) return; |
153 | Fail("expected <\"%s\"> to not be a substring of <\"%s\">" , needle, haystack); |
154 | } |
155 | |
156 | template <typename E, typename A> |
157 | void Expect::LessThan(const E& left, const A& right) { |
158 | if (left < right) return; |
159 | std::ostringstream ess, ass; |
160 | ess << left; |
161 | ass << right; |
162 | std::string es = ess.str(), as = ass.str(); |
163 | Fail("expected: %s < %s" , es.c_str(), as.c_str()); |
164 | } |
165 | |
166 | template <typename E, typename A> |
167 | void Expect::LessEqual(const E& left, const A& right) { |
168 | if (left <= right) return; |
169 | std::ostringstream ess, ass; |
170 | ess << left; |
171 | ass << right; |
172 | std::string es = ess.str(), as = ass.str(); |
173 | Fail("expected: %s <= %s" , es.c_str(), as.c_str()); |
174 | } |
175 | |
176 | template <typename E, typename A> |
177 | void Expect::GreaterThan(const E& left, const A& right) { |
178 | if (left > right) return; |
179 | std::ostringstream ess, ass; |
180 | ess << left; |
181 | ass << right; |
182 | std::string es = ess.str(), as = ass.str(); |
183 | Fail("expected: %s > %s" , es.c_str(), as.c_str()); |
184 | } |
185 | |
186 | template <typename E, typename A> |
187 | void Expect::GreaterEqual(const E& left, const A& right) { |
188 | if (left >= right) return; |
189 | std::ostringstream ess, ass; |
190 | ess << left; |
191 | ass << right; |
192 | std::string es = ess.str(), as = ass.str(); |
193 | Fail("expected: %s >= %s" , es.c_str(), as.c_str()); |
194 | } |
195 | |
196 | template <typename T> |
197 | void Expect::NotNull(const T p) { |
198 | if (p != NULL) return; |
199 | Fail("expected: not NULL, found NULL" ); |
200 | } |
201 | |
202 | template <typename T> |
203 | void Expect::Null(const T p) { |
204 | if (p == nullptr) return; |
205 | Fail("expected: nullptr, found not null pointer" ); |
206 | } |
207 | #endif |
208 | |
209 | } // namespace dart |
210 | |
211 | #define FATAL(error) dart::Assert(__FILE__, __LINE__).Fail("%s", error) |
212 | |
213 | #define FATAL1(format, p1) dart::Assert(__FILE__, __LINE__).Fail(format, (p1)) |
214 | |
215 | #define FATAL2(format, p1, p2) \ |
216 | dart::Assert(__FILE__, __LINE__).Fail(format, (p1), (p2)) |
217 | |
218 | #define FATAL3(format, p1, p2, p3) \ |
219 | dart::Assert(__FILE__, __LINE__).Fail(format, (p1), (p2), (p3)) |
220 | |
221 | #define UNIMPLEMENTED() FATAL("unimplemented code") |
222 | |
223 | #define UNREACHABLE() FATAL("unreachable code") |
224 | |
225 | #define OUT_OF_MEMORY() FATAL("Out of memory.") |
226 | |
227 | #if defined(DEBUG) |
228 | // DEBUG binaries use assertions in the code. |
229 | // Note: We wrap the if statement in a do-while so that we get a compile |
230 | // error if there is no semicolon after ASSERT(condition). This |
231 | // ensures that we get the same behavior on DEBUG and RELEASE builds. |
232 | |
233 | #define ASSERT(cond) \ |
234 | do { \ |
235 | if (!(cond)) dart::Assert(__FILE__, __LINE__).Fail("expected: %s", #cond); \ |
236 | } while (false) |
237 | |
238 | #define ASSERT_EQUAL(actual, expected) \ |
239 | do { \ |
240 | if ((expected) != (actual)) { \ |
241 | const std::string actual_str = std::to_string(actual); \ |
242 | const std::string expected_str = std::to_string(expected); \ |
243 | dart::Assert(__FILE__, __LINE__) \ |
244 | .Fail("expected \"%s\" = %s, actual \"%s\" = %s", #expected, \ |
245 | expected_str.c_str(), #actual, actual_str.c_str()); \ |
246 | } \ |
247 | } while (false) |
248 | |
249 | // DEBUG_ASSERT allows identifiers in condition to be undeclared in release |
250 | // mode. |
251 | #define DEBUG_ASSERT(cond) ASSERT(cond) |
252 | |
253 | // Returns 'ptr'; useful for initializer lists: |
254 | // class Foo { Foo(int* ptr) : ptr_(ASSERT_NOTNULL(ptr)) ... |
255 | #define ASSERT_NOTNULL(ptr) dart::Assert(__FILE__, __LINE__).NotNull((ptr)) |
256 | |
257 | #else // if defined(DEBUG) |
258 | |
259 | // In order to avoid variable unused warnings for code that only uses |
260 | // a variable in an ASSERT or EXPECT, we make sure to use the macro |
261 | // argument. |
262 | #define ASSERT(condition) \ |
263 | do { \ |
264 | } while (false && (condition)) |
265 | |
266 | #define ASSERT_EQUAL(expected, actual) \ |
267 | do { \ |
268 | } while (false && (expected) != (actual)) |
269 | |
270 | #define DEBUG_ASSERT(cond) |
271 | |
272 | #define ASSERT_NOTNULL(ptr) (ptr) |
273 | |
274 | #endif // if defined(DEBUG) |
275 | |
276 | #define RELEASE_ASSERT(cond) \ |
277 | do { \ |
278 | if (!(cond)) dart::Assert(__FILE__, __LINE__).Fail("expected: %s", #cond); \ |
279 | } while (false) |
280 | |
281 | #define COMPILE_ASSERT(expr) static_assert(expr, "") |
282 | |
283 | #if defined(TESTING) |
284 | |
285 | // EXPECT and FAIL are equivalent to ASSERT and FATAL except that they do not |
286 | // cause early termination of the unit test. This allows testing to proceed |
287 | // further to be able to report other failures before reporting the overall |
288 | // unit tests as failing. |
289 | |
290 | #define EXPECT(condition) \ |
291 | if (!(condition)) { \ |
292 | dart::Expect(__FILE__, __LINE__).Fail("expected: %s", #condition); \ |
293 | } |
294 | |
295 | #define EXPECT_EQ(expected, actual) \ |
296 | dart::Expect(__FILE__, __LINE__).Equals((expected), (actual)) |
297 | |
298 | #define EXPECT_NE(not_expected, actual) \ |
299 | dart::Expect(__FILE__, __LINE__).NotEquals((not_expected), (actual)) |
300 | |
301 | #define EXPECT_FLOAT_EQ(expected, actual, tol) \ |
302 | dart::Expect(__FILE__, __LINE__).FloatEquals((expected), (actual), (tol)) |
303 | |
304 | #define EXPECT_STREQ(expected, actual) \ |
305 | dart::Expect(__FILE__, __LINE__).StringEquals((expected), (actual)) |
306 | |
307 | #define EXPECT_SUBSTRING(needle, haystack) \ |
308 | dart::Expect(__FILE__, __LINE__).IsSubstring((needle), (haystack)) |
309 | |
310 | #define EXPECT_NOTSUBSTRING(needle, haystack) \ |
311 | dart::Expect(__FILE__, __LINE__).IsNotSubstring((needle), (haystack)) |
312 | |
313 | #define EXPECT_LT(left, right) \ |
314 | dart::Expect(__FILE__, __LINE__).LessThan((left), (right)) |
315 | |
316 | #define EXPECT_LE(left, right) \ |
317 | dart::Expect(__FILE__, __LINE__).LessEqual((left), (right)) |
318 | |
319 | #define EXPECT_GT(left, right) \ |
320 | dart::Expect(__FILE__, __LINE__).GreaterThan((left), (right)) |
321 | |
322 | #define EXPECT_GE(left, right) \ |
323 | dart::Expect(__FILE__, __LINE__).GreaterEqual((left), (right)) |
324 | |
325 | #define EXPECT_NOTNULL(ptr) dart::Expect(__FILE__, __LINE__).NotNull((ptr)) |
326 | |
327 | #define EXPECT_NULLPTR(ptr) dart::Expect(__FILE__, __LINE__).Null((ptr)) |
328 | |
329 | #define FAIL(error) dart::Expect(__FILE__, __LINE__).Fail("%s", error) |
330 | |
331 | #define FAIL1(format, p1) dart::Expect(__FILE__, __LINE__).Fail(format, (p1)) |
332 | |
333 | #define FAIL2(format, p1, p2) \ |
334 | dart::Expect(__FILE__, __LINE__).Fail(format, (p1), (p2)) |
335 | |
336 | #endif // defined(TESTING) |
337 | |
338 | #endif // RUNTIME_PLATFORM_ASSERT_H_ |
339 | |