17 #ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ 18 #define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ 23 #include <initializer_list> 27 #include <unordered_map> 29 #include "gtest/gtest.h" 45 return static_cast<TypeSpec>(
static_cast<T
>(
a) | static_cast<T>(b));
50 return static_cast<TypeSpec>(
static_cast<T
>(
a) & static_cast<T>(b));
55 return static_cast<AllocSpec>(
static_cast<T
>(
a) | static_cast<T>(b));
60 return static_cast<AllocSpec>(
static_cast<T
>(
a) & static_cast<T>(b));
63 namespace exceptions_internal {
77 virtual const char*
what() const noexcept {
return msg_.c_str(); }
105 int countdown) noexcept;
118 assert(current_tracker_instance_ ==
nullptr);
119 current_tracker_instance_ =
this;
123 assert(current_tracker_instance_ ==
this);
124 current_tracker_instance_ =
nullptr;
126 for (
auto& it : address_map_) {
127 void* address = it.first;
130 ADD_FAILURE() << ErrorMessage(address, tracked_address.
description,
131 countdown_,
"Object was not destroyed.");
137 if (!CurrentlyTracking())
return;
140 current_tracker_instance_->address_map_[address];
142 ADD_FAILURE() << ErrorMessage(
144 current_tracker_instance_->countdown_,
145 "Object was re-constructed. Current object was constructed by " +
148 tracked_address = {
true,
std::move(description)};
152 if (!CurrentlyTracking())
return;
154 auto it = current_tracker_instance_->address_map_.find(address);
156 if (it == current_tracker_instance_->address_map_.end())
return;
160 ADD_FAILURE() << ErrorMessage(address, tracked_address.
description,
161 current_tracker_instance_->countdown_,
162 "Object was re-destroyed.");
169 return current_tracker_instance_ !=
nullptr;
173 const std::string& address_description,
175 const std::string& error_description) {
177 "With coundtown at $0:\n" 179 " Object originally constructed by $2\n" 180 " Object address: $3\n",
181 countdown, error_description, address_description, address);
253 template <TypeSpec Spec = TypeSpec::kEverythingThrows>
256 return static_cast<bool>(Spec & spec);
259 static constexpr
int kDefaultValue = 0;
260 static constexpr
int kBadValue = 938550620;
265 dummy_ = kDefaultValue;
270 : TrackedObject(GetInstanceString(other.dummy_)) {
274 dummy_ = other.dummy_;
278 IsSpecified(
TypeSpec::kNoThrowMove))
279 : TrackedObject(GetInstanceString(other.dummy_)) {
283 dummy_ = other.dummy_;
292 : TrackedObject(GetInstanceString(i)), dummy_(i) {}
303 dummy_ = other.dummy_;
308 IsSpecified(
TypeSpec::kNoThrowMove)) {
313 dummy_ = other.dummy_;
431 return dummy_ && other.
dummy_;
436 return dummy_ || other.
dummy_;
527 return os << GetInstanceString(tv.
dummy_);
537 template <
typename... Args>
538 static void*
operator new(
size_t s, Args&&... args) noexcept(
543 return ::operator
new(s, std::forward<Args>(args)...);
546 template <
typename... Args>
547 static void*
operator new[](
size_t s, Args&&... args) noexcept(
552 return ::operator
new[](s, std::forward<Args>(args)...);
563 void operator delete(
void* p) noexcept { ::operator
delete(p); }
565 template <
typename... Args>
566 void operator delete(
void* p, Args&&... args) noexcept {
567 ::operator
delete(p, std::forward<Args>(args)...);
570 void operator delete[](
void* p) noexcept { return ::operator
delete[](p); }
572 template <
typename... Args>
573 void operator delete[](
void* p, Args&&... args) noexcept {
574 return ::operator
delete[](p, std::forward<Args>(args)...);
579 int&
Get() noexcept {
return dummy_; }
580 const int&
Get() const noexcept {
return dummy_; }
593 template <TypeSpec Spec,
typename T>
595 template <TypeSpec Spec,
typename T>
617 template <
typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
620 return static_cast<bool>(Spec & spec);
635 std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>;
643 dummy_ = std::make_shared<const int>(next_id_++);
646 template <
typename U>
648 : TrackedObject(GetInstanceString(*other.State())),
649 dummy_(other.State()) {}
654 : TrackedObject(GetInstanceString(*other.State())),
655 dummy_(other.State()) {}
657 template <
typename U>
659 : TrackedObject(GetInstanceString(*other.State())),
660 dummy_(
std::
move(other.State())) {}
663 : TrackedObject(GetInstanceString(*other.State())),
664 dummy_(
std::
move(other.State())) {}
669 dummy_ = other.
State();
673 template <
typename U>
676 dummy_ = other.
State();
680 template <
typename U>
686 template <
typename U>
693 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
694 return static_cast<pointer>(::operator
new(
n *
sizeof(T)));
698 IsSpecified(
AllocSpec::kNoThrowAllocate)) {
704 ::operator
delete(
static_cast<void*
>(
ptr));
707 template <
typename U,
typename... Args>
709 IsSpecified(
AllocSpec::kNoThrowAllocate)) {
710 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
711 ::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
714 template <
typename U>
721 return (std::numeric_limits<difference_type>::max)() /
sizeof(
value_type);
725 IsSpecified(
AllocSpec::kNoThrowAllocate)) {
727 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
731 template <
typename U>
733 return dummy_ == other.dummy_;
736 template <
typename U>
738 return dummy_ != other.dummy_;
741 template <
typename, AllocSpec>
751 const std::shared_ptr<const int>&
State()
const {
return dummy_; }
752 std::shared_ptr<const int>&
State() {
return dummy_; }
757 if (*dummy_ < 0) std::abort();
771 template <
typename T, AllocSpec Spec>
777 template <
typename T,
typename... Args>
782 for (
int count = 0;; ++count) {
786 T temp(std::forward<Args>(args)...);
787 static_cast<void>(temp);
797 template <
typename Operation>
805 return testing::AssertionSuccess();
807 return testing::AssertionFailure()
808 <<
"TestException thrown during call to operation() when nothrow " 809 "guarantee was expected.";
811 return testing::AssertionFailure()
812 <<
"Unknown exception thrown during call to operation() when " 813 "nothrow guarantee was expected.";
817 namespace exceptions_internal {
822 template <
typename T>
826 std::unique_ptr<T>
operator()()
const {
return absl::make_unique<T>(t_); }
832 template <
size_t LazyContractsCount,
typename LazyFactory,
833 typename LazyOperation>
835 LazyContractsCount != 0 &&
856 namespace exceptions_internal {
857 template <
typename T>
860 template <
typename T,
typename D>
863 template <
typename Factory>
865 using type = decltype(std::declval<const Factory&>()());
870 template <
typename Factory>
873 template <
typename Factory>
876 template <
typename T>
878 using Factory = std::function<std::unique_ptr<T>()>;
880 using Contract = std::function<AssertionResult(T*)>;
883 template <
typename... Contracts>
885 const Contracts&... contracts)
886 : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {}
889 for (
int count = 0;; ++count) {
892 for (
const auto& contract : contracts_) {
893 auto t_ptr = factory_();
896 operation_(t_ptr.get());
901 return AssertionSuccess();
903 if (!contract(t_ptr.get())) {
904 return AssertionFailure() << e.
what() <<
" failed contract check";
912 template <
typename ContractFn>
914 return [contract](T* t_ptr) {
return AssertionResult(contract(t_ptr)); };
918 return [
this](T* t_ptr) {
return AssertionResult(*factory_() == *t_ptr); };
972 template <
typename T>
985 template <
typename NewFactory>
988 return {new_factory, operation_, contracts_};
996 template <
typename NewOperation>
999 return {factory_, new_operation, contracts_};
1015 template <
typename... MoreContracts>
1020 factory_, operation_,
1022 more_contracts...))};
1042 typename NewOperation,
1044 testing::AssertionResult
Test(
const NewOperation& new_operation)
const {
1061 typename LazyOperation = Operation,
1063 testing::AssertionResult
Test()
const {
1064 return Test(operation_);
1068 template <
typename,
typename,
typename...>
1076 const std::tuple<Contracts...>&
i)
1077 : factory_(f), operation_(o), contracts_(i) {}
1079 template <
typename SelectedOperation,
size_t... Indices>
1080 testing::AssertionResult
TestImpl(SelectedOperation selected_operation,
1083 factory_, selected_operation, std::get<Indices>(contracts_)...)
1096 #endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
friend std::ostream & operator<<(std::ostream &os, const ThrowingValue &tv)
ThrowingValue & operator<<=(int shift)
exceptions_internal::StrongGuaranteeTagType strong_guarantee
std::false_type is_always_equal
std::unordered_map< void *, TrackedAddress > address_map_
ExceptionSafetyTestBuilder< absl::decay_t< NewFactory >, Operation, Contracts... > WithFactory(const NewFactory &new_factory) const
ExceptionSafetyTestBuilder(const Factory &f, const Operation &o, const std::tuple< Contracts... > &i)
ExceptionSafetyTestBuilder< Factory, absl::decay_t< NewOperation >, Contracts... > WithOperation(const NewOperation &new_operation) const
virtual const char * what() const noexcept
void operator,(const ThrowingValue< Spec > &, T &&)=delete
ThrowingBool(bool b) noexcept
static std::string GetInstanceString(int dummy)
ptrdiff_t difference_type
ThrowingBool operator!() const
bool operator==(const ThrowingAllocator< U, Spec > &other) const noexcept
ExceptionSafetyTestBuilder< Factory, Operation, Contracts..., absl::decay_t< MoreContracts >... > WithContracts(const MoreContracts &...more_contracts) const
bool operator!=(const ThrowingAllocator< U, Spec > &other) const noexcept
ThrowingValue operator--(int)
ConstructorTracker(int count)
ThrowingValue(const ThrowingValue &other) noexcept(IsSpecified(TypeSpec::kNoThrowCopy))
ThrowingValue & operator|=(const ThrowingValue &other)
ThrowingValue operator+() const
AssertionResult Test() const
void SetCountdown(int i=0)
testing::AssertionResult FailureMessage(const TestException &e, int countdown) noexcept
const void * const_void_pointer
ThrowingValue & operator=(ThrowingValue &&other) noexcept(IsSpecified(TypeSpec::kNoThrowMove))
ThrowingValue operator&(const ThrowingValue &other) const
ThrowingValue operator-() const
ThrowingValue & operator/=(const ThrowingValue &other)
friend std::istream & operator>>(std::istream &is, const ThrowingValue &)
ThrowingValue(int i, exceptions_internal::NoThrowTag) noexcept
typename std::decay< T >::type decay_t
ThrowingValue & operator>>=(int shift)
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
typename FactoryPtrTypeHelper< Factory >::type FactoryPtrType
static void ObjectDestructed(void *address)
std::function< void(T *)> Operation
ThrowingValue operator/(const ThrowingValue &other) const
exceptions_internal::ExceptionSafetyTestBuilder MakeExceptionSafetyTester()
std::shared_ptr< const int > dummy_
DefaultFactory(const T &t)
ThrowingValue & operator*=(const ThrowingValue &other)
ThrowingValue & operator--()
TrackedObject(std::string description)
ThrowingValue operator-(const ThrowingValue &other) const
ThrowingAllocator(const ThrowingAllocator &other) noexcept
const std::shared_ptr< const int > & State() const
ThrowingValue & operator++()
friend ThrowingBool operator<=(const ThrowingValue &a, const ThrowingValue &b)
std::function< AssertionResult(T *)> Contract
ThrowingValue(ThrowingValue &&other) noexcept(IsSpecified(TypeSpec::kNoThrowMove))
ThrowingValue operator^(const ThrowingValue &other) const
std::vector< Contract > contracts_
ThrowingValue operator++(int)
ThrowingAllocator & operator=(const ThrowingAllocator &other) noexcept
typename std::enable_if< B, T >::type enable_if_t
typename FactoryPtrType< Factory >::element_type FactoryElementType
Contract WrapContract(StrongGuaranteeTagType)
const T & const_reference
static constexpr bool IsSpecified(TypeSpec spec)
ThrowingValue operator%(const ThrowingValue &other) const
ThrowingBool operator&&(const ThrowingValue &other) const
std::unique_ptr< T > operator()() const
ThrowingValue operator+(const ThrowingValue &other) const
pointer allocate(size_type n) noexcept(IsSpecified(AllocSpec::kNoThrowAllocate))
testing::AssertionResult Test() const
friend ThrowingBool operator!=(const ThrowingValue &a, const ThrowingValue &b)
std::function< std::unique_ptr< T >()> Factory
const int & Get() const noexcept
ThrowingValue operator*(const ThrowingValue &other) const
std::true_type propagate_on_container_swap
ThrowingAllocator select_on_container_copy_construction() noexcept(IsSpecified(AllocSpec::kNoThrowAllocate))
ThrowingValue operator<<(int shift) const
ExceptionSafetyTest(const Factory &f, const Operation &op, const Contracts &...contracts)
size_type max_size() const noexcept
void construct(U *ptr, Args &&...args) noexcept(IsSpecified(AllocSpec::kNoThrowAllocate))
ThrowingValue operator~() const
static bool CurrentlyTracking()
static ConstructorTracker * current_tracker_instance_
Contract WrapContract(const ContractFn &contract)
constexpr TypeSpec operator|(TypeSpec a, TypeSpec b)
void TestThrowingCtor(Args &&...args)
std::shared_ptr< const int > & State()
static void ObjectConstructed(void *address, std::string description)
friend class ExceptionSafetyTestBuilder
void deallocate(pointer ptr, size_type) noexcept
ThrowingValue & operator%=(const ThrowingValue &other)
typename absl::enable_if_t< LazyContractsCount!=0 &&!std::is_same< LazyFactory, UninitializedT >::value &&!std::is_same< LazyOperation, UninitializedT >::value > EnableIfTestable
ThrowingAllocator(ThrowingAllocator &&other) noexcept
std::true_type propagate_on_container_move_assignment
ExceptionSafetyTestBuilder()
friend ThrowingBool operator>=(const ThrowingValue &a, const ThrowingValue &b)
friend ThrowingBool operator<(const ThrowingValue &a, const ThrowingValue &b)
TestException(absl::string_view msg)
static constexpr bool IsSpecified(AllocSpec spec)
ThrowingValue operator|(const ThrowingValue &other) const
ThrowingValue & operator-=(const ThrowingValue &other)
make_index_sequence< sizeof...(Ts)> index_sequence_for
std::true_type propagate_on_container_copy_assignment
ThrowingAllocator & operator=(const ThrowingAllocator< U, Spec > &other) noexcept
ThrowingAllocator(const ThrowingAllocator< U, Spec > &other) noexcept
testing::AssertionResult TestImpl(SelectedOperation selected_operation, absl::index_sequence< Indices... >) const
ThrowingValue & operator&=(const ThrowingValue &other)
exceptions_internal::NoThrowTag nothrow_ctor
constexpr TypeSpec operator&(TypeSpec a, TypeSpec b)
friend ThrowingBool operator==(const ThrowingValue &a, const ThrowingValue &b)
static std::string GetInstanceString(int dummy)
ThrowingBool operator||(const ThrowingValue &other) const
ThrowingValue & operator+=(const ThrowingValue &other)
ThrowingAllocator & operator=(ThrowingAllocator< U, Spec > &&other) noexcept
testing::AssertionResult TestNothrowOp(const Operation &operation)
decltype(std::declval< const Factory & >()()) type
typename std::underlying_type< T >::type underlying_type_t
static std::string ErrorMessage(void *address, const std::string &address_description, int countdown, const std::string &error_description)
ThrowingValue operator>>(int shift) const
~TrackedObject() noexcept
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
pointer allocate(size_type n, const_void_pointer) noexcept(IsSpecified(AllocSpec::kNoThrowAllocate))
void ReadStateAndMaybeThrow(absl::string_view msg) const
ABSL_MUST_USE_RESULT std::string Substitute(absl::string_view format)
ThrowingValue & operator^=(const ThrowingValue &other)
ThrowingValue & operator=(const ThrowingValue &other) noexcept(IsSpecified(TypeSpec::kNoThrowCopy))
std::string GetSpecString(TypeSpec spec)
std::tuple< Contracts... > contracts_
void MaybeThrow(absl::string_view msg, bool throw_bad_alloc)
ExceptionSafetyTestBuilder< DefaultFactory< T >, Operation, Contracts... > WithInitialValue(const T &t) const
std::integral_constant< bool, Spec==AllocSpec::kNoThrowAllocate > is_nothrow
friend ThrowingBool operator>(const ThrowingValue &a, const ThrowingValue &b)
ThrowingAllocator(ThrowingAllocator< U, Spec > &&other) noexcept
TestBadAllocException(absl::string_view msg)
void destroy(U *p) noexcept
testing::AssertionResult Test(const NewOperation &new_operation) const