1 /////////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 // 5 // This code is licensed under the MIT License (MIT). 6 // 7 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 // THE SOFTWARE. 14 // 15 /////////////////////////////////////////////////////////////////////////////// 16 17 #ifdef _MSC_VER 18 // blanket turn off warnings from CppCoreCheck from catch 19 // so people aren't annoyed by them when running the tool. 20 #pragma warning(disable : 26440 26426) // from catch 21 22 // Fix VS2015 build breaks in Release 23 #pragma warning(disable : 4702) // unreachable code 24 #endif 25 26 #include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_... 27 28 #include <gsl/pointers> // for not_null, operator<, operator<=, operator> 29 30 #include <algorithm> // for addressof 31 #include <memory> // for shared_ptr, make_shared, operator<, opera... 32 #include <sstream> // for operator<<, ostringstream, basic_ostream:... 33 #include <stdint.h> // for uint16_t 34 #include <string> // for basic_string, operator==, string, operator<< 35 #include <typeinfo> // for type_info 36 37 namespace gsl 38 { 39 struct fail_fast; 40 } // namespace gsl 41 42 using namespace gsl; 43 44 struct MyBase 45 { 46 }; 47 struct MyDerived : public MyBase 48 { 49 }; 50 struct Unrelated 51 { 52 }; 53 54 // stand-in for a user-defined ref-counted class 55 template <typename T> 56 struct RefCounted 57 { 58 RefCounted(T* p) : p_(p) {} 59 operator T*() { return p_; } 60 T* p_; 61 }; 62 63 // user defined smart pointer with comparison operators returning non bool value 64 template <typename T> 65 struct CustomPtr 66 { 67 CustomPtr(T* p) : p_(p) {} 68 operator T*() { return p_; } 69 bool operator!=(std::nullptr_t) const { return p_ != nullptr; } 70 T* p_ = nullptr; 71 }; 72 73 template <typename T, typename U> 74 std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 75 { 76 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 77 return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true" 78 : "false"; 79 } 80 81 template <typename T, typename U> 82 std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 83 { 84 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 85 return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true" 86 : "false"; 87 } 88 89 template <typename T, typename U> 90 std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 91 { 92 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 93 return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true" 94 : "false"; 95 } 96 97 template <typename T, typename U> 98 std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 99 { 100 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 101 return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true" 102 : "false"; 103 } 104 105 template <typename T, typename U> 106 std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 107 { 108 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 109 return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true" 110 : "false"; 111 } 112 113 template <typename T, typename U> 114 std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 115 { 116 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 117 return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true" 118 : "false"; 119 } 120 121 struct NonCopyableNonMovable 122 { 123 NonCopyableNonMovable() = default; 124 NonCopyableNonMovable(const NonCopyableNonMovable&) = delete; 125 NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete; 126 NonCopyableNonMovable(NonCopyableNonMovable&&) = delete; 127 NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; 128 }; 129 130 GSL_SUPPRESS(f.4) // NO-FORMAT: attribute 131 bool helper(not_null<int*> p) { return *p == 12; } 132 GSL_SUPPRESS(f.4) // NO-FORMAT: attribute 133 bool helper_const(not_null<const int*> p) { return *p == 12; } 134 135 int* return_pointer() { return nullptr; } 136 const int* return_pointer_const() { return nullptr; } 137 138 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 139 TEST_CASE("TestNotNullConstructors") 140 { 141 { 142 #ifdef CONFIRM_COMPILATION_ERRORS 143 not_null<int*> p = nullptr; // yay...does not compile! 144 not_null<std::vector<char>*> p1 = 0; // yay...does not compile! 145 not_null<int*> p2; // yay...does not compile! 146 std::unique_ptr<int> up = std::make_unique<int>(120); 147 not_null<int*> p3 = up; 148 149 // Forbid non-nullptr assignable types 150 not_null<std::vector<int>> f(std::vector<int>{1}); 151 not_null<int> z(10); 152 not_null<std::vector<int>> y({1, 2}); 153 #endif 154 } 155 156 { 157 // from shared pointer 158 int i = 12; 159 auto rp = RefCounted<int>(&i); 160 not_null<int*> p(rp); 161 CHECK(p.get() == &i); 162 163 not_null<std::shared_ptr<int>> x( 164 std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable 165 166 int* pi = nullptr; 167 CHECK_THROWS_AS(not_null<decltype(pi)>(pi), fail_fast); 168 } 169 170 { 171 // from pointer to local 172 int t = 42; 173 174 not_null<int*> x = &t; 175 helper(&t); 176 helper_const(&t); 177 178 CHECK(*x == 42); 179 } 180 181 { 182 // from raw pointer 183 // from not_null pointer 184 185 int t = 42; 186 int* p = &t; 187 188 not_null<int*> x = p; 189 helper(p); 190 helper_const(p); 191 helper(x); 192 helper_const(x); 193 194 CHECK(*x == 42); 195 } 196 197 { 198 // from raw const pointer 199 // from not_null const pointer 200 201 int t = 42; 202 const int* cp = &t; 203 204 not_null<const int*> x = cp; 205 helper_const(cp); 206 helper_const(x); 207 208 CHECK(*x == 42); 209 } 210 211 { 212 // from not_null const pointer, using auto 213 int t = 42; 214 const int* cp = &t; 215 216 auto x = not_null<const int*>{cp}; 217 218 CHECK(*x == 42); 219 } 220 221 { 222 // from returned pointer 223 224 CHECK_THROWS_AS(helper(return_pointer()), fail_fast); 225 CHECK_THROWS_AS(helper_const(return_pointer()), fail_fast); 226 } 227 } 228 229 template <typename T> 230 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 231 void ostream_helper(T v) 232 { 233 not_null<T*> p(&v); 234 { 235 std::ostringstream os; 236 std::ostringstream ref; 237 os << p; 238 ref << &v; 239 CHECK(os.str() == ref.str()); 240 } 241 { 242 std::ostringstream os; 243 std::ostringstream ref; 244 os << *p; 245 ref << v; 246 CHECK(os.str() == ref.str()); 247 } 248 } 249 250 TEST_CASE("TestNotNullostream") 251 { 252 ostream_helper<int>(17); 253 ostream_helper<float>(21.5f); 254 ostream_helper<double>(3.4566e-7); 255 ostream_helper<char>('c'); 256 ostream_helper<uint16_t>(0x0123u); 257 ostream_helper<const char*>("cstring"); 258 ostream_helper<std::string>("string"); 259 } 260 261 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 262 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 263 TEST_CASE("TestNotNullCasting") 264 { 265 MyBase base; 266 MyDerived derived; 267 Unrelated unrelated; 268 not_null<Unrelated*> u{&unrelated}; 269 (void) u; 270 not_null<MyDerived*> p{&derived}; 271 not_null<MyBase*> q(&base); 272 q = p; // allowed with heterogeneous copy ctor 273 CHECK(q == p); 274 275 #ifdef CONFIRM_COMPILATION_ERRORS 276 q = u; // no viable conversion possible between MyBase* and Unrelated* 277 p = q; // not possible to implicitly convert MyBase* to MyDerived* 278 279 not_null<Unrelated*> r = p; 280 not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p); 281 #endif 282 not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get())); 283 CHECK(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get())); 284 } 285 286 TEST_CASE("TestNotNullAssignment") 287 { 288 int i = 12; 289 not_null<int*> p(&i); 290 CHECK(helper(p)); 291 292 int* q = nullptr; 293 CHECK_THROWS_AS(p = not_null<int*>(q), fail_fast); 294 } 295 296 TEST_CASE("TestNotNullRawPointerComparison") 297 { 298 int ints[2] = {42, 43}; 299 int* p1 = &ints[0]; 300 const int* p2 = &ints[1]; 301 302 using NotNull1 = not_null<decltype(p1)>; 303 using NotNull2 = not_null<decltype(p2)>; 304 305 CHECK((NotNull1(p1) == NotNull1(p1)) == true); 306 CHECK((NotNull1(p1) == NotNull2(p2)) == false); 307 308 CHECK((NotNull1(p1) != NotNull1(p1)) == false); 309 CHECK((NotNull1(p1) != NotNull2(p2)) == true); 310 311 CHECK((NotNull1(p1) < NotNull1(p1)) == false); 312 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); 313 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); 314 315 CHECK((NotNull1(p1) > NotNull1(p1)) == false); 316 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); 317 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); 318 319 CHECK((NotNull1(p1) <= NotNull1(p1)) == true); 320 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); 321 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); 322 } 323 324 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 325 TEST_CASE("TestNotNullDereferenceOperator") 326 { 327 { 328 auto sp1 = std::make_shared<NonCopyableNonMovable>(); 329 330 using NotNullSp1 = not_null<decltype(sp1)>; 331 CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1))); 332 CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1)); 333 } 334 335 { 336 int ints[1] = {42}; 337 CustomPtr<int> p1(&ints[0]); 338 339 using NotNull1 = not_null<decltype(p1)>; 340 CHECK(typeid(*NotNull1(p1)) == typeid(*p1)); 341 CHECK(*NotNull1(p1) == 42); 342 *NotNull1(p1) = 43; 343 CHECK(ints[0] == 43); 344 } 345 346 { 347 int v = 42; 348 gsl::not_null<int*> p(&v); 349 CHECK(typeid(*p) == typeid(*(&v))); 350 *p = 43; 351 CHECK(v == 43); 352 } 353 } 354 355 TEST_CASE("TestNotNullSharedPtrComparison") 356 { 357 auto sp1 = std::make_shared<int>(42); 358 auto sp2 = std::make_shared<const int>(43); 359 360 using NotNullSp1 = not_null<decltype(sp1)>; 361 using NotNullSp2 = not_null<decltype(sp2)>; 362 363 CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true); 364 CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false); 365 366 CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false); 367 CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true); 368 369 CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false); 370 CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2)); 371 CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1)); 372 373 CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false); 374 CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2)); 375 CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1)); 376 377 CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true); 378 CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2)); 379 CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1)); 380 381 CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true); 382 CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2)); 383 CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1)); 384 } 385 386 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 387 TEST_CASE("TestNotNullCustomPtrComparison") 388 { 389 int ints[2] = {42, 43}; 390 CustomPtr<int> p1(&ints[0]); 391 CustomPtr<const int> p2(&ints[1]); 392 393 using NotNull1 = not_null<decltype(p1)>; 394 using NotNull2 = not_null<decltype(p2)>; 395 396 CHECK((NotNull1(p1) == NotNull1(p1)) == "true"); 397 CHECK((NotNull1(p1) == NotNull2(p2)) == "false"); 398 399 CHECK((NotNull1(p1) != NotNull1(p1)) == "false"); 400 CHECK((NotNull1(p1) != NotNull2(p2)) == "true"); 401 402 CHECK((NotNull1(p1) < NotNull1(p1)) == "false"); 403 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); 404 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); 405 406 CHECK((NotNull1(p1) > NotNull1(p1)) == "false"); 407 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); 408 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); 409 410 CHECK((NotNull1(p1) <= NotNull1(p1)) == "true"); 411 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); 412 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); 413 414 CHECK((NotNull1(p1) >= NotNull1(p1)) == "true"); 415 CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); 416 CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); 417 } 418 419 #if defined(__cplusplus) && (__cplusplus >= 201703L) 420 421 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 422 TEST_CASE("TestNotNullConstructorTypeDeduction") 423 { 424 { 425 int i = 42; 426 427 not_null x{&i}; 428 helper(not_null{&i}); 429 helper_const(not_null{&i}); 430 431 CHECK(*x == 42); 432 } 433 434 { 435 int i = 42; 436 int* p = &i; 437 438 not_null x{p}; 439 helper(not_null{p}); 440 helper_const(not_null{p}); 441 442 CHECK(*x == 42); 443 } 444 445 { 446 auto workaround_macro = []() { 447 int* p1 = nullptr; 448 const not_null x{p1}; 449 }; 450 CHECK_THROWS_AS(workaround_macro(), fail_fast); 451 } 452 453 { 454 auto workaround_macro = []() { 455 const int* p1 = nullptr; 456 const not_null x{p1}; 457 }; 458 CHECK_THROWS_AS(workaround_macro(), fail_fast); 459 } 460 461 { 462 int* p = nullptr; 463 464 CHECK_THROWS_AS(helper(not_null{p}), fail_fast); 465 CHECK_THROWS_AS(helper_const(not_null{p}), fail_fast); 466 } 467 468 #ifdef CONFIRM_COMPILATION_ERRORS 469 { 470 not_null x{nullptr}; 471 helper(not_null{nullptr}); 472 helper_const(not_null{nullptr}); 473 } 474 #endif 475 } 476 #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) 477 478 TEST_CASE("TestMakeNotNull") 479 { 480 { 481 int i = 42; 482 483 const auto x = make_not_null(&i); 484 helper(make_not_null(&i)); 485 helper_const(make_not_null(&i)); 486 487 CHECK(*x == 42); 488 } 489 490 { 491 int i = 42; 492 int* p = &i; 493 494 const auto x = make_not_null(p); 495 helper(make_not_null(p)); 496 helper_const(make_not_null(p)); 497 498 CHECK(*x == 42); 499 } 500 501 { 502 const auto workaround_macro = []() { 503 int* p1 = nullptr; 504 const auto x = make_not_null(p1); 505 CHECK(*x == 42); 506 }; 507 CHECK_THROWS_AS(workaround_macro(), fail_fast); 508 } 509 510 { 511 const auto workaround_macro = []() { 512 const int* p1 = nullptr; 513 const auto x = make_not_null(p1); 514 CHECK(*x == 42); 515 }; 516 CHECK_THROWS_AS(workaround_macro(), fail_fast); 517 } 518 519 { 520 int* p = nullptr; 521 522 CHECK_THROWS_AS(helper(make_not_null(p)), fail_fast); 523 CHECK_THROWS_AS(helper_const(make_not_null(p)), fail_fast); 524 } 525 526 #ifdef CONFIRM_COMPILATION_ERRORS 527 { 528 CHECK_THROWS_AS(make_not_null(nullptr), fail_fast); 529 CHECK_THROWS_AS(helper(make_not_null(nullptr)), fail_fast); 530 CHECK_THROWS_AS(helper_const(make_not_null(nullptr)), fail_fast); 531 } 532 #endif 533 } 534 535 static_assert(std::is_nothrow_move_constructible<not_null<void*>>::value, 536 "not_null must be no-throw move constructible"); 537