• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Utilities for testing exception-safety
16 
17 #ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
18 #define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
19 
20 #include "absl/base/config.h"
21 
22 #ifdef ABSL_HAVE_EXCEPTIONS
23 
24 #include <cstddef>
25 #include <cstdint>
26 #include <functional>
27 #include <initializer_list>
28 #include <iosfwd>
29 #include <string>
30 #include <tuple>
31 #include <unordered_map>
32 
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"
40 
41 namespace testing {
42 
43 enum class TypeSpec;
44 enum class AllocSpec;
45 
46 constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) {
47   using T = absl::underlying_type_t<TypeSpec>;
48   return static_cast<TypeSpec>(static_cast<T>(a) | static_cast<T>(b));
49 }
50 
51 constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) {
52   using T = absl::underlying_type_t<TypeSpec>;
53   return static_cast<TypeSpec>(static_cast<T>(a) & static_cast<T>(b));
54 }
55 
56 constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) {
57   using T = absl::underlying_type_t<AllocSpec>;
58   return static_cast<AllocSpec>(static_cast<T>(a) | static_cast<T>(b));
59 }
60 
61 constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) {
62   using T = absl::underlying_type_t<AllocSpec>;
63   return static_cast<AllocSpec>(static_cast<T>(a) & static_cast<T>(b));
64 }
65 
66 namespace exceptions_internal {
67 
68 std::string GetSpecString(TypeSpec);
69 std::string GetSpecString(AllocSpec);
70 
71 struct NoThrowTag {};
72 struct StrongGuaranteeTagType {};
73 
74 // A simple exception class.  We throw this so that test code can catch
75 // exceptions specifically thrown by ThrowingValue.
76 class TestException {
77  public:
TestException(absl::string_view msg)78   explicit TestException(absl::string_view msg) : msg_(msg) {}
~TestException()79   virtual ~TestException() {}
what()80   virtual const char* what() const noexcept { return msg_.c_str(); }
81 
82  private:
83   std::string msg_;
84 };
85 
86 // TestBadAllocException exists because allocation functions must throw an
87 // exception which can be caught by a handler of std::bad_alloc.  We use a child
88 // class of std::bad_alloc so we can customise the error message, and also
89 // derive from TestException so we don't accidentally end up catching an actual
90 // bad_alloc exception in TestExceptionSafety.
91 class TestBadAllocException : public std::bad_alloc, public TestException {
92  public:
TestBadAllocException(absl::string_view msg)93   explicit TestBadAllocException(absl::string_view msg) : TestException(msg) {}
94   using TestException::what;
95 };
96 
97 extern int countdown;
98 
99 // Allows the countdown variable to be set manually (defaulting to the initial
100 // value of 0)
101 inline void SetCountdown(int i = 0) { countdown = i; }
102 // Sets the countdown to the terminal value -1
UnsetCountdown()103 inline void UnsetCountdown() { SetCountdown(-1); }
104 
105 void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false);
106 
107 testing::AssertionResult FailureMessage(const TestException& e,
108                                         int countdown) noexcept;
109 
110 struct TrackedAddress {
111   bool is_alive;
112   std::string description;
113 };
114 
115 // Inspects the constructions and destructions of anything inheriting from
116 // TrackedObject. This allows us to safely "leak" TrackedObjects, as
117 // ConstructorTracker will destroy everything left over in its destructor.
118 class ConstructorTracker {
119  public:
ConstructorTracker(int count)120   explicit ConstructorTracker(int count) : countdown_(count) {
121     assert(current_tracker_instance_ == nullptr);
122     current_tracker_instance_ = this;
123   }
124 
~ConstructorTracker()125   ~ConstructorTracker() {
126     assert(current_tracker_instance_ == this);
127     current_tracker_instance_ = nullptr;
128 
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.");
135       }
136     }
137   }
138 
ObjectConstructed(void * address,std::string description)139   static void ObjectConstructed(void* address, std::string description) {
140     if (!CurrentlyTracking()) return;
141 
142     TrackedAddress& tracked_address =
143         current_tracker_instance_->address_map_[address];
144     if (tracked_address.is_alive) {
145       ADD_FAILURE() << ErrorMessage(
146           address, tracked_address.description,
147           current_tracker_instance_->countdown_,
148           "Object was re-constructed. Current object was constructed by " +
149               description);
150     }
151     tracked_address = {true, std::move(description)};
152   }
153 
ObjectDestructed(void * address)154   static void ObjectDestructed(void* address) {
155     if (!CurrentlyTracking()) return;
156 
157     auto it = current_tracker_instance_->address_map_.find(address);
158     // Not tracked. Ignore.
159     if (it == current_tracker_instance_->address_map_.end()) return;
160 
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.");
166     }
167     tracked_address.is_alive = false;
168   }
169 
170  private:
CurrentlyTracking()171   static bool CurrentlyTracking() {
172     return current_tracker_instance_ != nullptr;
173   }
174 
ErrorMessage(void * address,const std::string & address_description,int countdown,const std::string & error_description)175   static std::string ErrorMessage(void* address,
176                                   const std::string& address_description,
177                                   int countdown,
178                                   const std::string& error_description) {
179     return absl::Substitute(
180         "With coundtown at $0:\n"
181         "  $1\n"
182         "  Object originally constructed by $2\n"
183         "  Object address: $3\n",
184         countdown, error_description, address_description, address);
185   }
186 
187   std::unordered_map<void*, TrackedAddress> address_map_;
188   int countdown_;
189 
190   static ConstructorTracker* current_tracker_instance_;
191 };
192 
193 class TrackedObject {
194  public:
195   TrackedObject(const TrackedObject&) = delete;
196   TrackedObject(TrackedObject&&) = delete;
197 
198  protected:
TrackedObject(std::string description)199   explicit TrackedObject(std::string description) {
200     ConstructorTracker::ObjectConstructed(this, std::move(description));
201   }
202 
~TrackedObject()203   ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); }
204 };
205 }  // namespace exceptions_internal
206 
207 extern exceptions_internal::NoThrowTag nothrow_ctor;
208 
209 extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
210 
211 // A test class which is convertible to bool.  The conversion can be
212 // instrumented to throw at a controlled time.
213 class ThrowingBool {
214  public:
ThrowingBool(bool b)215   ThrowingBool(bool b) noexcept : b_(b) {}  // NOLINT(runtime/explicit)
216   operator bool() const {                   // NOLINT
217     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
218     return b_;
219   }
220 
221  private:
222   bool b_;
223 };
224 
225 /*
226  * Configuration enum for the ThrowingValue type that defines behavior for the
227  * lifetime of the instance. Use testing::nothrow_ctor to prevent the integer
228  * constructor from throwing.
229  *
230  * kEverythingThrows: Every operation can throw an exception
231  * kNoThrowCopy: Copy construction and copy assignment will not throw
232  * kNoThrowMove: Move construction and move assignment will not throw
233  * kNoThrowNew: Overloaded operators new and new[] will not throw
234  */
235 enum class TypeSpec {
236   kEverythingThrows = 0,
237   kNoThrowCopy = 1,
238   kNoThrowMove = 1 << 1,
239   kNoThrowNew = 1 << 2,
240 };
241 
242 /*
243  * A testing class instrumented to throw an exception at a controlled time.
244  *
245  * ThrowingValue implements a slightly relaxed version of the Regular concept --
246  * that is it's a value type with the expected semantics.  It also implements
247  * arithmetic operations.  It doesn't implement member and pointer operators
248  * like operator-> or operator[].
249  *
250  * ThrowingValue can be instrumented to have certain operations be noexcept by
251  * using compile-time bitfield template arguments.  That is, to make an
252  * ThrowingValue which has noexcept move construction/assignment and noexcept
253  * copy construction/assignment, use the following:
254  *   ThrowingValue<testing::kNoThrowMove | testing::kNoThrowCopy> my_thrwr{val};
255  */
256 template <TypeSpec Spec = TypeSpec::kEverythingThrows>
257 class ThrowingValue : private exceptions_internal::TrackedObject {
IsSpecified(TypeSpec spec)258   static constexpr bool IsSpecified(TypeSpec spec) {
259     return static_cast<bool>(Spec & spec);
260   }
261 
262   static constexpr int kDefaultValue = 0;
263   static constexpr int kBadValue = 938550620;
264 
265  public:
ThrowingValue()266   ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) {
267     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
268     dummy_ = kDefaultValue;
269   }
270 
noexcept(IsSpecified (TypeSpec::kNoThrowCopy))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);
276     }
277     dummy_ = other.dummy_;
278   }
279 
noexcept(IsSpecified (TypeSpec::kNoThrowMove))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);
285     }
286     dummy_ = other.dummy_;
287   }
288 
ThrowingValue(int i)289   explicit ThrowingValue(int i) : TrackedObject(GetInstanceString(i)) {
290     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
291     dummy_ = i;
292   }
293 
ThrowingValue(int i,exceptions_internal::NoThrowTag)294   ThrowingValue(int i, exceptions_internal::NoThrowTag) noexcept
295       : TrackedObject(GetInstanceString(i)), dummy_(i) {}
296 
297   // absl expects nothrow destructors
298   ~ThrowingValue() noexcept = default;
299 
noexcept(IsSpecified (TypeSpec::kNoThrowCopy))300   ThrowingValue& operator=(const ThrowingValue& other) noexcept(
301       IsSpecified(TypeSpec::kNoThrowCopy)) {
302     dummy_ = kBadValue;
303     if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
304       exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
305     }
306     dummy_ = other.dummy_;
307     return *this;
308   }
309 
noexcept(IsSpecified (TypeSpec::kNoThrowMove))310   ThrowingValue& operator=(ThrowingValue&& other) noexcept(
311       IsSpecified(TypeSpec::kNoThrowMove)) {
312     dummy_ = kBadValue;
313     if (!IsSpecified(TypeSpec::kNoThrowMove)) {
314       exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
315     }
316     dummy_ = other.dummy_;
317     return *this;
318   }
319 
320   // Arithmetic Operators
321   ThrowingValue operator+(const ThrowingValue& other) const {
322     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
323     return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor);
324   }
325 
326   ThrowingValue operator+() const {
327     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
328     return ThrowingValue(dummy_, nothrow_ctor);
329   }
330 
331   ThrowingValue operator-(const ThrowingValue& other) const {
332     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
333     return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor);
334   }
335 
336   ThrowingValue operator-() const {
337     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
338     return ThrowingValue(-dummy_, nothrow_ctor);
339   }
340 
341   ThrowingValue& operator++() {
342     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
343     ++dummy_;
344     return *this;
345   }
346 
347   ThrowingValue operator++(int) {
348     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
349     auto out = ThrowingValue(dummy_, nothrow_ctor);
350     ++dummy_;
351     return out;
352   }
353 
354   ThrowingValue& operator--() {
355     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
356     --dummy_;
357     return *this;
358   }
359 
360   ThrowingValue operator--(int) {
361     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
362     auto out = ThrowingValue(dummy_, nothrow_ctor);
363     --dummy_;
364     return out;
365   }
366 
367   ThrowingValue operator*(const ThrowingValue& other) const {
368     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
369     return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor);
370   }
371 
372   ThrowingValue operator/(const ThrowingValue& other) const {
373     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
374     return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor);
375   }
376 
377   ThrowingValue operator%(const ThrowingValue& other) const {
378     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
379     return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor);
380   }
381 
382   ThrowingValue operator<<(int shift) const {
383     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
384     return ThrowingValue(dummy_ << shift, nothrow_ctor);
385   }
386 
387   ThrowingValue operator>>(int shift) const {
388     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
389     return ThrowingValue(dummy_ >> shift, nothrow_ctor);
390   }
391 
392   // Comparison Operators
393   // NOTE: We use `ThrowingBool` instead of `bool` because most STL
394   // types/containers requires T to be convertible to bool.
395   friend ThrowingBool operator==(const ThrowingValue& a,
396                                  const ThrowingValue& b) {
397     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
398     return a.dummy_ == b.dummy_;
399   }
400   friend ThrowingBool operator!=(const ThrowingValue& a,
401                                  const ThrowingValue& b) {
402     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
403     return a.dummy_ != b.dummy_;
404   }
405   friend ThrowingBool operator<(const ThrowingValue& a,
406                                 const ThrowingValue& b) {
407     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
408     return a.dummy_ < b.dummy_;
409   }
410   friend ThrowingBool operator<=(const ThrowingValue& a,
411                                  const ThrowingValue& b) {
412     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
413     return a.dummy_ <= b.dummy_;
414   }
415   friend ThrowingBool operator>(const ThrowingValue& a,
416                                 const ThrowingValue& b) {
417     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
418     return a.dummy_ > b.dummy_;
419   }
420   friend ThrowingBool operator>=(const ThrowingValue& a,
421                                  const ThrowingValue& b) {
422     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
423     return a.dummy_ >= b.dummy_;
424   }
425 
426   // Logical Operators
427   ThrowingBool operator!() const {
428     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
429     return !dummy_;
430   }
431 
432   ThrowingBool operator&&(const ThrowingValue& other) const {
433     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
434     return dummy_ && other.dummy_;
435   }
436 
437   ThrowingBool operator||(const ThrowingValue& other) const {
438     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
439     return dummy_ || other.dummy_;
440   }
441 
442   // Bitwise Logical Operators
443   ThrowingValue operator~() const {
444     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
445     return ThrowingValue(~dummy_, nothrow_ctor);
446   }
447 
448   ThrowingValue operator&(const ThrowingValue& other) const {
449     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
450     return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor);
451   }
452 
453   ThrowingValue operator|(const ThrowingValue& other) const {
454     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
455     return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor);
456   }
457 
458   ThrowingValue operator^(const ThrowingValue& other) const {
459     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
460     return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor);
461   }
462 
463   // Compound Assignment operators
464   ThrowingValue& operator+=(const ThrowingValue& other) {
465     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
466     dummy_ += other.dummy_;
467     return *this;
468   }
469 
470   ThrowingValue& operator-=(const ThrowingValue& other) {
471     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
472     dummy_ -= other.dummy_;
473     return *this;
474   }
475 
476   ThrowingValue& operator*=(const ThrowingValue& other) {
477     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
478     dummy_ *= other.dummy_;
479     return *this;
480   }
481 
482   ThrowingValue& operator/=(const ThrowingValue& other) {
483     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
484     dummy_ /= other.dummy_;
485     return *this;
486   }
487 
488   ThrowingValue& operator%=(const ThrowingValue& other) {
489     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
490     dummy_ %= other.dummy_;
491     return *this;
492   }
493 
494   ThrowingValue& operator&=(const ThrowingValue& other) {
495     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
496     dummy_ &= other.dummy_;
497     return *this;
498   }
499 
500   ThrowingValue& operator|=(const ThrowingValue& other) {
501     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
502     dummy_ |= other.dummy_;
503     return *this;
504   }
505 
506   ThrowingValue& operator^=(const ThrowingValue& other) {
507     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
508     dummy_ ^= other.dummy_;
509     return *this;
510   }
511 
512   ThrowingValue& operator<<=(int shift) {
513     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
514     dummy_ <<= shift;
515     return *this;
516   }
517 
518   ThrowingValue& operator>>=(int shift) {
519     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
520     dummy_ >>= shift;
521     return *this;
522   }
523 
524   // Pointer operators
525   void operator&() const = delete;  // NOLINT(runtime/operator)
526 
527   // Stream operators
528   friend std::ostream& operator<<(std::ostream& os, const ThrowingValue& tv) {
529     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
530     return os << GetInstanceString(tv.dummy_);
531   }
532 
533   friend std::istream& operator>>(std::istream& is, const ThrowingValue&) {
534     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
535     return is;
536   }
537 
538   // Memory management operators
539   // Args.. allows us to overload regular and placement new in one shot
540   template <typename... Args>
new(size_t s,Args &&...args)541   static void* operator new(size_t s, Args&&... args) noexcept(
542       IsSpecified(TypeSpec::kNoThrowNew)) {
543     if (!IsSpecified(TypeSpec::kNoThrowNew)) {
544       exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
545     }
546     return ::operator new(s, std::forward<Args>(args)...);
547   }
548 
549   template <typename... Args>
noexcept(IsSpecified (TypeSpec::kNoThrowNew))550   static void* operator new[](size_t s, Args&&... args) noexcept(
551       IsSpecified(TypeSpec::kNoThrowNew)) {
552     if (!IsSpecified(TypeSpec::kNoThrowNew)) {
553       exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
554     }
555     return ::operator new[](s, std::forward<Args>(args)...);
556   }
557 
558   // Abseil doesn't support throwing overloaded operator delete.  These are
559   // provided so a throwing operator-new can clean up after itself.
560   //
561   // We provide both regular and templated operator delete because if only the
562   // templated version is provided as we did with operator new, the compiler has
563   // no way of knowing which overload of operator delete to call. See
564   // https://en.cppreference.com/w/cpp/memory/new/operator_delete and
565   // https://en.cppreference.com/w/cpp/language/delete for the gory details.
delete(void * p)566   void operator delete(void* p) noexcept { ::operator delete(p); }
567 
568   template <typename... Args>
delete(void * p,Args &&...args)569   void operator delete(void* p, Args&&... args) noexcept {
570     ::operator delete(p, std::forward<Args>(args)...);
571   }
572 
573   void operator delete[](void* p) noexcept { return ::operator delete[](p); }
574 
575   template <typename... Args>
576   void operator delete[](void* p, Args&&... args) noexcept {
577     return ::operator delete[](p, std::forward<Args>(args)...);
578   }
579 
580   // Non-standard access to the actual contained value.  No need for this to
581   // throw.
Get()582   int& Get() noexcept { return dummy_; }
Get()583   const int& Get() const noexcept { return dummy_; }
584 
585  private:
GetInstanceString(int dummy)586   static std::string GetInstanceString(int dummy) {
587     return absl::StrCat("ThrowingValue<",
588                         exceptions_internal::GetSpecString(Spec), ">(", dummy,
589                         ")");
590   }
591 
592   int dummy_;
593 };
594 // While not having to do with exceptions, explicitly delete comma operator, to
595 // make sure we don't use it on user-supplied types.
596 template <TypeSpec Spec, typename T>
597 void operator,(const ThrowingValue<Spec>&, T&&) = delete;
598 template <TypeSpec Spec, typename T>
599 void operator,(T&&, const ThrowingValue<Spec>&) = delete;
600 
601 /*
602  * Configuration enum for the ThrowingAllocator type that defines behavior for
603  * the lifetime of the instance.
604  *
605  * kEverythingThrows: Calls to the member functions may throw
606  * kNoThrowAllocate: Calls to the member functions will not throw
607  */
608 enum class AllocSpec {
609   kEverythingThrows = 0,
610   kNoThrowAllocate = 1,
611 };
612 
613 /*
614  * An allocator type which is instrumented to throw at a controlled time, or not
615  * to throw, using AllocSpec. The supported settings are the default of every
616  * function which is allowed to throw in a conforming allocator possibly
617  * throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS
618  * configuration macro.
619  */
620 template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
621 class ThrowingAllocator : private exceptions_internal::TrackedObject {
IsSpecified(AllocSpec spec)622   static constexpr bool IsSpecified(AllocSpec spec) {
623     return static_cast<bool>(Spec & spec);
624   }
625 
626  public:
627   using pointer = T*;
628   using const_pointer = const T*;
629   using reference = T&;
630   using const_reference = const T&;
631   using void_pointer = void*;
632   using const_void_pointer = const void*;
633   using value_type = T;
634   using size_type = size_t;
635   using difference_type = ptrdiff_t;
636 
637   using is_nothrow =
638       std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>;
639   using propagate_on_container_copy_assignment = std::true_type;
640   using propagate_on_container_move_assignment = std::true_type;
641   using propagate_on_container_swap = std::true_type;
642   using is_always_equal = std::false_type;
643 
ThrowingAllocator()644   ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) {
645     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
646     dummy_ = std::make_shared<const int>(next_id_++);
647   }
648 
649   template <typename U>
ThrowingAllocator(const ThrowingAllocator<U,Spec> & other)650   ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept  // NOLINT
651       : TrackedObject(GetInstanceString(*other.State())),
652         dummy_(other.State()) {}
653 
654   // According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of
655   // allocator shall not exit via an exception, thus they are marked noexcept.
ThrowingAllocator(const ThrowingAllocator & other)656   ThrowingAllocator(const ThrowingAllocator& other) noexcept
657       : TrackedObject(GetInstanceString(*other.State())),
658         dummy_(other.State()) {}
659 
660   template <typename U>
ThrowingAllocator(ThrowingAllocator<U,Spec> && other)661   ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept  // NOLINT
662       : TrackedObject(GetInstanceString(*other.State())),
663         dummy_(std::move(other.State())) {}
664 
ThrowingAllocator(ThrowingAllocator && other)665   ThrowingAllocator(ThrowingAllocator&& other) noexcept
666       : TrackedObject(GetInstanceString(*other.State())),
667         dummy_(std::move(other.State())) {}
668 
669   ~ThrowingAllocator() noexcept = default;
670 
671   ThrowingAllocator& operator=(const ThrowingAllocator& other) noexcept {
672     dummy_ = other.State();
673     return *this;
674   }
675 
676   template <typename U>
677   ThrowingAllocator& operator=(
678       const ThrowingAllocator<U, Spec>& other) noexcept {
679     dummy_ = other.State();
680     return *this;
681   }
682 
683   template <typename U>
684   ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept {
685     dummy_ = std::move(other.State());
686     return *this;
687   }
688 
689   template <typename U>
690   struct rebind {
691     using other = ThrowingAllocator<U, Spec>;
692   };
693 
allocate(size_type n)694   pointer allocate(size_type n) noexcept(
695       IsSpecified(AllocSpec::kNoThrowAllocate)) {
696     ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
697     return static_cast<pointer>(::operator new(n * sizeof(T)));
698   }
699 
allocate(size_type n,const_void_pointer)700   pointer allocate(size_type n, const_void_pointer) noexcept(
701       IsSpecified(AllocSpec::kNoThrowAllocate)) {
702     return allocate(n);
703   }
704 
deallocate(pointer ptr,size_type)705   void deallocate(pointer ptr, size_type) noexcept {
706     ReadState();
707     ::operator delete(static_cast<void*>(ptr));
708   }
709 
710   template <typename U, typename... Args>
construct(U * ptr,Args &&...args)711   void construct(U* ptr, Args&&... args) noexcept(
712       IsSpecified(AllocSpec::kNoThrowAllocate)) {
713     ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
714     ::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
715   }
716 
717   template <typename U>
destroy(U * p)718   void destroy(U* p) noexcept {
719     ReadState();
720     p->~U();
721   }
722 
max_size()723   size_type max_size() const noexcept {
724     return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
725   }
726 
select_on_container_copy_construction()727   ThrowingAllocator select_on_container_copy_construction() noexcept(
728       IsSpecified(AllocSpec::kNoThrowAllocate)) {
729     auto& out = *this;
730     ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
731     return out;
732   }
733 
734   template <typename U>
735   bool operator==(const ThrowingAllocator<U, Spec>& other) const noexcept {
736     return dummy_ == other.dummy_;
737   }
738 
739   template <typename U>
740   bool operator!=(const ThrowingAllocator<U, Spec>& other) const noexcept {
741     return dummy_ != other.dummy_;
742   }
743 
744   template <typename, AllocSpec>
745   friend class ThrowingAllocator;
746 
747  private:
GetInstanceString(int dummy)748   static std::string GetInstanceString(int dummy) {
749     return absl::StrCat("ThrowingAllocator<",
750                         exceptions_internal::GetSpecString(Spec), ">(", dummy,
751                         ")");
752   }
753 
State()754   const std::shared_ptr<const int>& State() const { return dummy_; }
State()755   std::shared_ptr<const int>& State() { return dummy_; }
756 
ReadState()757   void ReadState() {
758     // we know that this will never be true, but the compiler doesn't, so this
759     // should safely force a read of the value.
760     if (*dummy_ < 0) std::abort();
761   }
762 
ReadStateAndMaybeThrow(absl::string_view msg)763   void ReadStateAndMaybeThrow(absl::string_view msg) const {
764     if (!IsSpecified(AllocSpec::kNoThrowAllocate)) {
765       exceptions_internal::MaybeThrow(
766           absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg));
767     }
768   }
769 
770   static int next_id_;
771   std::shared_ptr<const int> dummy_;
772 };
773 
774 template <typename T, AllocSpec Spec>
775 int ThrowingAllocator<T, Spec>::next_id_ = 0;
776 
777 // Tests for resource leaks by attempting to construct a T using args repeatedly
778 // until successful, using the countdown method.  Side effects can then be
779 // tested for resource leaks.
780 template <typename T, typename... Args>
TestThrowingCtor(Args &&...args)781 void TestThrowingCtor(Args&&... args) {
782   struct Cleanup {
783     ~Cleanup() { exceptions_internal::UnsetCountdown(); }
784   } c;
785   for (int count = 0;; ++count) {
786     exceptions_internal::ConstructorTracker ct(count);
787     exceptions_internal::SetCountdown(count);
788     try {
789       T temp(std::forward<Args>(args)...);
790       static_cast<void>(temp);
791       break;
792     } catch (const exceptions_internal::TestException&) {
793     }
794   }
795 }
796 
797 // Tests the nothrow guarantee of the provided nullary operation. If the an
798 // exception is thrown, the result will be AssertionFailure(). Otherwise, it
799 // will be AssertionSuccess().
800 template <typename Operation>
TestNothrowOp(const Operation & operation)801 testing::AssertionResult TestNothrowOp(const Operation& operation) {
802   struct Cleanup {
803     Cleanup() { exceptions_internal::SetCountdown(); }
804     ~Cleanup() { exceptions_internal::UnsetCountdown(); }
805   } c;
806   try {
807     operation();
808     return testing::AssertionSuccess();
809   } catch (const exceptions_internal::TestException&) {
810     return testing::AssertionFailure()
811            << "TestException thrown during call to operation() when nothrow "
812               "guarantee was expected.";
813   } catch (...) {
814     return testing::AssertionFailure()
815            << "Unknown exception thrown during call to operation() when "
816               "nothrow guarantee was expected.";
817   }
818 }
819 
820 namespace exceptions_internal {
821 
822 // Dummy struct for ExceptionSafetyTestBuilder<> partial state.
823 struct UninitializedT {};
824 
825 template <typename T>
826 class DefaultFactory {
827  public:
DefaultFactory(const T & t)828   explicit DefaultFactory(const T& t) : t_(t) {}
operator()829   std::unique_ptr<T> operator()() const { return absl::make_unique<T>(t_); }
830 
831  private:
832   T t_;
833 };
834 
835 template <size_t LazyContractsCount, typename LazyFactory,
836           typename LazyOperation>
837 using EnableIfTestable = typename absl::enable_if_t<
838     LazyContractsCount != 0 &&
839     !std::is_same<LazyFactory, UninitializedT>::value &&
840     !std::is_same<LazyOperation, UninitializedT>::value>;
841 
842 template <typename Factory = UninitializedT,
843           typename Operation = UninitializedT, typename... Contracts>
844 class ExceptionSafetyTestBuilder;
845 
846 }  // namespace exceptions_internal
847 
848 /*
849  * Constructs an empty ExceptionSafetyTestBuilder. All
850  * ExceptionSafetyTestBuilder objects are immutable and all With[thing] mutation
851  * methods return new instances of ExceptionSafetyTestBuilder.
852  *
853  * In order to test a T for exception safety, a factory for that T, a testable
854  * operation, and at least one contract callback returning an assertion
855  * result must be applied using the respective methods.
856  */
857 exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester();
858 
859 namespace exceptions_internal {
860 template <typename T>
861 struct IsUniquePtr : std::false_type {};
862 
863 template <typename T, typename D>
864 struct IsUniquePtr<std::unique_ptr<T, D>> : std::true_type {};
865 
866 template <typename Factory>
867 struct FactoryPtrTypeHelper {
868   using type = decltype(std::declval<const Factory&>()());
869 
870   static_assert(IsUniquePtr<type>::value, "Factories must return a unique_ptr");
871 };
872 
873 template <typename Factory>
874 using FactoryPtrType = typename FactoryPtrTypeHelper<Factory>::type;
875 
876 template <typename Factory>
877 using FactoryElementType = typename FactoryPtrType<Factory>::element_type;
878 
879 template <typename T>
880 class ExceptionSafetyTest {
881   using Factory = std::function<std::unique_ptr<T>()>;
882   using Operation = std::function<void(T*)>;
883   using Contract = std::function<AssertionResult(T*)>;
884 
885  public:
886   template <typename... Contracts>
887   explicit ExceptionSafetyTest(const Factory& f, const Operation& op,
888                                const Contracts&... contracts)
889       : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {}
890 
891   AssertionResult Test() const {
892     for (int count = 0;; ++count) {
893       exceptions_internal::ConstructorTracker ct(count);
894 
895       for (const auto& contract : contracts_) {
896         auto t_ptr = factory_();
897         try {
898           SetCountdown(count);
899           operation_(t_ptr.get());
900           // Unset for the case that the operation throws no exceptions, which
901           // would leave the countdown set and break the *next* exception safety
902           // test after this one.
903           UnsetCountdown();
904           return AssertionSuccess();
905         } catch (const exceptions_internal::TestException& e) {
906           if (!contract(t_ptr.get())) {
907             return AssertionFailure() << e.what() << " failed contract check";
908           }
909         }
910       }
911     }
912   }
913 
914  private:
915   template <typename ContractFn>
916   Contract WrapContract(const ContractFn& contract) {
917     return [contract](T* t_ptr) { return AssertionResult(contract(t_ptr)); };
918   }
919 
920   Contract WrapContract(StrongGuaranteeTagType) {
921     return [this](T* t_ptr) { return AssertionResult(*factory_() == *t_ptr); };
922   }
923 
924   Factory factory_;
925   Operation operation_;
926   std::vector<Contract> contracts_;
927 };
928 
929 /*
930  * Builds a tester object that tests if performing a operation on a T follows
931  * exception safety guarantees. Verification is done via contract assertion
932  * callbacks applied to T instances post-throw.
933  *
934  * Template parameters for ExceptionSafetyTestBuilder:
935  *
936  * - Factory: The factory object (passed in via tester.WithFactory(...) or
937  *   tester.WithInitialValue(...)) must be invocable with the signature
938  *   `std::unique_ptr<T> operator()() const` where T is the type being tested.
939  *   It is used for reliably creating identical T instances to test on.
940  *
941  * - Operation: The operation object (passsed in via tester.WithOperation(...)
942  *   or tester.Test(...)) must be invocable with the signature
943  *   `void operator()(T*) const` where T is the type being tested. It is used
944  *   for performing steps on a T instance that may throw and that need to be
945  *   checked for exception safety. Each call to the operation will receive a
946  *   fresh T instance so it's free to modify and destroy the T instances as it
947  *   pleases.
948  *
949  * - Contracts...: The contract assertion callback objects (passed in via
950  *   tester.WithContracts(...)) must be invocable with the signature
951  *   `testing::AssertionResult operator()(T*) const` where T is the type being
952  *   tested. Contract assertion callbacks are provided T instances post-throw.
953  *   They must return testing::AssertionSuccess when the type contracts of the
954  *   provided T instance hold. If the type contracts of the T instance do not
955  *   hold, they must return testing::AssertionFailure. Execution order of
956  *   Contracts... is unspecified. They will each individually get a fresh T
957  *   instance so they are free to modify and destroy the T instances as they
958  *   please.
959  */
960 template <typename Factory, typename Operation, typename... Contracts>
961 class ExceptionSafetyTestBuilder {
962  public:
963   /*
964    * Returns a new ExceptionSafetyTestBuilder with an included T factory based
965    * on the provided T instance. The existing factory will not be included in
966    * the newly created tester instance. The created factory returns a new T
967    * instance by copy-constructing the provided const T& t.
968    *
969    * Preconditions for tester.WithInitialValue(const T& t):
970    *
971    * - The const T& t object must be copy-constructible where T is the type
972    *   being tested. For non-copy-constructible objects, use the method
973    *   tester.WithFactory(...).
974    */
975   template <typename T>
976   ExceptionSafetyTestBuilder<DefaultFactory<T>, Operation, Contracts...>
977   WithInitialValue(const T& t) const {
978     return WithFactory(DefaultFactory<T>(t));
979   }
980 
981   /*
982    * Returns a new ExceptionSafetyTestBuilder with the provided T factory
983    * included. The existing factory will not be included in the newly-created
984    * tester instance. This method is intended for use with types lacking a copy
985    * constructor. Types that can be copy-constructed should instead use the
986    * method tester.WithInitialValue(...).
987    */
988   template <typename NewFactory>
989   ExceptionSafetyTestBuilder<absl::decay_t<NewFactory>, Operation, Contracts...>
990   WithFactory(const NewFactory& new_factory) const {
991     return {new_factory, operation_, contracts_};
992   }
993 
994   /*
995    * Returns a new ExceptionSafetyTestBuilder with the provided testable
996    * operation included. The existing operation will not be included in the
997    * newly created tester.
998    */
999   template <typename NewOperation>
1000   ExceptionSafetyTestBuilder<Factory, absl::decay_t<NewOperation>, Contracts...>
1001   WithOperation(const NewOperation& new_operation) const {
1002     return {factory_, new_operation, contracts_};
1003   }
1004 
1005   /*
1006    * Returns a new ExceptionSafetyTestBuilder with the provided MoreContracts...
1007    * combined with the Contracts... that were already included in the instance
1008    * on which the method was called. Contracts... cannot be removed or replaced
1009    * once added to an ExceptionSafetyTestBuilder instance. A fresh object must
1010    * be created in order to get an empty Contracts... list.
1011    *
1012    * In addition to passing in custom contract assertion callbacks, this method
1013    * accepts `testing::strong_guarantee` as an argument which checks T instances
1014    * post-throw against freshly created T instances via operator== to verify
1015    * that any state changes made during the execution of the operation were
1016    * properly rolled back.
1017    */
1018   template <typename... MoreContracts>
1019   ExceptionSafetyTestBuilder<Factory, Operation, Contracts...,
1020                              absl::decay_t<MoreContracts>...>
1021   WithContracts(const MoreContracts&... more_contracts) const {
1022     return {
1023         factory_, operation_,
1024         std::tuple_cat(contracts_, std::tuple<absl::decay_t<MoreContracts>...>(
1025                                        more_contracts...))};
1026   }
1027 
1028   /*
1029    * Returns a testing::AssertionResult that is the reduced result of the
1030    * exception safety algorithm. The algorithm short circuits and returns
1031    * AssertionFailure after the first contract callback returns an
1032    * AssertionFailure. Otherwise, if all contract callbacks return an
1033    * AssertionSuccess, the reduced result is AssertionSuccess.
1034    *
1035    * The passed-in testable operation will not be saved in a new tester instance
1036    * nor will it modify/replace the existing tester instance. This is useful
1037    * when each operation being tested is unique and does not need to be reused.
1038    *
1039    * Preconditions for tester.Test(const NewOperation& new_operation):
1040    *
1041    * - May only be called after at least one contract assertion callback and a
1042    *   factory or initial value have been provided.
1043    */
1044   template <
1045       typename NewOperation,
1046       typename = EnableIfTestable<sizeof...(Contracts), Factory, NewOperation>>
1047   testing::AssertionResult Test(const NewOperation& new_operation) const {
1048     return TestImpl(new_operation, absl::index_sequence_for<Contracts...>());
1049   }
1050 
1051   /*
1052    * Returns a testing::AssertionResult that is the reduced result of the
1053    * exception safety algorithm. The algorithm short circuits and returns
1054    * AssertionFailure after the first contract callback returns an
1055    * AssertionFailure. Otherwise, if all contract callbacks return an
1056    * AssertionSuccess, the reduced result is AssertionSuccess.
1057    *
1058    * Preconditions for tester.Test():
1059    *
1060    * - May only be called after at least one contract assertion callback, a
1061    *   factory or initial value and a testable operation have been provided.
1062    */
1063   template <
1064       typename LazyOperation = Operation,
1065       typename = EnableIfTestable<sizeof...(Contracts), Factory, LazyOperation>>
1066   testing::AssertionResult Test() const {
1067     return Test(operation_);
1068   }
1069 
1070  private:
1071   template <typename, typename, typename...>
1072   friend class ExceptionSafetyTestBuilder;
1073 
1074   friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester();
1075 
1076   ExceptionSafetyTestBuilder() {}
1077 
1078   ExceptionSafetyTestBuilder(const Factory& f, const Operation& o,
1079                              const std::tuple<Contracts...>& i)
1080       : factory_(f), operation_(o), contracts_(i) {}
1081 
1082   template <typename SelectedOperation, size_t... Indices>
1083   testing::AssertionResult TestImpl(SelectedOperation selected_operation,
1084                                     absl::index_sequence<Indices...>) const {
1085     return ExceptionSafetyTest<FactoryElementType<Factory>>(
1086                factory_, selected_operation, std::get<Indices>(contracts_)...)
1087         .Test();
1088   }
1089 
1090   Factory factory_;
1091   Operation operation_;
1092   std::tuple<Contracts...> contracts_;
1093 };
1094 
1095 }  // namespace exceptions_internal
1096 
1097 }  // namespace testing
1098 
1099 #endif  // ABSL_HAVE_EXCEPTIONS
1100 
1101 #endif  // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
1102