tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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([&nothrow_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([&nothrow_assign1, &nothrow_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([&nothrow_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([&nothrow_assign1, &nothrow_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