| 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 |  | 
|---|