00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
00018 #define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
00019
00020 #include <cstddef>
00021 #include <cstdint>
00022 #include <functional>
00023 #include <initializer_list>
00024 #include <iosfwd>
00025 #include <string>
00026 #include <tuple>
00027 #include <unordered_map>
00028
00029 #include "gtest/gtest.h"
00030 #include "absl/base/config.h"
00031 #include "absl/base/internal/pretty_function.h"
00032 #include "absl/memory/memory.h"
00033 #include "absl/meta/type_traits.h"
00034 #include "absl/strings/string_view.h"
00035 #include "absl/strings/substitute.h"
00036 #include "absl/utility/utility.h"
00037
00038 namespace testing {
00039
00040 enum class TypeSpec;
00041 enum class AllocSpec;
00042
00043 constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) {
00044 using T = absl::underlying_type_t<TypeSpec>;
00045 return static_cast<TypeSpec>(static_cast<T>(a) | static_cast<T>(b));
00046 }
00047
00048 constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) {
00049 using T = absl::underlying_type_t<TypeSpec>;
00050 return static_cast<TypeSpec>(static_cast<T>(a) & static_cast<T>(b));
00051 }
00052
00053 constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) {
00054 using T = absl::underlying_type_t<AllocSpec>;
00055 return static_cast<AllocSpec>(static_cast<T>(a) | static_cast<T>(b));
00056 }
00057
00058 constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) {
00059 using T = absl::underlying_type_t<AllocSpec>;
00060 return static_cast<AllocSpec>(static_cast<T>(a) & static_cast<T>(b));
00061 }
00062
00063 namespace exceptions_internal {
00064
00065 std::string GetSpecString(TypeSpec);
00066 std::string GetSpecString(AllocSpec);
00067
00068 struct NoThrowTag {};
00069 struct StrongGuaranteeTagType {};
00070
00071
00072
00073 class TestException {
00074 public:
00075 explicit TestException(absl::string_view msg) : msg_(msg) {}
00076 virtual ~TestException() {}
00077 virtual const char* what() const noexcept { return msg_.c_str(); }
00078
00079 private:
00080 std::string msg_;
00081 };
00082
00083
00084
00085
00086
00087
00088 class TestBadAllocException : public std::bad_alloc, public TestException {
00089 public:
00090 explicit TestBadAllocException(absl::string_view msg) : TestException(msg) {}
00091 using TestException::what;
00092 };
00093
00094 extern int countdown;
00095
00096
00097
00098 inline void SetCountdown(int i = 0) { countdown = i; }
00099
00100 inline void UnsetCountdown() { SetCountdown(-1); }
00101
00102 void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false);
00103
00104 testing::AssertionResult FailureMessage(const TestException& e,
00105 int countdown) noexcept;
00106
00107 struct TrackedAddress {
00108 bool is_alive;
00109 std::string description;
00110 };
00111
00112
00113
00114
00115 class ConstructorTracker {
00116 public:
00117 explicit ConstructorTracker(int count) : countdown_(count) {
00118 assert(current_tracker_instance_ == nullptr);
00119 current_tracker_instance_ = this;
00120 }
00121
00122 ~ConstructorTracker() {
00123 assert(current_tracker_instance_ == this);
00124 current_tracker_instance_ = nullptr;
00125
00126 for (auto& it : address_map_) {
00127 void* address = it.first;
00128 TrackedAddress& tracked_address = it.second;
00129 if (tracked_address.is_alive) {
00130 ADD_FAILURE() << ErrorMessage(address, tracked_address.description,
00131 countdown_, "Object was not destroyed.");
00132 }
00133 }
00134 }
00135
00136 static void ObjectConstructed(void* address, std::string description) {
00137 if (!CurrentlyTracking()) return;
00138
00139 TrackedAddress& tracked_address =
00140 current_tracker_instance_->address_map_[address];
00141 if (tracked_address.is_alive) {
00142 ADD_FAILURE() << ErrorMessage(
00143 address, tracked_address.description,
00144 current_tracker_instance_->countdown_,
00145 "Object was re-constructed. Current object was constructed by " +
00146 description);
00147 }
00148 tracked_address = {true, std::move(description)};
00149 }
00150
00151 static void ObjectDestructed(void* address) {
00152 if (!CurrentlyTracking()) return;
00153
00154 auto it = current_tracker_instance_->address_map_.find(address);
00155
00156 if (it == current_tracker_instance_->address_map_.end()) return;
00157
00158 TrackedAddress& tracked_address = it->second;
00159 if (!tracked_address.is_alive) {
00160 ADD_FAILURE() << ErrorMessage(address, tracked_address.description,
00161 current_tracker_instance_->countdown_,
00162 "Object was re-destroyed.");
00163 }
00164 tracked_address.is_alive = false;
00165 }
00166
00167 private:
00168 static bool CurrentlyTracking() {
00169 return current_tracker_instance_ != nullptr;
00170 }
00171
00172 static std::string ErrorMessage(void* address,
00173 const std::string& address_description,
00174 int countdown,
00175 const std::string& error_description) {
00176 return absl::Substitute(
00177 "With coundtown at $0:\n"
00178 " $1\n"
00179 " Object originally constructed by $2\n"
00180 " Object address: $3\n",
00181 countdown, error_description, address_description, address);
00182 }
00183
00184 std::unordered_map<void*, TrackedAddress> address_map_;
00185 int countdown_;
00186
00187 static ConstructorTracker* current_tracker_instance_;
00188 };
00189
00190 class TrackedObject {
00191 public:
00192 TrackedObject(const TrackedObject&) = delete;
00193 TrackedObject(TrackedObject&&) = delete;
00194
00195 protected:
00196 explicit TrackedObject(std::string description) {
00197 ConstructorTracker::ObjectConstructed(this, std::move(description));
00198 }
00199
00200 ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); }
00201 };
00202 }
00203
00204 extern exceptions_internal::NoThrowTag nothrow_ctor;
00205
00206 extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
00207
00208
00209
00210 class ThrowingBool {
00211 public:
00212 ThrowingBool(bool b) noexcept : b_(b) {}
00213 operator bool() const {
00214 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00215 return b_;
00216 }
00217
00218 private:
00219 bool b_;
00220 };
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 enum class TypeSpec {
00233 kEverythingThrows = 0,
00234 kNoThrowCopy = 1,
00235 kNoThrowMove = 1 << 1,
00236 kNoThrowNew = 1 << 2,
00237 };
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 template <TypeSpec Spec = TypeSpec::kEverythingThrows>
00254 class ThrowingValue : private exceptions_internal::TrackedObject {
00255 static constexpr bool IsSpecified(TypeSpec spec) {
00256 return static_cast<bool>(Spec & spec);
00257 }
00258
00259 static constexpr int kDefaultValue = 0;
00260 static constexpr int kBadValue = 938550620;
00261
00262 public:
00263 ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) {
00264 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00265 dummy_ = kDefaultValue;
00266 }
00267
00268 ThrowingValue(const ThrowingValue& other) noexcept(
00269 IsSpecified(TypeSpec::kNoThrowCopy))
00270 : TrackedObject(GetInstanceString(other.dummy_)) {
00271 if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
00272 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00273 }
00274 dummy_ = other.dummy_;
00275 }
00276
00277 ThrowingValue(ThrowingValue&& other) noexcept(
00278 IsSpecified(TypeSpec::kNoThrowMove))
00279 : TrackedObject(GetInstanceString(other.dummy_)) {
00280 if (!IsSpecified(TypeSpec::kNoThrowMove)) {
00281 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00282 }
00283 dummy_ = other.dummy_;
00284 }
00285
00286 explicit ThrowingValue(int i) : TrackedObject(GetInstanceString(i)) {
00287 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00288 dummy_ = i;
00289 }
00290
00291 ThrowingValue(int i, exceptions_internal::NoThrowTag) noexcept
00292 : TrackedObject(GetInstanceString(i)), dummy_(i) {}
00293
00294
00295 ~ThrowingValue() noexcept = default;
00296
00297 ThrowingValue& operator=(const ThrowingValue& other) noexcept(
00298 IsSpecified(TypeSpec::kNoThrowCopy)) {
00299 dummy_ = kBadValue;
00300 if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
00301 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00302 }
00303 dummy_ = other.dummy_;
00304 return *this;
00305 }
00306
00307 ThrowingValue& operator=(ThrowingValue&& other) noexcept(
00308 IsSpecified(TypeSpec::kNoThrowMove)) {
00309 dummy_ = kBadValue;
00310 if (!IsSpecified(TypeSpec::kNoThrowMove)) {
00311 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00312 }
00313 dummy_ = other.dummy_;
00314 return *this;
00315 }
00316
00317
00318 ThrowingValue operator+(const ThrowingValue& other) const {
00319 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00320 return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor);
00321 }
00322
00323 ThrowingValue operator+() const {
00324 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00325 return ThrowingValue(dummy_, nothrow_ctor);
00326 }
00327
00328 ThrowingValue operator-(const ThrowingValue& other) const {
00329 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00330 return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor);
00331 }
00332
00333 ThrowingValue operator-() const {
00334 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00335 return ThrowingValue(-dummy_, nothrow_ctor);
00336 }
00337
00338 ThrowingValue& operator++() {
00339 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00340 ++dummy_;
00341 return *this;
00342 }
00343
00344 ThrowingValue operator++(int) {
00345 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00346 auto out = ThrowingValue(dummy_, nothrow_ctor);
00347 ++dummy_;
00348 return out;
00349 }
00350
00351 ThrowingValue& operator--() {
00352 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00353 --dummy_;
00354 return *this;
00355 }
00356
00357 ThrowingValue operator--(int) {
00358 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00359 auto out = ThrowingValue(dummy_, nothrow_ctor);
00360 --dummy_;
00361 return out;
00362 }
00363
00364 ThrowingValue operator*(const ThrowingValue& other) const {
00365 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00366 return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor);
00367 }
00368
00369 ThrowingValue operator/(const ThrowingValue& other) const {
00370 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00371 return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor);
00372 }
00373
00374 ThrowingValue operator%(const ThrowingValue& other) const {
00375 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00376 return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor);
00377 }
00378
00379 ThrowingValue operator<<(int shift) const {
00380 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00381 return ThrowingValue(dummy_ << shift, nothrow_ctor);
00382 }
00383
00384 ThrowingValue operator>>(int shift) const {
00385 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00386 return ThrowingValue(dummy_ >> shift, nothrow_ctor);
00387 }
00388
00389
00390
00391
00392 friend ThrowingBool operator==(const ThrowingValue& a,
00393 const ThrowingValue& b) {
00394 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00395 return a.dummy_ == b.dummy_;
00396 }
00397 friend ThrowingBool operator!=(const ThrowingValue& a,
00398 const ThrowingValue& b) {
00399 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00400 return a.dummy_ != b.dummy_;
00401 }
00402 friend ThrowingBool operator<(const ThrowingValue& a,
00403 const ThrowingValue& b) {
00404 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00405 return a.dummy_ < b.dummy_;
00406 }
00407 friend ThrowingBool operator<=(const ThrowingValue& a,
00408 const ThrowingValue& b) {
00409 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00410 return a.dummy_ <= b.dummy_;
00411 }
00412 friend ThrowingBool operator>(const ThrowingValue& a,
00413 const ThrowingValue& b) {
00414 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00415 return a.dummy_ > b.dummy_;
00416 }
00417 friend ThrowingBool operator>=(const ThrowingValue& a,
00418 const ThrowingValue& b) {
00419 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00420 return a.dummy_ >= b.dummy_;
00421 }
00422
00423
00424 ThrowingBool operator!() const {
00425 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00426 return !dummy_;
00427 }
00428
00429 ThrowingBool operator&&(const ThrowingValue& other) const {
00430 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00431 return dummy_ && other.dummy_;
00432 }
00433
00434 ThrowingBool operator||(const ThrowingValue& other) const {
00435 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00436 return dummy_ || other.dummy_;
00437 }
00438
00439
00440 ThrowingValue operator~() const {
00441 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00442 return ThrowingValue(~dummy_, nothrow_ctor);
00443 }
00444
00445 ThrowingValue operator&(const ThrowingValue& other) const {
00446 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00447 return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor);
00448 }
00449
00450 ThrowingValue operator|(const ThrowingValue& other) const {
00451 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00452 return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor);
00453 }
00454
00455 ThrowingValue operator^(const ThrowingValue& other) const {
00456 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00457 return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor);
00458 }
00459
00460
00461 ThrowingValue& operator+=(const ThrowingValue& other) {
00462 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00463 dummy_ += other.dummy_;
00464 return *this;
00465 }
00466
00467 ThrowingValue& operator-=(const ThrowingValue& other) {
00468 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00469 dummy_ -= other.dummy_;
00470 return *this;
00471 }
00472
00473 ThrowingValue& operator*=(const ThrowingValue& other) {
00474 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00475 dummy_ *= other.dummy_;
00476 return *this;
00477 }
00478
00479 ThrowingValue& operator/=(const ThrowingValue& other) {
00480 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00481 dummy_ /= other.dummy_;
00482 return *this;
00483 }
00484
00485 ThrowingValue& operator%=(const ThrowingValue& other) {
00486 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00487 dummy_ %= other.dummy_;
00488 return *this;
00489 }
00490
00491 ThrowingValue& operator&=(const ThrowingValue& other) {
00492 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00493 dummy_ &= other.dummy_;
00494 return *this;
00495 }
00496
00497 ThrowingValue& operator|=(const ThrowingValue& other) {
00498 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00499 dummy_ |= other.dummy_;
00500 return *this;
00501 }
00502
00503 ThrowingValue& operator^=(const ThrowingValue& other) {
00504 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00505 dummy_ ^= other.dummy_;
00506 return *this;
00507 }
00508
00509 ThrowingValue& operator<<=(int shift) {
00510 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00511 dummy_ <<= shift;
00512 return *this;
00513 }
00514
00515 ThrowingValue& operator>>=(int shift) {
00516 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00517 dummy_ >>= shift;
00518 return *this;
00519 }
00520
00521
00522 void operator&() const = delete;
00523
00524
00525 friend std::ostream& operator<<(std::ostream& os, const ThrowingValue& tv) {
00526 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00527 return os << GetInstanceString(tv.dummy_);
00528 }
00529
00530 friend std::istream& operator>>(std::istream& is, const ThrowingValue&) {
00531 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00532 return is;
00533 }
00534
00535
00536
00537 template <typename... Args>
00538 static void* operator new(size_t s, Args&&... args) noexcept(
00539 IsSpecified(TypeSpec::kNoThrowNew)) {
00540 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
00541 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
00542 }
00543 return ::operator new(s, std::forward<Args>(args)...);
00544 }
00545
00546 template <typename... Args>
00547 static void* operator new[](size_t s, Args&&... args) noexcept(
00548 IsSpecified(TypeSpec::kNoThrowNew)) {
00549 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
00550 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
00551 }
00552 return ::operator new[](s, std::forward<Args>(args)...);
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 void operator delete(void* p) noexcept { ::operator delete(p); }
00564
00565 template <typename... Args>
00566 void operator delete(void* p, Args&&... args) noexcept {
00567 ::operator delete(p, std::forward<Args>(args)...);
00568 }
00569
00570 void operator delete[](void* p) noexcept { return ::operator delete[](p); }
00571
00572 template <typename... Args>
00573 void operator delete[](void* p, Args&&... args) noexcept {
00574 return ::operator delete[](p, std::forward<Args>(args)...);
00575 }
00576
00577
00578
00579 int& Get() noexcept { return dummy_; }
00580 const int& Get() const noexcept { return dummy_; }
00581
00582 private:
00583 static std::string GetInstanceString(int dummy) {
00584 return absl::StrCat("ThrowingValue<",
00585 exceptions_internal::GetSpecString(Spec), ">(", dummy,
00586 ")");
00587 }
00588
00589 int dummy_;
00590 };
00591
00592
00593 template <TypeSpec Spec, typename T>
00594 void operator,(const ThrowingValue<Spec>&, T&&) = delete;
00595 template <TypeSpec Spec, typename T>
00596 void operator,(T&&, const ThrowingValue<Spec>&) = delete;
00597
00598
00599
00600
00601
00602
00603
00604
00605 enum class AllocSpec {
00606 kEverythingThrows = 0,
00607 kNoThrowAllocate = 1,
00608 };
00609
00610
00611
00612
00613
00614
00615
00616
00617 template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
00618 class ThrowingAllocator : private exceptions_internal::TrackedObject {
00619 static constexpr bool IsSpecified(AllocSpec spec) {
00620 return static_cast<bool>(Spec & spec);
00621 }
00622
00623 public:
00624 using pointer = T*;
00625 using const_pointer = const T*;
00626 using reference = T&;
00627 using const_reference = const T&;
00628 using void_pointer = void*;
00629 using const_void_pointer = const void*;
00630 using value_type = T;
00631 using size_type = size_t;
00632 using difference_type = ptrdiff_t;
00633
00634 using is_nothrow =
00635 std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>;
00636 using propagate_on_container_copy_assignment = std::true_type;
00637 using propagate_on_container_move_assignment = std::true_type;
00638 using propagate_on_container_swap = std::true_type;
00639 using is_always_equal = std::false_type;
00640
00641 ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) {
00642 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
00643 dummy_ = std::make_shared<const int>(next_id_++);
00644 }
00645
00646 template <typename U>
00647 ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept
00648 : TrackedObject(GetInstanceString(*other.State())),
00649 dummy_(other.State()) {}
00650
00651
00652
00653 ThrowingAllocator(const ThrowingAllocator& other) noexcept
00654 : TrackedObject(GetInstanceString(*other.State())),
00655 dummy_(other.State()) {}
00656
00657 template <typename U>
00658 ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept
00659 : TrackedObject(GetInstanceString(*other.State())),
00660 dummy_(std::move(other.State())) {}
00661
00662 ThrowingAllocator(ThrowingAllocator&& other) noexcept
00663 : TrackedObject(GetInstanceString(*other.State())),
00664 dummy_(std::move(other.State())) {}
00665
00666 ~ThrowingAllocator() noexcept = default;
00667
00668 ThrowingAllocator& operator=(const ThrowingAllocator& other) noexcept {
00669 dummy_ = other.State();
00670 return *this;
00671 }
00672
00673 template <typename U>
00674 ThrowingAllocator& operator=(
00675 const ThrowingAllocator<U, Spec>& other) noexcept {
00676 dummy_ = other.State();
00677 return *this;
00678 }
00679
00680 template <typename U>
00681 ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept {
00682 dummy_ = std::move(other.State());
00683 return *this;
00684 }
00685
00686 template <typename U>
00687 struct rebind {
00688 using other = ThrowingAllocator<U, Spec>;
00689 };
00690
00691 pointer allocate(size_type n) noexcept(
00692 IsSpecified(AllocSpec::kNoThrowAllocate)) {
00693 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
00694 return static_cast<pointer>(::operator new(n * sizeof(T)));
00695 }
00696
00697 pointer allocate(size_type n, const_void_pointer) noexcept(
00698 IsSpecified(AllocSpec::kNoThrowAllocate)) {
00699 return allocate(n);
00700 }
00701
00702 void deallocate(pointer ptr, size_type) noexcept {
00703 ReadState();
00704 ::operator delete(static_cast<void*>(ptr));
00705 }
00706
00707 template <typename U, typename... Args>
00708 void construct(U* ptr, Args&&... args) noexcept(
00709 IsSpecified(AllocSpec::kNoThrowAllocate)) {
00710 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
00711 ::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
00712 }
00713
00714 template <typename U>
00715 void destroy(U* p) noexcept {
00716 ReadState();
00717 p->~U();
00718 }
00719
00720 size_type max_size() const noexcept {
00721 return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
00722 }
00723
00724 ThrowingAllocator select_on_container_copy_construction() noexcept(
00725 IsSpecified(AllocSpec::kNoThrowAllocate)) {
00726 auto& out = *this;
00727 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
00728 return out;
00729 }
00730
00731 template <typename U>
00732 bool operator==(const ThrowingAllocator<U, Spec>& other) const noexcept {
00733 return dummy_ == other.dummy_;
00734 }
00735
00736 template <typename U>
00737 bool operator!=(const ThrowingAllocator<U, Spec>& other) const noexcept {
00738 return dummy_ != other.dummy_;
00739 }
00740
00741 template <typename, AllocSpec>
00742 friend class ThrowingAllocator;
00743
00744 private:
00745 static std::string GetInstanceString(int dummy) {
00746 return absl::StrCat("ThrowingAllocator<",
00747 exceptions_internal::GetSpecString(Spec), ">(", dummy,
00748 ")");
00749 }
00750
00751 const std::shared_ptr<const int>& State() const { return dummy_; }
00752 std::shared_ptr<const int>& State() { return dummy_; }
00753
00754 void ReadState() {
00755
00756
00757 if (*dummy_ < 0) std::abort();
00758 }
00759
00760 void ReadStateAndMaybeThrow(absl::string_view msg) const {
00761 if (!IsSpecified(AllocSpec::kNoThrowAllocate)) {
00762 exceptions_internal::MaybeThrow(
00763 absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg));
00764 }
00765 }
00766
00767 static int next_id_;
00768 std::shared_ptr<const int> dummy_;
00769 };
00770
00771 template <typename T, AllocSpec Spec>
00772 int ThrowingAllocator<T, Spec>::next_id_ = 0;
00773
00774
00775
00776
00777 template <typename T, typename... Args>
00778 void TestThrowingCtor(Args&&... args) {
00779 struct Cleanup {
00780 ~Cleanup() { exceptions_internal::UnsetCountdown(); }
00781 } c;
00782 for (int count = 0;; ++count) {
00783 exceptions_internal::ConstructorTracker ct(count);
00784 exceptions_internal::SetCountdown(count);
00785 try {
00786 T temp(std::forward<Args>(args)...);
00787 static_cast<void>(temp);
00788 break;
00789 } catch (const exceptions_internal::TestException&) {
00790 }
00791 }
00792 }
00793
00794
00795
00796
00797 template <typename Operation>
00798 testing::AssertionResult TestNothrowOp(const Operation& operation) {
00799 struct Cleanup {
00800 Cleanup() { exceptions_internal::SetCountdown(); }
00801 ~Cleanup() { exceptions_internal::UnsetCountdown(); }
00802 } c;
00803 try {
00804 operation();
00805 return testing::AssertionSuccess();
00806 } catch (const exceptions_internal::TestException&) {
00807 return testing::AssertionFailure()
00808 << "TestException thrown during call to operation() when nothrow "
00809 "guarantee was expected.";
00810 } catch (...) {
00811 return testing::AssertionFailure()
00812 << "Unknown exception thrown during call to operation() when "
00813 "nothrow guarantee was expected.";
00814 }
00815 }
00816
00817 namespace exceptions_internal {
00818
00819
00820 struct UninitializedT {};
00821
00822 template <typename T>
00823 class DefaultFactory {
00824 public:
00825 explicit DefaultFactory(const T& t) : t_(t) {}
00826 std::unique_ptr<T> operator()() const { return absl::make_unique<T>(t_); }
00827
00828 private:
00829 T t_;
00830 };
00831
00832 template <size_t LazyContractsCount, typename LazyFactory,
00833 typename LazyOperation>
00834 using EnableIfTestable = typename absl::enable_if_t<
00835 LazyContractsCount != 0 &&
00836 !std::is_same<LazyFactory, UninitializedT>::value &&
00837 !std::is_same<LazyOperation, UninitializedT>::value>;
00838
00839 template <typename Factory = UninitializedT,
00840 typename Operation = UninitializedT, typename... Contracts>
00841 class ExceptionSafetyTestBuilder;
00842
00843 }
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854 exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester();
00855
00856 namespace exceptions_internal {
00857 template <typename T>
00858 struct IsUniquePtr : std::false_type {};
00859
00860 template <typename T, typename D>
00861 struct IsUniquePtr<std::unique_ptr<T, D>> : std::true_type {};
00862
00863 template <typename Factory>
00864 struct FactoryPtrTypeHelper {
00865 using type = decltype(std::declval<const Factory&>()());
00866
00867 static_assert(IsUniquePtr<type>::value, "Factories must return a unique_ptr");
00868 };
00869
00870 template <typename Factory>
00871 using FactoryPtrType = typename FactoryPtrTypeHelper<Factory>::type;
00872
00873 template <typename Factory>
00874 using FactoryElementType = typename FactoryPtrType<Factory>::element_type;
00875
00876 template <typename T>
00877 class ExceptionSafetyTest {
00878 using Factory = std::function<std::unique_ptr<T>()>;
00879 using Operation = std::function<void(T*)>;
00880 using Contract = std::function<AssertionResult(T*)>;
00881
00882 public:
00883 template <typename... Contracts>
00884 explicit ExceptionSafetyTest(const Factory& f, const Operation& op,
00885 const Contracts&... contracts)
00886 : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {}
00887
00888 AssertionResult Test() const {
00889 for (int count = 0;; ++count) {
00890 exceptions_internal::ConstructorTracker ct(count);
00891
00892 for (const auto& contract : contracts_) {
00893 auto t_ptr = factory_();
00894 try {
00895 SetCountdown(count);
00896 operation_(t_ptr.get());
00897
00898
00899
00900 UnsetCountdown();
00901 return AssertionSuccess();
00902 } catch (const exceptions_internal::TestException& e) {
00903 if (!contract(t_ptr.get())) {
00904 return AssertionFailure() << e.what() << " failed contract check";
00905 }
00906 }
00907 }
00908 }
00909 }
00910
00911 private:
00912 template <typename ContractFn>
00913 Contract WrapContract(const ContractFn& contract) {
00914 return [contract](T* t_ptr) { return AssertionResult(contract(t_ptr)); };
00915 }
00916
00917 Contract WrapContract(StrongGuaranteeTagType) {
00918 return [this](T* t_ptr) { return AssertionResult(*factory_() == *t_ptr); };
00919 }
00920
00921 Factory factory_;
00922 Operation operation_;
00923 std::vector<Contract> contracts_;
00924 };
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957 template <typename Factory, typename Operation, typename... Contracts>
00958 class ExceptionSafetyTestBuilder {
00959 public:
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972 template <typename T>
00973 ExceptionSafetyTestBuilder<DefaultFactory<T>, Operation, Contracts...>
00974 WithInitialValue(const T& t) const {
00975 return WithFactory(DefaultFactory<T>(t));
00976 }
00977
00978
00979
00980
00981
00982
00983
00984
00985 template <typename NewFactory>
00986 ExceptionSafetyTestBuilder<absl::decay_t<NewFactory>, Operation, Contracts...>
00987 WithFactory(const NewFactory& new_factory) const {
00988 return {new_factory, operation_, contracts_};
00989 }
00990
00991
00992
00993
00994
00995
00996 template <typename NewOperation>
00997 ExceptionSafetyTestBuilder<Factory, absl::decay_t<NewOperation>, Contracts...>
00998 WithOperation(const NewOperation& new_operation) const {
00999 return {factory_, new_operation, contracts_};
01000 }
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015 template <typename... MoreContracts>
01016 ExceptionSafetyTestBuilder<Factory, Operation, Contracts...,
01017 absl::decay_t<MoreContracts>...>
01018 WithContracts(const MoreContracts&... more_contracts) const {
01019 return {
01020 factory_, operation_,
01021 std::tuple_cat(contracts_, std::tuple<absl::decay_t<MoreContracts>...>(
01022 more_contracts...))};
01023 }
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041 template <
01042 typename NewOperation,
01043 typename = EnableIfTestable<sizeof...(Contracts), Factory, NewOperation>>
01044 testing::AssertionResult Test(const NewOperation& new_operation) const {
01045 return TestImpl(new_operation, absl::index_sequence_for<Contracts...>());
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060 template <
01061 typename LazyOperation = Operation,
01062 typename = EnableIfTestable<sizeof...(Contracts), Factory, LazyOperation>>
01063 testing::AssertionResult Test() const {
01064 return Test(operation_);
01065 }
01066
01067 private:
01068 template <typename, typename, typename...>
01069 friend class ExceptionSafetyTestBuilder;
01070
01071 friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester();
01072
01073 ExceptionSafetyTestBuilder() {}
01074
01075 ExceptionSafetyTestBuilder(const Factory& f, const Operation& o,
01076 const std::tuple<Contracts...>& i)
01077 : factory_(f), operation_(o), contracts_(i) {}
01078
01079 template <typename SelectedOperation, size_t... Indices>
01080 testing::AssertionResult TestImpl(SelectedOperation selected_operation,
01081 absl::index_sequence<Indices...>) const {
01082 return ExceptionSafetyTest<FactoryElementType<Factory>>(
01083 factory_, selected_operation, std::get<Indices>(contracts_)...)
01084 .Test();
01085 }
01086
01087 Factory factory_;
01088 Operation operation_;
01089 std::tuple<Contracts...> contracts_;
01090 };
01091
01092 }
01093
01094 }
01095
01096 #endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_