exception_safety_testing_test.cc (28238B)
1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "absl/base/internal/exception_safety_testing.h" 16 17 #ifdef ABSL_HAVE_EXCEPTIONS 18 19 #include <cstddef> 20 #include <exception> 21 #include <iostream> 22 #include <list> 23 #include <type_traits> 24 #include <vector> 25 26 #include "gtest/gtest-spi.h" 27 #include "gtest/gtest.h" 28 #include "absl/memory/memory.h" 29 30 namespace testing { 31 32 namespace { 33 34 using ::testing::exceptions_internal::SetCountdown; 35 using ::testing::exceptions_internal::TestException; 36 using ::testing::exceptions_internal::UnsetCountdown; 37 38 // EXPECT_NO_THROW can't inspect the thrown inspection in general. 39 template <typename F> 40 void ExpectNoThrow(const F& f) { 41 try { 42 f(); 43 } catch (const TestException& e) { 44 ADD_FAILURE() << "Unexpected exception thrown from " << e.what(); 45 } 46 } 47 48 TEST(ThrowingValueTest, Throws) { 49 SetCountdown(); 50 EXPECT_THROW(ThrowingValue<> bomb, TestException); 51 52 // It's not guaranteed that every operator only throws *once*. The default 53 // ctor only throws once, though, so use it to make sure we only throw when 54 // the countdown hits 0 55 SetCountdown(2); 56 ExpectNoThrow([]() { ThrowingValue<> bomb; }); 57 ExpectNoThrow([]() { ThrowingValue<> bomb; }); 58 EXPECT_THROW(ThrowingValue<> bomb, TestException); 59 60 UnsetCountdown(); 61 } 62 63 // Tests that an operation throws when the countdown is at 0, doesn't throw when 64 // the countdown doesn't hit 0, and doesn't modify the state of the 65 // ThrowingValue if it throws 66 template <typename F> 67 void TestOp(const F& f) { 68 ExpectNoThrow(f); 69 70 SetCountdown(); 71 EXPECT_THROW(f(), TestException); 72 UnsetCountdown(); 73 } 74 75 TEST(ThrowingValueTest, ThrowingCtors) { 76 ThrowingValue<> bomb; 77 78 TestOp([]() { ThrowingValue<> bomb(1); }); 79 TestOp([&]() { ThrowingValue<> bomb1 = bomb; }); 80 TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); }); 81 } 82 83 TEST(ThrowingValueTest, ThrowingAssignment) { 84 ThrowingValue<> bomb, bomb1; 85 86 TestOp([&]() { bomb = bomb1; }); 87 TestOp([&]() { bomb = std::move(bomb1); }); 88 89 // Test that when assignment throws, the assignment should fail (lhs != rhs) 90 // and strong guarantee fails (lhs != lhs_copy). 91 { 92 ThrowingValue<> lhs(39), rhs(42); 93 ThrowingValue<> lhs_copy(lhs); 94 SetCountdown(); 95 EXPECT_THROW(lhs = rhs, TestException); 96 UnsetCountdown(); 97 EXPECT_NE(lhs, rhs); 98 EXPECT_NE(lhs_copy, lhs); 99 } 100 { 101 ThrowingValue<> lhs(39), rhs(42); 102 ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs); 103 SetCountdown(); 104 EXPECT_THROW(lhs = std::move(rhs), TestException); 105 UnsetCountdown(); 106 EXPECT_NE(lhs, rhs_copy); 107 EXPECT_NE(lhs_copy, lhs); 108 } 109 } 110 111 TEST(ThrowingValueTest, ThrowingComparisons) { 112 ThrowingValue<> bomb1, bomb2; 113 TestOp([&]() { return bomb1 == bomb2; }); 114 TestOp([&]() { return bomb1 != bomb2; }); 115 TestOp([&]() { return bomb1 < bomb2; }); 116 TestOp([&]() { return bomb1 <= bomb2; }); 117 TestOp([&]() { return bomb1 > bomb2; }); 118 TestOp([&]() { return bomb1 >= bomb2; }); 119 } 120 121 TEST(ThrowingValueTest, ThrowingArithmeticOps) { 122 ThrowingValue<> bomb1(1), bomb2(2); 123 124 TestOp([&bomb1]() { +bomb1; }); 125 TestOp([&bomb1]() { -bomb1; }); 126 TestOp([&bomb1]() { ++bomb1; }); 127 TestOp([&bomb1]() { bomb1++; }); 128 TestOp([&bomb1]() { --bomb1; }); 129 TestOp([&bomb1]() { bomb1--; }); 130 131 TestOp([&]() { bomb1 + bomb2; }); 132 TestOp([&]() { bomb1 - bomb2; }); 133 TestOp([&]() { bomb1* bomb2; }); 134 TestOp([&]() { bomb1 / bomb2; }); 135 TestOp([&]() { bomb1 << 1; }); 136 TestOp([&]() { bomb1 >> 1; }); 137 } 138 139 TEST(ThrowingValueTest, ThrowingLogicalOps) { 140 ThrowingValue<> bomb1, bomb2; 141 142 TestOp([&bomb1]() { !bomb1; }); 143 TestOp([&]() { bomb1&& bomb2; }); 144 TestOp([&]() { bomb1 || bomb2; }); 145 } 146 147 TEST(ThrowingValueTest, ThrowingBitwiseOps) { 148 ThrowingValue<> bomb1, bomb2; 149 150 TestOp([&bomb1]() { ~bomb1; }); 151 TestOp([&]() { bomb1 & bomb2; }); 152 TestOp([&]() { bomb1 | bomb2; }); 153 TestOp([&]() { bomb1 ^ bomb2; }); 154 } 155 156 TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) { 157 ThrowingValue<> bomb1(1), bomb2(2); 158 159 TestOp([&]() { bomb1 += bomb2; }); 160 TestOp([&]() { bomb1 -= bomb2; }); 161 TestOp([&]() { bomb1 *= bomb2; }); 162 TestOp([&]() { bomb1 /= bomb2; }); 163 TestOp([&]() { bomb1 %= bomb2; }); 164 TestOp([&]() { bomb1 &= bomb2; }); 165 TestOp([&]() { bomb1 |= bomb2; }); 166 TestOp([&]() { bomb1 ^= bomb2; }); 167 TestOp([&]() { bomb1 *= bomb2; }); 168 } 169 170 TEST(ThrowingValueTest, ThrowingStreamOps) { 171 ThrowingValue<> bomb; 172 173 TestOp([&]() { 174 std::istringstream stream; 175 stream >> bomb; 176 }); 177 TestOp([&]() { 178 std::stringstream stream; 179 stream << bomb; 180 }); 181 } 182 183 // Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit 184 // a nonfatal failure that contains the string representation of the Thrower 185 TEST(ThrowingValueTest, StreamOpsOutput) { 186 using ::testing::TypeSpec; 187 exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); 188 189 // Test default spec list (kEverythingThrows) 190 EXPECT_NONFATAL_FAILURE( 191 { 192 using Thrower = ThrowingValue<TypeSpec{}>; 193 auto thrower = Thrower(123); 194 thrower.~Thrower(); 195 }, 196 "ThrowingValue<>(123)"); 197 198 // Test with one item in spec list (kNoThrowCopy) 199 EXPECT_NONFATAL_FAILURE( 200 { 201 using Thrower = ThrowingValue<TypeSpec::kNoThrowCopy>; 202 auto thrower = Thrower(234); 203 thrower.~Thrower(); 204 }, 205 "ThrowingValue<kNoThrowCopy>(234)"); 206 207 // Test with multiple items in spec list (kNoThrowMove, kNoThrowNew) 208 EXPECT_NONFATAL_FAILURE( 209 { 210 using Thrower = 211 ThrowingValue<TypeSpec::kNoThrowMove | TypeSpec::kNoThrowNew>; 212 auto thrower = Thrower(345); 213 thrower.~Thrower(); 214 }, 215 "ThrowingValue<kNoThrowMove | kNoThrowNew>(345)"); 216 217 // Test with all items in spec list (kNoThrowCopy, kNoThrowMove, kNoThrowNew) 218 EXPECT_NONFATAL_FAILURE( 219 { 220 using Thrower = ThrowingValue<static_cast<TypeSpec>(-1)>; 221 auto thrower = Thrower(456); 222 thrower.~Thrower(); 223 }, 224 "ThrowingValue<kNoThrowCopy | kNoThrowMove | kNoThrowNew>(456)"); 225 } 226 227 template <typename F> 228 void TestAllocatingOp(const F& f) { 229 ExpectNoThrow(f); 230 231 SetCountdown(); 232 EXPECT_THROW(f(), exceptions_internal::TestBadAllocException); 233 UnsetCountdown(); 234 } 235 236 TEST(ThrowingValueTest, ThrowingAllocatingOps) { 237 // make_unique calls unqualified operator new, so these exercise the 238 // ThrowingValue overloads. 239 TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>>(1); }); 240 TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); }); 241 } 242 243 TEST(ThrowingValueTest, NonThrowingMoveCtor) { 244 ThrowingValue<TypeSpec::kNoThrowMove> nothrow_ctor; 245 246 SetCountdown(); 247 ExpectNoThrow([¬hrow_ctor]() { 248 ThrowingValue<TypeSpec::kNoThrowMove> nothrow1 = std::move(nothrow_ctor); 249 }); 250 UnsetCountdown(); 251 } 252 253 TEST(ThrowingValueTest, NonThrowingMoveAssign) { 254 ThrowingValue<TypeSpec::kNoThrowMove> nothrow_assign1, nothrow_assign2; 255 256 SetCountdown(); 257 ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() { 258 nothrow_assign1 = std::move(nothrow_assign2); 259 }); 260 UnsetCountdown(); 261 } 262 263 TEST(ThrowingValueTest, ThrowingCopyCtor) { 264 ThrowingValue<> tv; 265 266 TestOp([&]() { ThrowingValue<> tv_copy(tv); }); 267 } 268 269 TEST(ThrowingValueTest, ThrowingCopyAssign) { 270 ThrowingValue<> tv1, tv2; 271 272 TestOp([&]() { tv1 = tv2; }); 273 } 274 275 TEST(ThrowingValueTest, NonThrowingCopyCtor) { 276 ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_ctor; 277 278 SetCountdown(); 279 ExpectNoThrow([¬hrow_ctor]() { 280 ThrowingValue<TypeSpec::kNoThrowCopy> nothrow1(nothrow_ctor); 281 }); 282 UnsetCountdown(); 283 } 284 285 TEST(ThrowingValueTest, NonThrowingCopyAssign) { 286 ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_assign1, nothrow_assign2; 287 288 SetCountdown(); 289 ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() { 290 nothrow_assign1 = nothrow_assign2; 291 }); 292 UnsetCountdown(); 293 } 294 295 TEST(ThrowingValueTest, ThrowingSwap) { 296 ThrowingValue<> bomb1, bomb2; 297 TestOp([&]() { std::swap(bomb1, bomb2); }); 298 } 299 300 TEST(ThrowingValueTest, NonThrowingSwap) { 301 ThrowingValue<TypeSpec::kNoThrowMove> bomb1, bomb2; 302 ExpectNoThrow([&]() { std::swap(bomb1, bomb2); }); 303 } 304 305 TEST(ThrowingValueTest, NonThrowingAllocation) { 306 ThrowingValue<TypeSpec::kNoThrowNew>* allocated; 307 ThrowingValue<TypeSpec::kNoThrowNew>* array; 308 309 ExpectNoThrow([&allocated]() { 310 allocated = new ThrowingValue<TypeSpec::kNoThrowNew>(1); 311 delete allocated; 312 }); 313 ExpectNoThrow([&array]() { 314 array = new ThrowingValue<TypeSpec::kNoThrowNew>[2]; 315 delete[] array; 316 }); 317 } 318 319 TEST(ThrowingValueTest, NonThrowingDelete) { 320 auto* allocated = new ThrowingValue<>(1); 321 auto* array = new ThrowingValue<>[2]; 322 323 SetCountdown(); 324 ExpectNoThrow([allocated]() { delete allocated; }); 325 SetCountdown(); 326 ExpectNoThrow([array]() { delete[] array; }); 327 328 UnsetCountdown(); 329 } 330 331 TEST(ThrowingValueTest, NonThrowingPlacementDelete) { 332 constexpr int kArrayLen = 2; 333 // We intentionally create extra space to store the tag allocated by placement 334 // new[]. 335 constexpr size_t kExtraSpaceLen = sizeof(size_t) * 2; 336 337 alignas(ThrowingValue<>) unsigned char buf[sizeof(ThrowingValue<>)]; 338 alignas(ThrowingValue<>) unsigned char 339 array_buf[kExtraSpaceLen + sizeof(ThrowingValue<>[kArrayLen])]; 340 auto* placed = new (&buf) ThrowingValue<>(1); 341 auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen]; 342 auto* placed_array_end = reinterpret_cast<unsigned char*>(placed_array) + 343 sizeof(ThrowingValue<>[kArrayLen]); 344 EXPECT_LE(placed_array_end, array_buf + sizeof(array_buf)); 345 346 SetCountdown(); 347 ExpectNoThrow([placed, &buf]() { 348 placed->~ThrowingValue<>(); 349 ThrowingValue<>::operator delete(placed, &buf); 350 }); 351 352 SetCountdown(); 353 ExpectNoThrow([&, placed_array]() { 354 for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>(); 355 ThrowingValue<>::operator delete[](placed_array, &array_buf); 356 }); 357 358 UnsetCountdown(); 359 } 360 361 TEST(ThrowingValueTest, NonThrowingDestructor) { 362 auto* allocated = new ThrowingValue<>(); 363 364 SetCountdown(); 365 ExpectNoThrow([allocated]() { delete allocated; }); 366 UnsetCountdown(); 367 } 368 369 TEST(ThrowingBoolTest, ThrowingBool) { 370 ThrowingBool t = true; 371 372 // Test that it's contextually convertible to bool 373 if (t) { // NOLINT(whitespace/empty_if_body) 374 } 375 EXPECT_TRUE(t); 376 377 TestOp([&]() { (void)!t; }); 378 } 379 380 TEST(ThrowingAllocatorTest, MemoryManagement) { 381 // Just exercise the memory management capabilities under LSan to make sure we 382 // don't leak. 383 ThrowingAllocator<int> int_alloc; 384 int* ip = int_alloc.allocate(1); 385 int_alloc.deallocate(ip, 1); 386 int* i_array = int_alloc.allocate(2); 387 int_alloc.deallocate(i_array, 2); 388 389 ThrowingAllocator<ThrowingValue<>> tv_alloc; 390 ThrowingValue<>* ptr = tv_alloc.allocate(1); 391 tv_alloc.deallocate(ptr, 1); 392 ThrowingValue<>* tv_array = tv_alloc.allocate(2); 393 tv_alloc.deallocate(tv_array, 2); 394 } 395 396 TEST(ThrowingAllocatorTest, CallsGlobalNew) { 397 ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> nothrow_alloc; 398 ThrowingValue<>* ptr; 399 400 SetCountdown(); 401 // This will only throw if ThrowingValue::new is called. 402 ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); }); 403 nothrow_alloc.deallocate(ptr, 1); 404 405 UnsetCountdown(); 406 } 407 408 TEST(ThrowingAllocatorTest, ThrowingConstructors) { 409 ThrowingAllocator<int> int_alloc; 410 int* ip = nullptr; 411 412 SetCountdown(); 413 EXPECT_THROW(ip = int_alloc.allocate(1), TestException); 414 ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); 415 416 *ip = 1; 417 SetCountdown(); 418 EXPECT_THROW(int_alloc.construct(ip, 2), TestException); 419 EXPECT_EQ(*ip, 1); 420 int_alloc.deallocate(ip, 1); 421 422 UnsetCountdown(); 423 } 424 425 TEST(ThrowingAllocatorTest, NonThrowingConstruction) { 426 { 427 ThrowingAllocator<int, AllocSpec::kNoThrowAllocate> int_alloc; 428 int* ip = nullptr; 429 430 SetCountdown(); 431 ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); 432 433 SetCountdown(); 434 ExpectNoThrow([&]() { int_alloc.construct(ip, 2); }); 435 436 EXPECT_EQ(*ip, 2); 437 int_alloc.deallocate(ip, 1); 438 439 UnsetCountdown(); 440 } 441 442 { 443 ThrowingAllocator<int> int_alloc; 444 int* ip = nullptr; 445 ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); 446 ExpectNoThrow([&]() { int_alloc.construct(ip, 2); }); 447 EXPECT_EQ(*ip, 2); 448 int_alloc.deallocate(ip, 1); 449 } 450 451 { 452 ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> 453 nothrow_alloc; 454 ThrowingValue<>* ptr; 455 456 SetCountdown(); 457 ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); }); 458 459 SetCountdown(); 460 ExpectNoThrow( 461 [&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); }); 462 463 EXPECT_EQ(ptr->Get(), 2); 464 nothrow_alloc.destroy(ptr); 465 nothrow_alloc.deallocate(ptr, 1); 466 467 UnsetCountdown(); 468 } 469 470 { 471 ThrowingAllocator<int> a; 472 473 SetCountdown(); 474 ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; }); 475 476 SetCountdown(); 477 ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); }); 478 479 UnsetCountdown(); 480 } 481 } 482 483 TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) { 484 ThrowingAllocator<int> a; 485 TestOp([]() { ThrowingAllocator<int> a; }); 486 TestOp([&]() { a.select_on_container_copy_construction(); }); 487 } 488 489 TEST(ThrowingAllocatorTest, State) { 490 ThrowingAllocator<int> a1, a2; 491 EXPECT_NE(a1, a2); 492 493 auto a3 = a1; 494 EXPECT_EQ(a3, a1); 495 int* ip = a1.allocate(1); 496 EXPECT_EQ(a3, a1); 497 a3.deallocate(ip, 1); 498 EXPECT_EQ(a3, a1); 499 } 500 501 TEST(ThrowingAllocatorTest, InVector) { 502 std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v; 503 for (int i = 0; i < 20; ++i) v.push_back({}); 504 for (int i = 0; i < 20; ++i) v.pop_back(); 505 } 506 507 TEST(ThrowingAllocatorTest, InList) { 508 std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l; 509 for (int i = 0; i < 20; ++i) l.push_back({}); 510 for (int i = 0; i < 20; ++i) l.pop_back(); 511 for (int i = 0; i < 20; ++i) l.push_front({}); 512 for (int i = 0; i < 20; ++i) l.pop_front(); 513 } 514 515 template <typename TesterInstance, typename = void> 516 struct NullaryTestValidator : public std::false_type {}; 517 518 template <typename TesterInstance> 519 struct NullaryTestValidator< 520 TesterInstance, 521 absl::void_t<decltype(std::declval<TesterInstance>().Test())>> 522 : public std::true_type {}; 523 524 template <typename TesterInstance> 525 bool HasNullaryTest(const TesterInstance&) { 526 return NullaryTestValidator<TesterInstance>::value; 527 } 528 529 void DummyOp(void*) {} 530 531 template <typename TesterInstance, typename = void> 532 struct UnaryTestValidator : public std::false_type {}; 533 534 template <typename TesterInstance> 535 struct UnaryTestValidator< 536 TesterInstance, 537 absl::void_t<decltype(std::declval<TesterInstance>().Test(DummyOp))>> 538 : public std::true_type {}; 539 540 template <typename TesterInstance> 541 bool HasUnaryTest(const TesterInstance&) { 542 return UnaryTestValidator<TesterInstance>::value; 543 } 544 545 TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) { 546 using T = exceptions_internal::UninitializedT; 547 auto op = [](T* t) {}; 548 auto inv = [](T*) { return testing::AssertionSuccess(); }; 549 auto fac = []() { return absl::make_unique<T>(); }; 550 551 // Test that providing operation and inveriants still does not allow for the 552 // the invocation of .Test() and .Test(op) because it lacks a factory 553 auto without_fac = 554 testing::MakeExceptionSafetyTester().WithOperation(op).WithContracts( 555 inv, testing::strong_guarantee); 556 EXPECT_FALSE(HasNullaryTest(without_fac)); 557 EXPECT_FALSE(HasUnaryTest(without_fac)); 558 559 // Test that providing contracts and factory allows the invocation of 560 // .Test(op) but does not allow for .Test() because it lacks an operation 561 auto without_op = testing::MakeExceptionSafetyTester() 562 .WithContracts(inv, testing::strong_guarantee) 563 .WithFactory(fac); 564 EXPECT_FALSE(HasNullaryTest(without_op)); 565 EXPECT_TRUE(HasUnaryTest(without_op)); 566 567 // Test that providing operation and factory still does not allow for the 568 // the invocation of .Test() and .Test(op) because it lacks contracts 569 auto without_inv = 570 testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac); 571 EXPECT_FALSE(HasNullaryTest(without_inv)); 572 EXPECT_FALSE(HasUnaryTest(without_inv)); 573 } 574 575 struct ExampleStruct {}; 576 577 std::unique_ptr<ExampleStruct> ExampleFunctionFactory() { 578 return absl::make_unique<ExampleStruct>(); 579 } 580 581 void ExampleFunctionOperation(ExampleStruct*) {} 582 583 testing::AssertionResult ExampleFunctionContract(ExampleStruct*) { 584 return testing::AssertionSuccess(); 585 } 586 587 struct { 588 std::unique_ptr<ExampleStruct> operator()() const { 589 return ExampleFunctionFactory(); 590 } 591 } example_struct_factory; 592 593 struct { 594 void operator()(ExampleStruct*) const {} 595 } example_struct_operation; 596 597 struct { 598 testing::AssertionResult operator()(ExampleStruct* example_struct) const { 599 return ExampleFunctionContract(example_struct); 600 } 601 } example_struct_contract; 602 603 auto example_lambda_factory = []() { return ExampleFunctionFactory(); }; 604 605 auto example_lambda_operation = [](ExampleStruct*) {}; 606 607 auto example_lambda_contract = [](ExampleStruct* example_struct) { 608 return ExampleFunctionContract(example_struct); 609 }; 610 611 // Testing that function references, pointers, structs with operator() and 612 // lambdas can all be used with ExceptionSafetyTester 613 TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) { 614 // function reference 615 EXPECT_TRUE(testing::MakeExceptionSafetyTester() 616 .WithFactory(ExampleFunctionFactory) 617 .WithOperation(ExampleFunctionOperation) 618 .WithContracts(ExampleFunctionContract) 619 .Test()); 620 621 // function pointer 622 EXPECT_TRUE(testing::MakeExceptionSafetyTester() 623 .WithFactory(&ExampleFunctionFactory) 624 .WithOperation(&ExampleFunctionOperation) 625 .WithContracts(&ExampleFunctionContract) 626 .Test()); 627 628 // struct 629 EXPECT_TRUE(testing::MakeExceptionSafetyTester() 630 .WithFactory(example_struct_factory) 631 .WithOperation(example_struct_operation) 632 .WithContracts(example_struct_contract) 633 .Test()); 634 635 // lambda 636 EXPECT_TRUE(testing::MakeExceptionSafetyTester() 637 .WithFactory(example_lambda_factory) 638 .WithOperation(example_lambda_operation) 639 .WithContracts(example_lambda_contract) 640 .Test()); 641 } 642 643 struct NonNegative { 644 bool operator==(const NonNegative& other) const { return i == other.i; } 645 int i; 646 }; 647 648 testing::AssertionResult CheckNonNegativeInvariants(NonNegative* g) { 649 if (g->i >= 0) { 650 return testing::AssertionSuccess(); 651 } 652 return testing::AssertionFailure() 653 << "i should be non-negative but is " << g->i; 654 } 655 656 struct { 657 template <typename T> 658 void operator()(T* t) const { 659 (*t)(); 660 } 661 } invoker; 662 663 auto tester = 664 testing::MakeExceptionSafetyTester().WithOperation(invoker).WithContracts( 665 CheckNonNegativeInvariants); 666 auto strong_tester = tester.WithContracts(testing::strong_guarantee); 667 668 struct FailsBasicGuarantee : public NonNegative { 669 void operator()() { 670 --i; 671 ThrowingValue<> bomb; 672 ++i; 673 } 674 }; 675 676 TEST(ExceptionCheckTest, BasicGuaranteeFailure) { 677 EXPECT_FALSE(tester.WithInitialValue(FailsBasicGuarantee{}).Test()); 678 } 679 680 struct FollowsBasicGuarantee : public NonNegative { 681 void operator()() { 682 ++i; 683 ThrowingValue<> bomb; 684 } 685 }; 686 687 TEST(ExceptionCheckTest, BasicGuarantee) { 688 EXPECT_TRUE(tester.WithInitialValue(FollowsBasicGuarantee{}).Test()); 689 } 690 691 TEST(ExceptionCheckTest, StrongGuaranteeFailure) { 692 EXPECT_FALSE(strong_tester.WithInitialValue(FailsBasicGuarantee{}).Test()); 693 EXPECT_FALSE(strong_tester.WithInitialValue(FollowsBasicGuarantee{}).Test()); 694 } 695 696 struct BasicGuaranteeWithExtraContracts : public NonNegative { 697 // After operator(), i is incremented. If operator() throws, i is set to 9999 698 void operator()() { 699 int old_i = i; 700 i = kExceptionSentinel; 701 ThrowingValue<> bomb; 702 i = ++old_i; 703 } 704 705 static constexpr int kExceptionSentinel = 9999; 706 }; 707 708 TEST(ExceptionCheckTest, BasicGuaranteeWithExtraContracts) { 709 auto tester_with_val = 710 tester.WithInitialValue(BasicGuaranteeWithExtraContracts{}); 711 EXPECT_TRUE(tester_with_val.Test()); 712 EXPECT_TRUE( 713 tester_with_val 714 .WithContracts([](BasicGuaranteeWithExtraContracts* o) { 715 if (o->i == BasicGuaranteeWithExtraContracts::kExceptionSentinel) { 716 return testing::AssertionSuccess(); 717 } 718 return testing::AssertionFailure() 719 << "i should be " 720 << BasicGuaranteeWithExtraContracts::kExceptionSentinel 721 << ", but is " << o->i; 722 }) 723 .Test()); 724 } 725 726 struct FollowsStrongGuarantee : public NonNegative { 727 void operator()() { ThrowingValue<> bomb; } 728 }; 729 730 TEST(ExceptionCheckTest, StrongGuarantee) { 731 EXPECT_TRUE(tester.WithInitialValue(FollowsStrongGuarantee{}).Test()); 732 EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}).Test()); 733 } 734 735 struct HasReset : public NonNegative { 736 void operator()() { 737 i = -1; 738 ThrowingValue<> bomb; 739 i = 1; 740 } 741 742 void reset() { i = 0; } 743 }; 744 745 testing::AssertionResult CheckHasResetContracts(HasReset* h) { 746 h->reset(); 747 return testing::AssertionResult(h->i == 0); 748 } 749 750 TEST(ExceptionCheckTest, ModifyingChecker) { 751 auto set_to_1000 = [](FollowsBasicGuarantee* g) { 752 g->i = 1000; 753 return testing::AssertionSuccess(); 754 }; 755 auto is_1000 = [](FollowsBasicGuarantee* g) { 756 return testing::AssertionResult(g->i == 1000); 757 }; 758 auto increment = [](FollowsStrongGuarantee* g) { 759 ++g->i; 760 return testing::AssertionSuccess(); 761 }; 762 763 EXPECT_FALSE(tester.WithInitialValue(FollowsBasicGuarantee{}) 764 .WithContracts(set_to_1000, is_1000) 765 .Test()); 766 EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}) 767 .WithContracts(increment) 768 .Test()); 769 EXPECT_TRUE(testing::MakeExceptionSafetyTester() 770 .WithInitialValue(HasReset{}) 771 .WithContracts(CheckHasResetContracts) 772 .Test(invoker)); 773 } 774 775 TEST(ExceptionSafetyTesterTest, ResetsCountdown) { 776 auto test = 777 testing::MakeExceptionSafetyTester() 778 .WithInitialValue(ThrowingValue<>()) 779 .WithContracts([](ThrowingValue<>*) { return AssertionSuccess(); }) 780 .WithOperation([](ThrowingValue<>*) {}); 781 ASSERT_TRUE(test.Test()); 782 // If the countdown isn't reset because there were no exceptions thrown, then 783 // this will fail with a termination from an unhandled exception 784 EXPECT_TRUE(test.Test()); 785 } 786 787 struct NonCopyable : public NonNegative { 788 NonCopyable(const NonCopyable&) = delete; 789 NonCopyable() : NonNegative{0} {} 790 791 void operator()() { ThrowingValue<> bomb; } 792 }; 793 794 TEST(ExceptionCheckTest, NonCopyable) { 795 auto factory = []() { return absl::make_unique<NonCopyable>(); }; 796 EXPECT_TRUE(tester.WithFactory(factory).Test()); 797 EXPECT_TRUE(strong_tester.WithFactory(factory).Test()); 798 } 799 800 struct NonEqualityComparable : public NonNegative { 801 void operator()() { ThrowingValue<> bomb; } 802 803 void ModifyOnThrow() { 804 ++i; 805 ThrowingValue<> bomb; 806 static_cast<void>(bomb); 807 --i; 808 } 809 }; 810 811 TEST(ExceptionCheckTest, NonEqualityComparable) { 812 auto nec_is_strong = [](NonEqualityComparable* nec) { 813 return testing::AssertionResult(nec->i == NonEqualityComparable().i); 814 }; 815 auto strong_nec_tester = tester.WithInitialValue(NonEqualityComparable{}) 816 .WithContracts(nec_is_strong); 817 818 EXPECT_TRUE(strong_nec_tester.Test()); 819 EXPECT_FALSE(strong_nec_tester.Test( 820 [](NonEqualityComparable* n) { n->ModifyOnThrow(); })); 821 } 822 823 template <typename T> 824 struct ExhaustivenessTester { 825 void operator()() { 826 successes |= 1; 827 T b1; 828 static_cast<void>(b1); 829 successes |= (1 << 1); 830 T b2; 831 static_cast<void>(b2); 832 successes |= (1 << 2); 833 T b3; 834 static_cast<void>(b3); 835 successes |= (1 << 3); 836 } 837 838 bool operator==(const ExhaustivenessTester<ThrowingValue<>>&) const { 839 return true; 840 } 841 842 static unsigned char successes; 843 }; 844 845 struct { 846 template <typename T> 847 testing::AssertionResult operator()(ExhaustivenessTester<T>*) const { 848 return testing::AssertionSuccess(); 849 } 850 } CheckExhaustivenessTesterContracts; 851 852 template <typename T> 853 unsigned char ExhaustivenessTester<T>::successes = 0; 854 855 TEST(ExceptionCheckTest, Exhaustiveness) { 856 auto exhaust_tester = testing::MakeExceptionSafetyTester() 857 .WithContracts(CheckExhaustivenessTesterContracts) 858 .WithOperation(invoker); 859 860 EXPECT_TRUE( 861 exhaust_tester.WithInitialValue(ExhaustivenessTester<int>{}).Test()); 862 EXPECT_EQ(ExhaustivenessTester<int>::successes, 0xF); 863 864 EXPECT_TRUE( 865 exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{}) 866 .WithContracts(testing::strong_guarantee) 867 .Test()); 868 EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF); 869 } 870 871 struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject { 872 LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) { 873 ++counter; 874 ThrowingValue<> v; 875 static_cast<void>(v); 876 --counter; 877 } 878 LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept 879 : TrackedObject(ABSL_PRETTY_FUNCTION) {} 880 static int counter; 881 }; 882 int LeaksIfCtorThrows::counter = 0; 883 884 TEST(ExceptionCheckTest, TestLeakyCtor) { 885 testing::TestThrowingCtor<LeaksIfCtorThrows>(); 886 EXPECT_EQ(LeaksIfCtorThrows::counter, 1); 887 LeaksIfCtorThrows::counter = 0; 888 } 889 890 struct Tracked : private exceptions_internal::TrackedObject { 891 Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {} 892 }; 893 894 TEST(ConstructorTrackerTest, CreatedBefore) { 895 Tracked a, b, c; 896 exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); 897 } 898 899 TEST(ConstructorTrackerTest, CreatedAfter) { 900 exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); 901 Tracked a, b, c; 902 } 903 904 TEST(ConstructorTrackerTest, NotDestroyedAfter) { 905 alignas(Tracked) unsigned char storage[sizeof(Tracked)]; 906 EXPECT_NONFATAL_FAILURE( 907 { 908 exceptions_internal::ConstructorTracker ct( 909 exceptions_internal::countdown); 910 new (&storage) Tracked(); 911 }, 912 "not destroyed"); 913 } 914 915 TEST(ConstructorTrackerTest, DestroyedTwice) { 916 exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); 917 EXPECT_NONFATAL_FAILURE( 918 { 919 Tracked t; 920 t.~Tracked(); 921 }, 922 "re-destroyed"); 923 } 924 925 TEST(ConstructorTrackerTest, ConstructedTwice) { 926 exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); 927 alignas(Tracked) unsigned char storage[sizeof(Tracked)]; 928 EXPECT_NONFATAL_FAILURE( 929 { 930 new (&storage) Tracked(); 931 new (&storage) Tracked(); 932 reinterpret_cast<Tracked*>(&storage)->~Tracked(); 933 }, 934 "re-constructed"); 935 } 936 937 TEST(ThrowingValueTraitsTest, RelationalOperators) { 938 ThrowingValue<> a, b; 939 EXPECT_TRUE((std::is_convertible<decltype(a == b), bool>::value)); 940 EXPECT_TRUE((std::is_convertible<decltype(a != b), bool>::value)); 941 EXPECT_TRUE((std::is_convertible<decltype(a < b), bool>::value)); 942 EXPECT_TRUE((std::is_convertible<decltype(a <= b), bool>::value)); 943 EXPECT_TRUE((std::is_convertible<decltype(a > b), bool>::value)); 944 EXPECT_TRUE((std::is_convertible<decltype(a >= b), bool>::value)); 945 } 946 947 TEST(ThrowingAllocatorTraitsTest, Assignablility) { 948 EXPECT_TRUE(absl::is_move_assignable<ThrowingAllocator<int>>::value); 949 EXPECT_TRUE(absl::is_copy_assignable<ThrowingAllocator<int>>::value); 950 EXPECT_TRUE(std::is_nothrow_move_assignable<ThrowingAllocator<int>>::value); 951 EXPECT_TRUE(std::is_nothrow_copy_assignable<ThrowingAllocator<int>>::value); 952 } 953 954 } // namespace 955 956 } // namespace testing 957 958 #endif // ABSL_HAVE_EXCEPTIONS