| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954 | // Copyright 2017 The Abseil Authors.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////      https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.#include "absl/base/internal/exception_safety_testing.h"#include <cstddef>#include <exception>#include <iostream>#include <list>#include <type_traits>#include <vector>#include "gtest/gtest-spi.h"#include "gtest/gtest.h"#include "absl/memory/memory.h"namespace testing {namespace {using ::testing::exceptions_internal::SetCountdown;using ::testing::exceptions_internal::TestException;using ::testing::exceptions_internal::UnsetCountdown;// EXPECT_NO_THROW can't inspect the thrown inspection in general.template <typename F>void ExpectNoThrow(const F& f) {  try {    f();  } catch (const TestException& e) {    ADD_FAILURE() << "Unexpected exception thrown from " << e.what();  }}TEST(ThrowingValueTest, Throws) {  SetCountdown();  EXPECT_THROW(ThrowingValue<> bomb, TestException);  // It's not guaranteed that every operator only throws *once*.  The default  // ctor only throws once, though, so use it to make sure we only throw when  // the countdown hits 0  SetCountdown(2);  ExpectNoThrow([]() { ThrowingValue<> bomb; });  ExpectNoThrow([]() { ThrowingValue<> bomb; });  EXPECT_THROW(ThrowingValue<> bomb, TestException);  UnsetCountdown();}// Tests that an operation throws when the countdown is at 0, doesn't throw when// the countdown doesn't hit 0, and doesn't modify the state of the// ThrowingValue if it throwstemplate <typename F>void TestOp(const F& f) {  ExpectNoThrow(f);  SetCountdown();  EXPECT_THROW(f(), TestException);  UnsetCountdown();}TEST(ThrowingValueTest, ThrowingCtors) {  ThrowingValue<> bomb;  TestOp([]() { ThrowingValue<> bomb(1); });  TestOp([&]() { ThrowingValue<> bomb1 = bomb; });  TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); });}TEST(ThrowingValueTest, ThrowingAssignment) {  ThrowingValue<> bomb, bomb1;  TestOp([&]() { bomb = bomb1; });  TestOp([&]() { bomb = std::move(bomb1); });  // Test that when assignment throws, the assignment should fail (lhs != rhs)  // and strong guarantee fails (lhs != lhs_copy).  {    ThrowingValue<> lhs(39), rhs(42);    ThrowingValue<> lhs_copy(lhs);    SetCountdown();    EXPECT_THROW(lhs = rhs, TestException);    UnsetCountdown();    EXPECT_NE(lhs, rhs);    EXPECT_NE(lhs_copy, lhs);  }  {    ThrowingValue<> lhs(39), rhs(42);    ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs);    SetCountdown();    EXPECT_THROW(lhs = std::move(rhs), TestException);    UnsetCountdown();    EXPECT_NE(lhs, rhs_copy);    EXPECT_NE(lhs_copy, lhs);  }}TEST(ThrowingValueTest, ThrowingComparisons) {  ThrowingValue<> bomb1, bomb2;  TestOp([&]() { return bomb1 == bomb2; });  TestOp([&]() { return bomb1 != bomb2; });  TestOp([&]() { return bomb1 < bomb2; });  TestOp([&]() { return bomb1 <= bomb2; });  TestOp([&]() { return bomb1 > bomb2; });  TestOp([&]() { return bomb1 >= bomb2; });}TEST(ThrowingValueTest, ThrowingArithmeticOps) {  ThrowingValue<> bomb1(1), bomb2(2);  TestOp([&bomb1]() { +bomb1; });  TestOp([&bomb1]() { -bomb1; });  TestOp([&bomb1]() { ++bomb1; });  TestOp([&bomb1]() { bomb1++; });  TestOp([&bomb1]() { --bomb1; });  TestOp([&bomb1]() { bomb1--; });  TestOp([&]() { bomb1 + bomb2; });  TestOp([&]() { bomb1 - bomb2; });  TestOp([&]() { bomb1* bomb2; });  TestOp([&]() { bomb1 / bomb2; });  TestOp([&]() { bomb1 << 1; });  TestOp([&]() { bomb1 >> 1; });}TEST(ThrowingValueTest, ThrowingLogicalOps) {  ThrowingValue<> bomb1, bomb2;  TestOp([&bomb1]() { !bomb1; });  TestOp([&]() { bomb1&& bomb2; });  TestOp([&]() { bomb1 || bomb2; });}TEST(ThrowingValueTest, ThrowingBitwiseOps) {  ThrowingValue<> bomb1, bomb2;  TestOp([&bomb1]() { ~bomb1; });  TestOp([&]() { bomb1& bomb2; });  TestOp([&]() { bomb1 | bomb2; });  TestOp([&]() { bomb1 ^ bomb2; });}TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) {  ThrowingValue<> bomb1(1), bomb2(2);  TestOp([&]() { bomb1 += bomb2; });  TestOp([&]() { bomb1 -= bomb2; });  TestOp([&]() { bomb1 *= bomb2; });  TestOp([&]() { bomb1 /= bomb2; });  TestOp([&]() { bomb1 %= bomb2; });  TestOp([&]() { bomb1 &= bomb2; });  TestOp([&]() { bomb1 |= bomb2; });  TestOp([&]() { bomb1 ^= bomb2; });  TestOp([&]() { bomb1 *= bomb2; });}TEST(ThrowingValueTest, ThrowingStreamOps) {  ThrowingValue<> bomb;  TestOp([&]() {    std::istringstream stream;    stream >> bomb;  });  TestOp([&]() {    std::stringstream stream;    stream << bomb;  });}// Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit// a nonfatal failure that contains the string representation of the ThrowerTEST(ThrowingValueTest, StreamOpsOutput) {  using ::testing::TypeSpec;  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);  // Test default spec list (kEverythingThrows)  EXPECT_NONFATAL_FAILURE(      {        using Thrower = ThrowingValue<TypeSpec{}>;        auto thrower = Thrower(123);        thrower.~Thrower();      },      "ThrowingValue<>(123)");  // Test with one item in spec list (kNoThrowCopy)  EXPECT_NONFATAL_FAILURE(      {        using Thrower = ThrowingValue<TypeSpec::kNoThrowCopy>;        auto thrower = Thrower(234);        thrower.~Thrower();      },      "ThrowingValue<kNoThrowCopy>(234)");  // Test with multiple items in spec list (kNoThrowMove, kNoThrowNew)  EXPECT_NONFATAL_FAILURE(      {        using Thrower =            ThrowingValue<TypeSpec::kNoThrowMove | TypeSpec::kNoThrowNew>;        auto thrower = Thrower(345);        thrower.~Thrower();      },      "ThrowingValue<kNoThrowMove | kNoThrowNew>(345)");  // Test with all items in spec list (kNoThrowCopy, kNoThrowMove, kNoThrowNew)  EXPECT_NONFATAL_FAILURE(      {        using Thrower = ThrowingValue<static_cast<TypeSpec>(-1)>;        auto thrower = Thrower(456);        thrower.~Thrower();      },      "ThrowingValue<kNoThrowCopy | kNoThrowMove | kNoThrowNew>(456)");}template <typename F>void TestAllocatingOp(const F& f) {  ExpectNoThrow(f);  SetCountdown();  EXPECT_THROW(f(), exceptions_internal::TestBadAllocException);  UnsetCountdown();}TEST(ThrowingValueTest, ThrowingAllocatingOps) {  // make_unique calls unqualified operator new, so these exercise the  // ThrowingValue overloads.  TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>>(1); });  TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); });}TEST(ThrowingValueTest, NonThrowingMoveCtor) {  ThrowingValue<TypeSpec::kNoThrowMove> nothrow_ctor;  SetCountdown();  ExpectNoThrow([¬hrow_ctor]() {    ThrowingValue<TypeSpec::kNoThrowMove> nothrow1 = std::move(nothrow_ctor);  });  UnsetCountdown();}TEST(ThrowingValueTest, NonThrowingMoveAssign) {  ThrowingValue<TypeSpec::kNoThrowMove> nothrow_assign1, nothrow_assign2;  SetCountdown();  ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() {    nothrow_assign1 = std::move(nothrow_assign2);  });  UnsetCountdown();}TEST(ThrowingValueTest, ThrowingCopyCtor) {  ThrowingValue<> tv;  TestOp([&]() { ThrowingValue<> tv_copy(tv); });}TEST(ThrowingValueTest, ThrowingCopyAssign) {  ThrowingValue<> tv1, tv2;  TestOp([&]() { tv1 = tv2; });}TEST(ThrowingValueTest, NonThrowingCopyCtor) {  ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_ctor;  SetCountdown();  ExpectNoThrow([¬hrow_ctor]() {    ThrowingValue<TypeSpec::kNoThrowCopy> nothrow1(nothrow_ctor);  });  UnsetCountdown();}TEST(ThrowingValueTest, NonThrowingCopyAssign) {  ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_assign1, nothrow_assign2;  SetCountdown();  ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() {    nothrow_assign1 = nothrow_assign2;  });  UnsetCountdown();}TEST(ThrowingValueTest, ThrowingSwap) {  ThrowingValue<> bomb1, bomb2;  TestOp([&]() { std::swap(bomb1, bomb2); });}TEST(ThrowingValueTest, NonThrowingSwap) {  ThrowingValue<TypeSpec::kNoThrowMove> bomb1, bomb2;  ExpectNoThrow([&]() { std::swap(bomb1, bomb2); });}TEST(ThrowingValueTest, NonThrowingAllocation) {  ThrowingValue<TypeSpec::kNoThrowNew>* allocated;  ThrowingValue<TypeSpec::kNoThrowNew>* array;  ExpectNoThrow([&allocated]() {    allocated = new ThrowingValue<TypeSpec::kNoThrowNew>(1);    delete allocated;  });  ExpectNoThrow([&array]() {    array = new ThrowingValue<TypeSpec::kNoThrowNew>[2];    delete[] array;  });}TEST(ThrowingValueTest, NonThrowingDelete) {  auto* allocated = new ThrowingValue<>(1);  auto* array = new ThrowingValue<>[2];  SetCountdown();  ExpectNoThrow([allocated]() { delete allocated; });  SetCountdown();  ExpectNoThrow([array]() { delete[] array; });  UnsetCountdown();}using Storage =    absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>;TEST(ThrowingValueTest, NonThrowingPlacementDelete) {  constexpr int kArrayLen = 2;  // We intentionally create extra space to store the tag allocated by placement  // new[].  constexpr int kStorageLen = 4;  Storage buf;  Storage array_buf[kStorageLen];  auto* placed = new (&buf) ThrowingValue<>(1);  auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen];  SetCountdown();  ExpectNoThrow([placed, &buf]() {    placed->~ThrowingValue<>();    ThrowingValue<>::operator delete(placed, &buf);  });  SetCountdown();  ExpectNoThrow([&, placed_array]() {    for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>();    ThrowingValue<>::operator delete[](placed_array, &array_buf);  });  UnsetCountdown();}TEST(ThrowingValueTest, NonThrowingDestructor) {  auto* allocated = new ThrowingValue<>();  SetCountdown();  ExpectNoThrow([allocated]() { delete allocated; });  UnsetCountdown();}TEST(ThrowingBoolTest, ThrowingBool) {  ThrowingBool t = true;  // Test that it's contextually convertible to bool  if (t) {  // NOLINT(whitespace/empty_if_body)  }  EXPECT_TRUE(t);  TestOp([&]() { (void)!t; });}TEST(ThrowingAllocatorTest, MemoryManagement) {  // Just exercise the memory management capabilities under LSan to make sure we  // don't leak.  ThrowingAllocator<int> int_alloc;  int* ip = int_alloc.allocate(1);  int_alloc.deallocate(ip, 1);  int* i_array = int_alloc.allocate(2);  int_alloc.deallocate(i_array, 2);  ThrowingAllocator<ThrowingValue<>> tv_alloc;  ThrowingValue<>* ptr = tv_alloc.allocate(1);  tv_alloc.deallocate(ptr, 1);  ThrowingValue<>* tv_array = tv_alloc.allocate(2);  tv_alloc.deallocate(tv_array, 2);}TEST(ThrowingAllocatorTest, CallsGlobalNew) {  ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> nothrow_alloc;  ThrowingValue<>* ptr;  SetCountdown();  // This will only throw if ThrowingValue::new is called.  ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });  nothrow_alloc.deallocate(ptr, 1);  UnsetCountdown();}TEST(ThrowingAllocatorTest, ThrowingConstructors) {  ThrowingAllocator<int> int_alloc;  int* ip = nullptr;  SetCountdown();  EXPECT_THROW(ip = int_alloc.allocate(1), TestException);  ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });  *ip = 1;  SetCountdown();  EXPECT_THROW(int_alloc.construct(ip, 2), TestException);  EXPECT_EQ(*ip, 1);  int_alloc.deallocate(ip, 1);  UnsetCountdown();}TEST(ThrowingAllocatorTest, NonThrowingConstruction) {  {    ThrowingAllocator<int, AllocSpec::kNoThrowAllocate> int_alloc;    int* ip = nullptr;    SetCountdown();    ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });    SetCountdown();    ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });    EXPECT_EQ(*ip, 2);    int_alloc.deallocate(ip, 1);    UnsetCountdown();  }  {    ThrowingAllocator<int> int_alloc;    int* ip = nullptr;    ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });    ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });    EXPECT_EQ(*ip, 2);    int_alloc.deallocate(ip, 1);  }  {    ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate>        nothrow_alloc;    ThrowingValue<>* ptr;    SetCountdown();    ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });    SetCountdown();    ExpectNoThrow(        [&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); });    EXPECT_EQ(ptr->Get(), 2);    nothrow_alloc.destroy(ptr);    nothrow_alloc.deallocate(ptr, 1);    UnsetCountdown();  }  {    ThrowingAllocator<int> a;    SetCountdown();    ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; });    SetCountdown();    ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); });    UnsetCountdown();  }}TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) {  ThrowingAllocator<int> a;  TestOp([]() { ThrowingAllocator<int> a; });  TestOp([&]() { a.select_on_container_copy_construction(); });}TEST(ThrowingAllocatorTest, State) {  ThrowingAllocator<int> a1, a2;  EXPECT_NE(a1, a2);  auto a3 = a1;  EXPECT_EQ(a3, a1);  int* ip = a1.allocate(1);  EXPECT_EQ(a3, a1);  a3.deallocate(ip, 1);  EXPECT_EQ(a3, a1);}TEST(ThrowingAllocatorTest, InVector) {  std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v;  for (int i = 0; i < 20; ++i) v.push_back({});  for (int i = 0; i < 20; ++i) v.pop_back();}TEST(ThrowingAllocatorTest, InList) {  std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l;  for (int i = 0; i < 20; ++i) l.push_back({});  for (int i = 0; i < 20; ++i) l.pop_back();  for (int i = 0; i < 20; ++i) l.push_front({});  for (int i = 0; i < 20; ++i) l.pop_front();}template <typename TesterInstance, typename = void>struct NullaryTestValidator : public std::false_type {};template <typename TesterInstance>struct NullaryTestValidator<    TesterInstance,    absl::void_t<decltype(std::declval<TesterInstance>().Test())>>    : public std::true_type {};template <typename TesterInstance>bool HasNullaryTest(const TesterInstance&) {  return NullaryTestValidator<TesterInstance>::value;}void DummyOp(void*) {}template <typename TesterInstance, typename = void>struct UnaryTestValidator : public std::false_type {};template <typename TesterInstance>struct UnaryTestValidator<    TesterInstance,    absl::void_t<decltype(std::declval<TesterInstance>().Test(DummyOp))>>    : public std::true_type {};template <typename TesterInstance>bool HasUnaryTest(const TesterInstance&) {  return UnaryTestValidator<TesterInstance>::value;}TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) {  using T = exceptions_internal::UninitializedT;  auto op = [](T* t) {};  auto inv = [](T*) { return testing::AssertionSuccess(); };  auto fac = []() { return absl::make_unique<T>(); };  // Test that providing operation and inveriants still does not allow for the  // the invocation of .Test() and .Test(op) because it lacks a factory  auto without_fac =      testing::MakeExceptionSafetyTester().WithOperation(op).WithContracts(          inv, testing::strong_guarantee);  EXPECT_FALSE(HasNullaryTest(without_fac));  EXPECT_FALSE(HasUnaryTest(without_fac));  // Test that providing contracts and factory allows the invocation of  // .Test(op) but does not allow for .Test() because it lacks an operation  auto without_op = testing::MakeExceptionSafetyTester()                        .WithContracts(inv, testing::strong_guarantee)                        .WithFactory(fac);  EXPECT_FALSE(HasNullaryTest(without_op));  EXPECT_TRUE(HasUnaryTest(without_op));  // Test that providing operation and factory still does not allow for the  // the invocation of .Test() and .Test(op) because it lacks contracts  auto without_inv =      testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac);  EXPECT_FALSE(HasNullaryTest(without_inv));  EXPECT_FALSE(HasUnaryTest(without_inv));}struct ExampleStruct {};std::unique_ptr<ExampleStruct> ExampleFunctionFactory() {  return absl::make_unique<ExampleStruct>();}void ExampleFunctionOperation(ExampleStruct*) {}testing::AssertionResult ExampleFunctionContract(ExampleStruct*) {  return testing::AssertionSuccess();}struct {  std::unique_ptr<ExampleStruct> operator()() const {    return ExampleFunctionFactory();  }} example_struct_factory;struct {  void operator()(ExampleStruct*) const {}} example_struct_operation;struct {  testing::AssertionResult operator()(ExampleStruct* example_struct) const {    return ExampleFunctionContract(example_struct);  }} example_struct_contract;auto example_lambda_factory = []() { return ExampleFunctionFactory(); };auto example_lambda_operation = [](ExampleStruct*) {};auto example_lambda_contract = [](ExampleStruct* example_struct) {  return ExampleFunctionContract(example_struct);};// Testing that function references, pointers, structs with operator() and// lambdas can all be used with ExceptionSafetyTesterTEST(ExceptionSafetyTesterTest, MixedFunctionTypes) {  // function reference  EXPECT_TRUE(testing::MakeExceptionSafetyTester()                  .WithFactory(ExampleFunctionFactory)                  .WithOperation(ExampleFunctionOperation)                  .WithContracts(ExampleFunctionContract)                  .Test());  // function pointer  EXPECT_TRUE(testing::MakeExceptionSafetyTester()                  .WithFactory(&ExampleFunctionFactory)                  .WithOperation(&ExampleFunctionOperation)                  .WithContracts(&ExampleFunctionContract)                  .Test());  // struct  EXPECT_TRUE(testing::MakeExceptionSafetyTester()                  .WithFactory(example_struct_factory)                  .WithOperation(example_struct_operation)                  .WithContracts(example_struct_contract)                  .Test());  // lambda  EXPECT_TRUE(testing::MakeExceptionSafetyTester()                  .WithFactory(example_lambda_factory)                  .WithOperation(example_lambda_operation)                  .WithContracts(example_lambda_contract)                  .Test());}struct NonNegative {  bool operator==(const NonNegative& other) const { return i == other.i; }  int i;};testing::AssertionResult CheckNonNegativeInvariants(NonNegative* g) {  if (g->i >= 0) {    return testing::AssertionSuccess();  }  return testing::AssertionFailure()         << "i should be non-negative but is " << g->i;}struct {  template <typename T>  void operator()(T* t) const {    (*t)();  }} invoker;auto tester =    testing::MakeExceptionSafetyTester().WithOperation(invoker).WithContracts(        CheckNonNegativeInvariants);auto strong_tester = tester.WithContracts(testing::strong_guarantee);struct FailsBasicGuarantee : public NonNegative {  void operator()() {    --i;    ThrowingValue<> bomb;    ++i;  }};TEST(ExceptionCheckTest, BasicGuaranteeFailure) {  EXPECT_FALSE(tester.WithInitialValue(FailsBasicGuarantee{}).Test());}struct FollowsBasicGuarantee : public NonNegative {  void operator()() {    ++i;    ThrowingValue<> bomb;  }};TEST(ExceptionCheckTest, BasicGuarantee) {  EXPECT_TRUE(tester.WithInitialValue(FollowsBasicGuarantee{}).Test());}TEST(ExceptionCheckTest, StrongGuaranteeFailure) {  EXPECT_FALSE(strong_tester.WithInitialValue(FailsBasicGuarantee{}).Test());  EXPECT_FALSE(strong_tester.WithInitialValue(FollowsBasicGuarantee{}).Test());}struct BasicGuaranteeWithExtraContracts : public NonNegative {  // After operator(), i is incremented.  If operator() throws, i is set to 9999  void operator()() {    int old_i = i;    i = kExceptionSentinel;    ThrowingValue<> bomb;    i = ++old_i;  }  static constexpr int kExceptionSentinel = 9999;};constexpr int BasicGuaranteeWithExtraContracts::kExceptionSentinel;TEST(ExceptionCheckTest, BasicGuaranteeWithExtraContracts) {  auto tester_with_val =      tester.WithInitialValue(BasicGuaranteeWithExtraContracts{});  EXPECT_TRUE(tester_with_val.Test());  EXPECT_TRUE(      tester_with_val          .WithContracts([](BasicGuaranteeWithExtraContracts* o) {            if (o->i == BasicGuaranteeWithExtraContracts::kExceptionSentinel) {              return testing::AssertionSuccess();            }            return testing::AssertionFailure()                   << "i should be "                   << BasicGuaranteeWithExtraContracts::kExceptionSentinel                   << ", but is " << o->i;          })          .Test());}struct FollowsStrongGuarantee : public NonNegative {  void operator()() { ThrowingValue<> bomb; }};TEST(ExceptionCheckTest, StrongGuarantee) {  EXPECT_TRUE(tester.WithInitialValue(FollowsStrongGuarantee{}).Test());  EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}).Test());}struct HasReset : public NonNegative {  void operator()() {    i = -1;    ThrowingValue<> bomb;    i = 1;  }  void reset() { i = 0; }};testing::AssertionResult CheckHasResetContracts(HasReset* h) {  h->reset();  return testing::AssertionResult(h->i == 0);}TEST(ExceptionCheckTest, ModifyingChecker) {  auto set_to_1000 = [](FollowsBasicGuarantee* g) {    g->i = 1000;    return testing::AssertionSuccess();  };  auto is_1000 = [](FollowsBasicGuarantee* g) {    return testing::AssertionResult(g->i == 1000);  };  auto increment = [](FollowsStrongGuarantee* g) {    ++g->i;    return testing::AssertionSuccess();  };  EXPECT_FALSE(tester.WithInitialValue(FollowsBasicGuarantee{})                   .WithContracts(set_to_1000, is_1000)                   .Test());  EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{})                  .WithContracts(increment)                  .Test());  EXPECT_TRUE(testing::MakeExceptionSafetyTester()                  .WithInitialValue(HasReset{})                  .WithContracts(CheckHasResetContracts)                  .Test(invoker));}TEST(ExceptionSafetyTesterTest, ResetsCountdown) {  auto test =      testing::MakeExceptionSafetyTester()          .WithInitialValue(ThrowingValue<>())          .WithContracts([](ThrowingValue<>*) { return AssertionSuccess(); })          .WithOperation([](ThrowingValue<>*) {});  ASSERT_TRUE(test.Test());  // If the countdown isn't reset because there were no exceptions thrown, then  // this will fail with a termination from an unhandled exception  EXPECT_TRUE(test.Test());}struct NonCopyable : public NonNegative {  NonCopyable(const NonCopyable&) = delete;  NonCopyable() : NonNegative{0} {}  void operator()() { ThrowingValue<> bomb; }};TEST(ExceptionCheckTest, NonCopyable) {  auto factory = []() { return absl::make_unique<NonCopyable>(); };  EXPECT_TRUE(tester.WithFactory(factory).Test());  EXPECT_TRUE(strong_tester.WithFactory(factory).Test());}struct NonEqualityComparable : public NonNegative {  void operator()() { ThrowingValue<> bomb; }  void ModifyOnThrow() {    ++i;    ThrowingValue<> bomb;    static_cast<void>(bomb);    --i;  }};TEST(ExceptionCheckTest, NonEqualityComparable) {  auto nec_is_strong = [](NonEqualityComparable* nec) {    return testing::AssertionResult(nec->i == NonEqualityComparable().i);  };  auto strong_nec_tester = tester.WithInitialValue(NonEqualityComparable{})                               .WithContracts(nec_is_strong);  EXPECT_TRUE(strong_nec_tester.Test());  EXPECT_FALSE(strong_nec_tester.Test(      [](NonEqualityComparable* n) { n->ModifyOnThrow(); }));}template <typename T>struct ExhaustivenessTester {  void operator()() {    successes |= 1;    T b1;    static_cast<void>(b1);    successes |= (1 << 1);    T b2;    static_cast<void>(b2);    successes |= (1 << 2);    T b3;    static_cast<void>(b3);    successes |= (1 << 3);  }  bool operator==(const ExhaustivenessTester<ThrowingValue<>>&) const {    return true;  }  static unsigned char successes;};struct {  template <typename T>  testing::AssertionResult operator()(ExhaustivenessTester<T>*) const {    return testing::AssertionSuccess();  }} CheckExhaustivenessTesterContracts;template <typename T>unsigned char ExhaustivenessTester<T>::successes = 0;TEST(ExceptionCheckTest, Exhaustiveness) {  auto exhaust_tester = testing::MakeExceptionSafetyTester()                            .WithContracts(CheckExhaustivenessTesterContracts)                            .WithOperation(invoker);  EXPECT_TRUE(      exhaust_tester.WithInitialValue(ExhaustivenessTester<int>{}).Test());  EXPECT_EQ(ExhaustivenessTester<int>::successes, 0xF);  EXPECT_TRUE(      exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{})          .WithContracts(testing::strong_guarantee)          .Test());  EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF);}struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject {  LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) {    ++counter;    ThrowingValue<> v;    static_cast<void>(v);    --counter;  }  LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept      : TrackedObject(ABSL_PRETTY_FUNCTION) {}  static int counter;};int LeaksIfCtorThrows::counter = 0;TEST(ExceptionCheckTest, TestLeakyCtor) {  testing::TestThrowingCtor<LeaksIfCtorThrows>();  EXPECT_EQ(LeaksIfCtorThrows::counter, 1);  LeaksIfCtorThrows::counter = 0;}struct Tracked : private exceptions_internal::TrackedObject {  Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {}};TEST(ConstructorTrackerTest, CreatedBefore) {  Tracked a, b, c;  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);}TEST(ConstructorTrackerTest, CreatedAfter) {  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);  Tracked a, b, c;}TEST(ConstructorTrackerTest, NotDestroyedAfter) {  absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;  EXPECT_NONFATAL_FAILURE(      {        exceptions_internal::ConstructorTracker ct(            exceptions_internal::countdown);        new (&storage) Tracked;      },      "not destroyed");}TEST(ConstructorTrackerTest, DestroyedTwice) {  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);  EXPECT_NONFATAL_FAILURE(      {        Tracked t;        t.~Tracked();      },      "re-destroyed");}TEST(ConstructorTrackerTest, ConstructedTwice) {  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);  absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;  EXPECT_NONFATAL_FAILURE(      {        new (&storage) Tracked;        new (&storage) Tracked;        reinterpret_cast<Tracked*>(&storage)->~Tracked();      },      "re-constructed");}TEST(ThrowingValueTraitsTest, RelationalOperators) {  ThrowingValue<> a, b;  EXPECT_TRUE((std::is_convertible<decltype(a == b), bool>::value));  EXPECT_TRUE((std::is_convertible<decltype(a != b), bool>::value));  EXPECT_TRUE((std::is_convertible<decltype(a < b), bool>::value));  EXPECT_TRUE((std::is_convertible<decltype(a <= b), bool>::value));  EXPECT_TRUE((std::is_convertible<decltype(a > b), bool>::value));  EXPECT_TRUE((std::is_convertible<decltype(a >= b), bool>::value));}TEST(ThrowingAllocatorTraitsTest, Assignablility) {  EXPECT_TRUE(absl::is_move_assignable<ThrowingAllocator<int>>::value);  EXPECT_TRUE(absl::is_copy_assignable<ThrowingAllocator<int>>::value);  EXPECT_TRUE(std::is_nothrow_move_assignable<ThrowingAllocator<int>>::value);  EXPECT_TRUE(std::is_nothrow_copy_assignable<ThrowingAllocator<int>>::value);}}  // namespace}  // namespace testing
 |