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