17 #ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
18 #define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
20 #include "absl/base/config.h"
22 #ifdef ABSL_HAVE_EXCEPTIONS
27 #include <initializer_list>
31 #include <unordered_map>
33 #include "gtest/gtest.h"
34 #include "absl/base/internal/pretty_function.h"
35 #include "absl/memory/memory.h"
36 #include "absl/meta/type_traits.h"
37 #include "absl/strings/string_view.h"
38 #include "absl/strings/substitute.h"
39 #include "absl/utility/utility.h"
46 constexpr TypeSpec
operator|(TypeSpec
a, TypeSpec
b) {
48 return static_cast<TypeSpec
>(
static_cast<T>(
a) |
static_cast<T>(
b));
51 constexpr TypeSpec
operator&(TypeSpec
a, TypeSpec
b) {
53 return static_cast<TypeSpec
>(
static_cast<T>(
a) &
static_cast<T>(
b));
56 constexpr AllocSpec
operator|(AllocSpec
a, AllocSpec
b) {
58 return static_cast<AllocSpec
>(
static_cast<T>(
a) |
static_cast<T>(
b));
61 constexpr AllocSpec
operator&(AllocSpec
a, AllocSpec
b) {
63 return static_cast<AllocSpec
>(
static_cast<T>(
a) &
static_cast<T>(
b));
66 namespace exceptions_internal {
72 struct StrongGuaranteeTagType {};
79 virtual ~TestException() {}
80 virtual const char* what()
const noexcept {
return msg_.c_str(); }
91 class TestBadAllocException :
public std::bad_alloc,
public TestException {
94 using TestException::what;
101 inline void SetCountdown(
int i = 0) { countdown =
i; }
103 inline void UnsetCountdown() { SetCountdown(-1); }
108 int countdown) noexcept;
110 struct TrackedAddress {
118 class ConstructorTracker {
120 explicit ConstructorTracker(
int count) : countdown_(
count) {
121 assert(current_tracker_instance_ ==
nullptr);
122 current_tracker_instance_ =
this;
125 ~ConstructorTracker() {
126 assert(current_tracker_instance_ ==
this);
127 current_tracker_instance_ =
nullptr;
129 for (
auto&
it : address_map_) {
130 void* address =
it.first;
131 TrackedAddress& tracked_address =
it.second;
132 if (tracked_address.is_alive) {
133 ADD_FAILURE() << ErrorMessage(address, tracked_address.description,
134 countdown_,
"Object was not destroyed.");
140 if (!CurrentlyTracking())
return;
142 TrackedAddress& tracked_address =
143 current_tracker_instance_->address_map_[address];
144 if (tracked_address.is_alive) {
146 address, tracked_address.description,
147 current_tracker_instance_->countdown_,
148 "Object was re-constructed. Current object was constructed by " +
154 static void ObjectDestructed(
void* address) {
155 if (!CurrentlyTracking())
return;
157 auto it = current_tracker_instance_->address_map_.find(address);
159 if (
it == current_tracker_instance_->address_map_.end())
return;
161 TrackedAddress& tracked_address =
it->second;
162 if (!tracked_address.is_alive) {
163 ADD_FAILURE() << ErrorMessage(address, tracked_address.description,
164 current_tracker_instance_->countdown_,
165 "Object was re-destroyed.");
167 tracked_address.is_alive =
false;
171 static bool CurrentlyTracking() {
172 return current_tracker_instance_ !=
nullptr;
180 "With coundtown at $0:\n"
182 " Object originally constructed by $2\n"
183 " Object address: $3\n",
184 countdown, error_description, address_description, address);
187 std::unordered_map<void*, TrackedAddress> address_map_;
190 static ConstructorTracker* current_tracker_instance_;
193 class TrackedObject {
195 TrackedObject(
const TrackedObject&) =
delete;
196 TrackedObject(TrackedObject&&) =
delete;
203 ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(
this); }
207 extern exceptions_internal::NoThrowTag nothrow_ctor;
209 extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
215 ThrowingBool(
bool b) noexcept :
b_(
b) {}
216 operator bool()
const {
217 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
235 enum class TypeSpec {
236 kEverythingThrows = 0,
238 kNoThrowMove = 1 << 1,
239 kNoThrowNew = 1 << 2,
256 template <TypeSpec Spec = TypeSpec::kEverythingThrows>
257 class ThrowingValue :
private exceptions_internal::TrackedObject {
258 static constexpr
bool IsSpecified(TypeSpec
spec) {
259 return static_cast<bool>(Spec &
spec);
262 static constexpr
int kDefaultValue = 0;
263 static constexpr
int kBadValue = 938550620;
266 ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) {
267 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
268 dummy_ = kDefaultValue;
271 ThrowingValue(
const ThrowingValue& other) noexcept(
272 IsSpecified(TypeSpec::kNoThrowCopy))
273 : TrackedObject(GetInstanceString(other.dummy_)) {
274 if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
275 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
277 dummy_ = other.dummy_;
280 ThrowingValue(ThrowingValue&& other) noexcept(
281 IsSpecified(TypeSpec::kNoThrowMove))
282 : TrackedObject(GetInstanceString(other.dummy_)) {
283 if (!IsSpecified(TypeSpec::kNoThrowMove)) {
284 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
286 dummy_ = other.dummy_;
289 explicit ThrowingValue(
int i) : TrackedObject(GetInstanceString(
i)) {
290 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
294 ThrowingValue(
int i, exceptions_internal::NoThrowTag) noexcept
295 : TrackedObject(GetInstanceString(i)), dummy_(i) {}
298 ~ThrowingValue() noexcept =
default;
300 ThrowingValue& operator=(
const ThrowingValue& other) noexcept(
301 IsSpecified(TypeSpec::kNoThrowCopy)) {
303 if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
304 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
306 dummy_ = other.dummy_;
310 ThrowingValue& operator=(ThrowingValue&& other) noexcept(
311 IsSpecified(TypeSpec::kNoThrowMove)) {
313 if (!IsSpecified(TypeSpec::kNoThrowMove)) {
314 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
316 dummy_ = other.dummy_;
321 ThrowingValue
operator+(
const ThrowingValue& other)
const {
322 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
323 return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor);
327 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
328 return ThrowingValue(dummy_, nothrow_ctor);
331 ThrowingValue
operator-(
const ThrowingValue& other)
const {
332 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
333 return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor);
337 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
338 return ThrowingValue(-dummy_, nothrow_ctor);
342 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
348 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
349 auto out = ThrowingValue(dummy_, nothrow_ctor);
354 ThrowingValue& operator--() {
355 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
360 ThrowingValue operator--(
int) {
361 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
362 auto out = ThrowingValue(dummy_, nothrow_ctor);
367 ThrowingValue
operator*(
const ThrowingValue& other)
const {
368 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
369 return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor);
372 ThrowingValue
operator/(
const ThrowingValue& other)
const {
373 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
374 return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor);
377 ThrowingValue
operator%(
const ThrowingValue& other)
const {
378 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
379 return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor);
383 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
384 return ThrowingValue(dummy_ << shift, nothrow_ctor);
388 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
389 return ThrowingValue(dummy_ >> shift, nothrow_ctor);
395 friend ThrowingBool
operator==(
const ThrowingValue& a,
396 const ThrowingValue&
b) {
397 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
398 return a.dummy_ ==
b.dummy_;
400 friend ThrowingBool
operator!=(
const ThrowingValue& a,
401 const ThrowingValue&
b) {
402 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
403 return a.dummy_ !=
b.dummy_;
405 friend ThrowingBool
operator<(
const ThrowingValue& a,
406 const ThrowingValue&
b) {
407 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
408 return a.dummy_ <
b.dummy_;
410 friend ThrowingBool
operator<=(
const ThrowingValue& a,
411 const ThrowingValue&
b) {
412 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
413 return a.dummy_ <=
b.dummy_;
415 friend ThrowingBool
operator>(
const ThrowingValue& a,
416 const ThrowingValue&
b) {
417 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
418 return a.dummy_ >
b.dummy_;
420 friend ThrowingBool
operator>=(
const ThrowingValue& a,
421 const ThrowingValue&
b) {
422 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
423 return a.dummy_ >=
b.dummy_;
428 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
432 ThrowingBool operator&&(
const ThrowingValue& other)
const {
433 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
434 return dummy_ && other.dummy_;
437 ThrowingBool operator||(
const ThrowingValue& other)
const {
438 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
439 return dummy_ || other.dummy_;
444 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
445 return ThrowingValue(~dummy_, nothrow_ctor);
448 ThrowingValue
operator&(
const ThrowingValue& other)
const {
449 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
450 return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor);
453 ThrowingValue
operator|(
const ThrowingValue& other)
const {
454 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
455 return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor);
458 ThrowingValue
operator^(
const ThrowingValue& other)
const {
459 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
460 return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor);
464 ThrowingValue&
operator+=(
const ThrowingValue& other) {
465 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
466 dummy_ += other.dummy_;
470 ThrowingValue&
operator-=(
const ThrowingValue& other) {
471 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
472 dummy_ -= other.dummy_;
476 ThrowingValue&
operator*=(
const ThrowingValue& other) {
477 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
478 dummy_ *= other.dummy_;
482 ThrowingValue&
operator/=(
const ThrowingValue& other) {
483 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
484 dummy_ /= other.dummy_;
488 ThrowingValue&
operator%=(
const ThrowingValue& other) {
489 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
490 dummy_ %= other.dummy_;
494 ThrowingValue&
operator&=(
const ThrowingValue& other) {
495 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
496 dummy_ &= other.dummy_;
500 ThrowingValue&
operator|=(
const ThrowingValue& other) {
501 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
502 dummy_ |= other.dummy_;
506 ThrowingValue&
operator^=(
const ThrowingValue& other) {
507 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
508 dummy_ ^= other.dummy_;
512 ThrowingValue& operator<<=(
int shift) {
513 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
518 ThrowingValue& operator>>=(
int shift) {
519 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
528 friend std::ostream&
operator<<(std::ostream& os,
const ThrowingValue& tv) {
529 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
530 return os << GetInstanceString(tv.dummy_);
533 friend std::istream&
operator>>(std::istream& is,
const ThrowingValue&) {
534 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
539 static void*
operator new(
size_t s) noexcept(
540 IsSpecified(TypeSpec::kNoThrowNew)) {
541 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
542 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION,
true);
544 return ::operator
new(
s);
547 static void*
operator new[](
size_t s) noexcept(
548 IsSpecified(TypeSpec::kNoThrowNew)) {
549 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
550 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION,
true);
552 return ::operator
new[](
s);
555 template <
typename...
Args>
556 static void*
operator new(
size_t s,
Args&&...
args) noexcept(
557 IsSpecified(TypeSpec::kNoThrowNew)) {
558 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
559 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION,
true);
561 return ::operator
new(
s, std::forward<Args>(
args)...);
564 template <
typename...
Args>
565 static void*
operator new[](
size_t s,
Args&&...
args) noexcept(
566 IsSpecified(TypeSpec::kNoThrowNew)) {
567 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
568 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION,
true);
570 return ::operator
new[](
s, std::forward<Args>(
args)...);
575 void operator delete(
void*
p) noexcept { ::operator
delete(
p); }
577 template <
typename...
Args>
578 void operator delete(
void*
p,
Args&&...
args) noexcept {
579 ::operator
delete(
p, std::forward<Args>(
args)...);
582 void operator delete[](
void*
p) noexcept { return ::operator
delete[](
p); }
584 template <
typename...
Args>
585 void operator delete[](
void*
p,
Args&&...
args) noexcept {
586 return ::operator
delete[](
p, std::forward<Args>(
args)...);
591 int&
Get() noexcept {
return dummy_; }
592 const int&
Get()
const noexcept {
return dummy_; }
597 exceptions_internal::GetSpecString(Spec),
">(",
dummy,
605 template <TypeSpec Spec,
typename T>
606 void operator,(
const ThrowingValue<Spec>&,
T&&) =
delete;
607 template <TypeSpec Spec,
typename T>
608 void operator,(
T&&,
const ThrowingValue<Spec>&) =
delete;
617 enum class AllocSpec {
618 kEverythingThrows = 0,
619 kNoThrowAllocate = 1,
629 template <
typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
630 class ThrowingAllocator :
private exceptions_internal::TrackedObject {
631 static constexpr
bool IsSpecified(AllocSpec
spec) {
632 return static_cast<bool>(Spec &
spec);
638 using reference =
T&;
640 using void_pointer =
void*;
641 using const_void_pointer =
const void*;
643 using size_type = size_t;
644 using difference_type = ptrdiff_t;
647 std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>;
653 ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) {
654 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
655 dummy_ = std::make_shared<const int>(next_id_++);
658 template <
typename U>
659 ThrowingAllocator(
const ThrowingAllocator<U, Spec>& other) noexcept
660 : TrackedObject(GetInstanceString(*other.State())),
661 dummy_(other.State()) {}
665 ThrowingAllocator(
const ThrowingAllocator& other) noexcept
666 : TrackedObject(GetInstanceString(*other.State())),
667 dummy_(other.State()) {}
669 template <
typename U>
670 ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept
671 : TrackedObject(GetInstanceString(*other.State())),
674 ThrowingAllocator(ThrowingAllocator&& other) noexcept
675 : TrackedObject(GetInstanceString(*other.State())),
678 ~ThrowingAllocator() noexcept =
default;
680 ThrowingAllocator& operator=(
const ThrowingAllocator& other) noexcept {
681 dummy_ = other.State();
685 template <
typename U>
686 ThrowingAllocator& operator=(
687 const ThrowingAllocator<U, Spec>& other) noexcept {
688 dummy_ = other.State();
692 template <
typename U>
693 ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept {
698 template <
typename U>
700 using other = ThrowingAllocator<U, Spec>;
703 pointer allocate(size_type n) noexcept(
704 IsSpecified(AllocSpec::kNoThrowAllocate)) {
705 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
706 return static_cast<pointer
>(::operator
new(
n *
sizeof(
T)));
709 pointer allocate(size_type n, const_void_pointer) noexcept(
710 IsSpecified(AllocSpec::kNoThrowAllocate)) {
714 void deallocate(pointer
ptr, size_type) noexcept {
716 ::operator
delete(
static_cast<void*
>(
ptr));
719 template <
typename U,
typename...
Args>
721 IsSpecified(AllocSpec::kNoThrowAllocate)) {
722 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
723 ::new (
static_cast<void*
>(
ptr)) U(std::forward<Args>(
args)...);
726 template <
typename U>
732 size_type max_size()
const noexcept {
736 ThrowingAllocator select_on_container_copy_construction() noexcept(
737 IsSpecified(AllocSpec::kNoThrowAllocate)) {
738 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
742 template <
typename U>
743 bool operator==(
const ThrowingAllocator<U, Spec>& other)
const noexcept {
744 return dummy_ == other.dummy_;
747 template <
typename U>
748 bool operator!=(
const ThrowingAllocator<U, Spec>& other)
const noexcept {
749 return dummy_ != other.dummy_;
752 template <
typename, AllocSpec>
753 friend class ThrowingAllocator;
758 exceptions_internal::GetSpecString(Spec),
">(",
dummy,
762 const std::shared_ptr<const int>& State()
const {
return dummy_; }
763 std::shared_ptr<const int>& State() {
return dummy_; }
768 if (*dummy_ < 0) std::abort();
772 if (!IsSpecified(AllocSpec::kNoThrowAllocate)) {
773 exceptions_internal::MaybeThrow(
779 std::shared_ptr<const int> dummy_;
782 template <
typename T, AllocSpec Spec>
783 int ThrowingAllocator<T, Spec>::next_id_ = 0;
788 template <
typename T,
typename...
Args>
789 void TestThrowingCtor(
Args&&...
args) {
791 ~Cleanup() { exceptions_internal::UnsetCountdown(); }
794 exceptions_internal::ConstructorTracker ct(
count);
795 exceptions_internal::SetCountdown(
count);
798 static_cast<void>(
temp);
800 }
catch (
const exceptions_internal::TestException&) {
808 template <
typename Operation>
811 Cleanup() { exceptions_internal::SetCountdown(); }
812 ~Cleanup() { exceptions_internal::UnsetCountdown(); }
817 }
catch (
const exceptions_internal::TestException&) {
819 <<
"TestException thrown during call to operation() when nothrow "
820 "guarantee was expected.";
823 <<
"Unknown exception thrown during call to operation() when "
824 "nothrow guarantee was expected.";
828 namespace exceptions_internal {
831 struct UninitializedT {};
833 template <
typename T>
834 class DefaultFactory {
836 explicit DefaultFactory(
const T& t) : t_(
t) {}
837 std::unique_ptr<T> operator()()
const {
return absl::make_unique<T>(t_); }
843 template <
size_t LazyContractsCount,
typename LazyFactory,
844 typename LazyOperation>
846 LazyContractsCount != 0 &&
850 template <
typename Factory = UninitializedT,
851 typename Operation = UninitializedT,
typename... Contracts>
852 class ExceptionSafetyTestBuilder;
865 exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester();
867 namespace exceptions_internal {
868 template <
typename T>
871 template <
typename T,
typename D>
874 template <
typename Factory>
875 struct FactoryPtrTypeHelper {
876 using type = decltype(std::declval<const Factory&>()());
881 template <
typename Factory>
884 template <
typename Factory>
885 using FactoryElementType =
typename FactoryPtrType<Factory>::element_type;
887 template <
typename T>
888 class ExceptionSafetyTest {
889 using Factory = std::function<std::unique_ptr<T>()>;
894 template <
typename... Contracts>
895 explicit ExceptionSafetyTest(
const Factory& f,
const Operation&
op,
896 const Contracts&... contracts)
897 : factory_(
f), operation_(
op), contracts_{WrapContract(contracts)...} {}
899 AssertionResult
Test()
const {
901 exceptions_internal::ConstructorTracker ct(
count);
903 for (
const auto& contract : contracts_) {
904 auto t_ptr = factory_();
907 operation_(t_ptr.get());
913 }
catch (
const exceptions_internal::TestException& e) {
914 if (!contract(t_ptr.get())) {
923 template <
typename ContractFn>
924 Contract WrapContract(
const ContractFn& contract) {
925 return [contract](
T* t_ptr) {
return AssertionResult(contract(t_ptr)); };
928 Contract WrapContract(StrongGuaranteeTagType) {
929 return [
this](
T* t_ptr) {
return AssertionResult(*factory_() == *t_ptr); };
934 std::vector<Contract> contracts_;
968 template <
typename Factory,
typename Operation,
typename... Contracts>
969 class ExceptionSafetyTestBuilder {
983 template <
typename T>
984 ExceptionSafetyTestBuilder<DefaultFactory<T>,
Operation, Contracts...>
985 WithInitialValue(
const T& t)
const {
986 return WithFactory(DefaultFactory<T>(t));
996 template <
typename NewFactory>
997 ExceptionSafetyTestBuilder<absl::decay_t<NewFactory>,
Operation, Contracts...>
998 WithFactory(
const NewFactory& new_factory)
const {
999 return {new_factory, operation_, contracts_};
1007 template <
typename NewOperation>
1008 ExceptionSafetyTestBuilder<Factory, absl::decay_t<NewOperation>, Contracts...>
1009 WithOperation(
const NewOperation& new_operation)
const {
1010 return {factory_, new_operation, contracts_};
1026 template <
typename... MoreContracts>
1027 ExceptionSafetyTestBuilder<Factory,
Operation, Contracts...,
1029 WithContracts(
const MoreContracts&... more_contracts)
const {
1031 factory_, operation_,
1033 more_contracts...))};
1053 typename NewOperation,
1054 typename = EnableIfTestable<
sizeof...(Contracts), Factory, NewOperation>>
1073 typename = EnableIfTestable<
sizeof...(Contracts), Factory, LazyOperation>>
1075 return Test(operation_);
1079 template <
typename,
typename,
typename...>
1080 friend class ExceptionSafetyTestBuilder;
1082 friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester();
1084 ExceptionSafetyTestBuilder() {}
1086 ExceptionSafetyTestBuilder(
const Factory& f,
const Operation& o,
1087 const std::tuple<Contracts...>& i)
1088 : factory_(
f), operation_(
o), contracts_(
i) {}
1090 template <
typename SelectedOperation,
size_t... Indices>
1093 return ExceptionSafetyTest<FactoryElementType<Factory>>(
1094 factory_, selected_operation, std::get<Indices>(contracts_)...)
1100 std::tuple<Contracts...> contracts_;
1107 #endif // ABSL_HAVE_EXCEPTIONS
1109 #endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_