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
25namespace dart {
26
27class 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
41class 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
51class 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
98template <typename T>
99T 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.
108template <typename E, typename A>
109void 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
118template <typename E, typename A>
119void 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
127template <typename E, typename A, typename T>
128void 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
141inline 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
146inline 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
151inline 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
156template <typename E, typename A>
157void 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
166template <typename E, typename A>
167void 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
176template <typename E, typename A>
177void 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
186template <typename E, typename A>
187void 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
196template <typename T>
197void Expect::NotNull(const T p) {
198 if (p != NULL) return;
199 Fail("expected: not NULL, found NULL");
200}
201
202template <typename T>
203void 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