xref: /aosp_15_r20/external/abseil-cpp/absl/base/exception_safety_testing_test.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
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 #include "absl/base/internal/exception_safety_testing.h"
16 
17 #ifdef ABSL_HAVE_EXCEPTIONS
18 
19 #include <cstddef>
20 #include <exception>
21 #include <iostream>
22 #include <list>
23 #include <type_traits>
24 #include <vector>
25 
26 #include "gtest/gtest-spi.h"
27 #include "gtest/gtest.h"
28 #include "absl/memory/memory.h"
29 
30 namespace testing {
31 
32 namespace {
33 
34 using ::testing::exceptions_internal::SetCountdown;
35 using ::testing::exceptions_internal::TestException;
36 using ::testing::exceptions_internal::UnsetCountdown;
37 
38 // EXPECT_NO_THROW can't inspect the thrown inspection in general.
39 template <typename F>
ExpectNoThrow(const F & f)40 void ExpectNoThrow(const F& f) {
41   try {
42     f();
43   } catch (const TestException& e) {
44     ADD_FAILURE() << "Unexpected exception thrown from " << e.what();
45   }
46 }
47 
TEST(ThrowingValueTest,Throws)48 TEST(ThrowingValueTest, Throws) {
49   SetCountdown();
50   EXPECT_THROW(ThrowingValue<> bomb, TestException);
51 
52   // It's not guaranteed that every operator only throws *once*.  The default
53   // ctor only throws once, though, so use it to make sure we only throw when
54   // the countdown hits 0
55   SetCountdown(2);
56   ExpectNoThrow([]() { ThrowingValue<> bomb; });
57   ExpectNoThrow([]() { ThrowingValue<> bomb; });
58   EXPECT_THROW(ThrowingValue<> bomb, TestException);
59 
60   UnsetCountdown();
61 }
62 
63 // Tests that an operation throws when the countdown is at 0, doesn't throw when
64 // the countdown doesn't hit 0, and doesn't modify the state of the
65 // ThrowingValue if it throws
66 template <typename F>
TestOp(const F & f)67 void TestOp(const F& f) {
68   ExpectNoThrow(f);
69 
70   SetCountdown();
71   EXPECT_THROW(f(), TestException);
72   UnsetCountdown();
73 }
74 
TEST(ThrowingValueTest,ThrowingCtors)75 TEST(ThrowingValueTest, ThrowingCtors) {
76   ThrowingValue<> bomb;
77 
78   TestOp([]() { ThrowingValue<> bomb(1); });
79   TestOp([&]() { ThrowingValue<> bomb1 = bomb; });
80   TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); });
81 }
82 
TEST(ThrowingValueTest,ThrowingAssignment)83 TEST(ThrowingValueTest, ThrowingAssignment) {
84   ThrowingValue<> bomb, bomb1;
85 
86   TestOp([&]() { bomb = bomb1; });
87   TestOp([&]() { bomb = std::move(bomb1); });
88 
89   // Test that when assignment throws, the assignment should fail (lhs != rhs)
90   // and strong guarantee fails (lhs != lhs_copy).
91   {
92     ThrowingValue<> lhs(39), rhs(42);
93     ThrowingValue<> lhs_copy(lhs);
94     SetCountdown();
95     EXPECT_THROW(lhs = rhs, TestException);
96     UnsetCountdown();
97     EXPECT_NE(lhs, rhs);
98     EXPECT_NE(lhs_copy, lhs);
99   }
100   {
101     ThrowingValue<> lhs(39), rhs(42);
102     ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs);
103     SetCountdown();
104     EXPECT_THROW(lhs = std::move(rhs), TestException);
105     UnsetCountdown();
106     EXPECT_NE(lhs, rhs_copy);
107     EXPECT_NE(lhs_copy, lhs);
108   }
109 }
110 
TEST(ThrowingValueTest,ThrowingComparisons)111 TEST(ThrowingValueTest, ThrowingComparisons) {
112   ThrowingValue<> bomb1, bomb2;
113   TestOp([&]() { return bomb1 == bomb2; });
114   TestOp([&]() { return bomb1 != bomb2; });
115   TestOp([&]() { return bomb1 < bomb2; });
116   TestOp([&]() { return bomb1 <= bomb2; });
117   TestOp([&]() { return bomb1 > bomb2; });
118   TestOp([&]() { return bomb1 >= bomb2; });
119 }
120 
TEST(ThrowingValueTest,ThrowingArithmeticOps)121 TEST(ThrowingValueTest, ThrowingArithmeticOps) {
122   ThrowingValue<> bomb1(1), bomb2(2);
123 
124   TestOp([&bomb1]() { +bomb1; });
125   TestOp([&bomb1]() { -bomb1; });
126   TestOp([&bomb1]() { ++bomb1; });
127   TestOp([&bomb1]() { bomb1++; });
128   TestOp([&bomb1]() { --bomb1; });
129   TestOp([&bomb1]() { bomb1--; });
130 
131   TestOp([&]() { bomb1 + bomb2; });
132   TestOp([&]() { bomb1 - bomb2; });
133   TestOp([&]() { bomb1* bomb2; });
134   TestOp([&]() { bomb1 / bomb2; });
135   TestOp([&]() { bomb1 << 1; });
136   TestOp([&]() { bomb1 >> 1; });
137 }
138 
TEST(ThrowingValueTest,ThrowingLogicalOps)139 TEST(ThrowingValueTest, ThrowingLogicalOps) {
140   ThrowingValue<> bomb1, bomb2;
141 
142   TestOp([&bomb1]() { !bomb1; });
143   TestOp([&]() { bomb1&& bomb2; });
144   TestOp([&]() { bomb1 || bomb2; });
145 }
146 
TEST(ThrowingValueTest,ThrowingBitwiseOps)147 TEST(ThrowingValueTest, ThrowingBitwiseOps) {
148   ThrowingValue<> bomb1, bomb2;
149 
150   TestOp([&bomb1]() { ~bomb1; });
151   TestOp([&]() { bomb1 & bomb2; });
152   TestOp([&]() { bomb1 | bomb2; });
153   TestOp([&]() { bomb1 ^ bomb2; });
154 }
155 
TEST(ThrowingValueTest,ThrowingCompoundAssignmentOps)156 TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
157   ThrowingValue<> bomb1(1), bomb2(2);
158 
159   TestOp([&]() { bomb1 += bomb2; });
160   TestOp([&]() { bomb1 -= bomb2; });
161   TestOp([&]() { bomb1 *= bomb2; });
162   TestOp([&]() { bomb1 /= bomb2; });
163   TestOp([&]() { bomb1 %= bomb2; });
164   TestOp([&]() { bomb1 &= bomb2; });
165   TestOp([&]() { bomb1 |= bomb2; });
166   TestOp([&]() { bomb1 ^= bomb2; });
167   TestOp([&]() { bomb1 *= bomb2; });
168 }
169 
TEST(ThrowingValueTest,ThrowingStreamOps)170 TEST(ThrowingValueTest, ThrowingStreamOps) {
171   ThrowingValue<> bomb;
172 
173   TestOp([&]() {
174     std::istringstream stream;
175     stream >> bomb;
176   });
177   TestOp([&]() {
178     std::stringstream stream;
179     stream << bomb;
180   });
181 }
182 
183 // Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit
184 // a nonfatal failure that contains the string representation of the Thrower
TEST(ThrowingValueTest,StreamOpsOutput)185 TEST(ThrowingValueTest, StreamOpsOutput) {
186   using ::testing::TypeSpec;
187   exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
188 
189   // Test default spec list (kEverythingThrows)
190   EXPECT_NONFATAL_FAILURE(
191       {
192         using Thrower = ThrowingValue<TypeSpec{}>;
193         auto thrower = Thrower(123);
194         thrower.~Thrower();
195       },
196       "ThrowingValue<>(123)");
197 
198   // Test with one item in spec list (kNoThrowCopy)
199   EXPECT_NONFATAL_FAILURE(
200       {
201         using Thrower = ThrowingValue<TypeSpec::kNoThrowCopy>;
202         auto thrower = Thrower(234);
203         thrower.~Thrower();
204       },
205       "ThrowingValue<kNoThrowCopy>(234)");
206 
207   // Test with multiple items in spec list (kNoThrowMove, kNoThrowNew)
208   EXPECT_NONFATAL_FAILURE(
209       {
210         using Thrower =
211             ThrowingValue<TypeSpec::kNoThrowMove | TypeSpec::kNoThrowNew>;
212         auto thrower = Thrower(345);
213         thrower.~Thrower();
214       },
215       "ThrowingValue<kNoThrowMove | kNoThrowNew>(345)");
216 
217   // Test with all items in spec list (kNoThrowCopy, kNoThrowMove, kNoThrowNew)
218   EXPECT_NONFATAL_FAILURE(
219       {
220         using Thrower = ThrowingValue<static_cast<TypeSpec>(-1)>;
221         auto thrower = Thrower(456);
222         thrower.~Thrower();
223       },
224       "ThrowingValue<kNoThrowCopy | kNoThrowMove | kNoThrowNew>(456)");
225 }
226 
227 template <typename F>
TestAllocatingOp(const F & f)228 void TestAllocatingOp(const F& f) {
229   ExpectNoThrow(f);
230 
231   SetCountdown();
232   EXPECT_THROW(f(), exceptions_internal::TestBadAllocException);
233   UnsetCountdown();
234 }
235 
TEST(ThrowingValueTest,ThrowingAllocatingOps)236 TEST(ThrowingValueTest, ThrowingAllocatingOps) {
237   // make_unique calls unqualified operator new, so these exercise the
238   // ThrowingValue overloads.
239   TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>>(1); });
240   TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); });
241 }
242 
TEST(ThrowingValueTest,NonThrowingMoveCtor)243 TEST(ThrowingValueTest, NonThrowingMoveCtor) {
244   ThrowingValue<TypeSpec::kNoThrowMove> nothrow_ctor;
245 
246   SetCountdown();
247   ExpectNoThrow([&nothrow_ctor]() {
248     ThrowingValue<TypeSpec::kNoThrowMove> nothrow1 = std::move(nothrow_ctor);
249   });
250   UnsetCountdown();
251 }
252 
TEST(ThrowingValueTest,NonThrowingMoveAssign)253 TEST(ThrowingValueTest, NonThrowingMoveAssign) {
254   ThrowingValue<TypeSpec::kNoThrowMove> nothrow_assign1, nothrow_assign2;
255 
256   SetCountdown();
257   ExpectNoThrow([&nothrow_assign1, &nothrow_assign2]() {
258     nothrow_assign1 = std::move(nothrow_assign2);
259   });
260   UnsetCountdown();
261 }
262 
TEST(ThrowingValueTest,ThrowingCopyCtor)263 TEST(ThrowingValueTest, ThrowingCopyCtor) {
264   ThrowingValue<> tv;
265 
266   TestOp([&]() { ThrowingValue<> tv_copy(tv); });
267 }
268 
TEST(ThrowingValueTest,ThrowingCopyAssign)269 TEST(ThrowingValueTest, ThrowingCopyAssign) {
270   ThrowingValue<> tv1, tv2;
271 
272   TestOp([&]() { tv1 = tv2; });
273 }
274 
TEST(ThrowingValueTest,NonThrowingCopyCtor)275 TEST(ThrowingValueTest, NonThrowingCopyCtor) {
276   ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_ctor;
277 
278   SetCountdown();
279   ExpectNoThrow([&nothrow_ctor]() {
280     ThrowingValue<TypeSpec::kNoThrowCopy> nothrow1(nothrow_ctor);
281   });
282   UnsetCountdown();
283 }
284 
TEST(ThrowingValueTest,NonThrowingCopyAssign)285 TEST(ThrowingValueTest, NonThrowingCopyAssign) {
286   ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_assign1, nothrow_assign2;
287 
288   SetCountdown();
289   ExpectNoThrow([&nothrow_assign1, &nothrow_assign2]() {
290     nothrow_assign1 = nothrow_assign2;
291   });
292   UnsetCountdown();
293 }
294 
TEST(ThrowingValueTest,ThrowingSwap)295 TEST(ThrowingValueTest, ThrowingSwap) {
296   ThrowingValue<> bomb1, bomb2;
297   TestOp([&]() { std::swap(bomb1, bomb2); });
298 }
299 
TEST(ThrowingValueTest,NonThrowingSwap)300 TEST(ThrowingValueTest, NonThrowingSwap) {
301   ThrowingValue<TypeSpec::kNoThrowMove> bomb1, bomb2;
302   ExpectNoThrow([&]() { std::swap(bomb1, bomb2); });
303 }
304 
TEST(ThrowingValueTest,NonThrowingAllocation)305 TEST(ThrowingValueTest, NonThrowingAllocation) {
306   ThrowingValue<TypeSpec::kNoThrowNew>* allocated;
307   ThrowingValue<TypeSpec::kNoThrowNew>* array;
308 
309   ExpectNoThrow([&allocated]() {
310     allocated = new ThrowingValue<TypeSpec::kNoThrowNew>(1);
311     delete allocated;
312   });
313   ExpectNoThrow([&array]() {
314     array = new ThrowingValue<TypeSpec::kNoThrowNew>[2];
315     delete[] array;
316   });
317 }
318 
TEST(ThrowingValueTest,NonThrowingDelete)319 TEST(ThrowingValueTest, NonThrowingDelete) {
320   auto* allocated = new ThrowingValue<>(1);
321   auto* array = new ThrowingValue<>[2];
322 
323   SetCountdown();
324   ExpectNoThrow([allocated]() { delete allocated; });
325   SetCountdown();
326   ExpectNoThrow([array]() { delete[] array; });
327 
328   UnsetCountdown();
329 }
330 
TEST(ThrowingValueTest,NonThrowingPlacementDelete)331 TEST(ThrowingValueTest, NonThrowingPlacementDelete) {
332   constexpr int kArrayLen = 2;
333   // We intentionally create extra space to store the tag allocated by placement
334   // new[].
335   constexpr size_t kExtraSpaceLen = sizeof(size_t) * 2;
336 
337   alignas(ThrowingValue<>) unsigned char buf[sizeof(ThrowingValue<>)];
338   alignas(ThrowingValue<>) unsigned char
339       array_buf[kExtraSpaceLen + sizeof(ThrowingValue<>[kArrayLen])];
340   auto* placed = new (&buf) ThrowingValue<>(1);
341   auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen];
342   auto* placed_array_end = reinterpret_cast<unsigned char*>(placed_array) +
343                            sizeof(ThrowingValue<>[kArrayLen]);
344   EXPECT_LE(placed_array_end, array_buf + sizeof(array_buf));
345 
346   SetCountdown();
347   ExpectNoThrow([placed, &buf]() {
348     placed->~ThrowingValue<>();
349     ThrowingValue<>::operator delete(placed, &buf);
350   });
351 
352   SetCountdown();
353   ExpectNoThrow([&, placed_array]() {
354     for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>();
355     ThrowingValue<>::operator delete[](placed_array, &array_buf);
356   });
357 
358   UnsetCountdown();
359 }
360 
TEST(ThrowingValueTest,NonThrowingDestructor)361 TEST(ThrowingValueTest, NonThrowingDestructor) {
362   auto* allocated = new ThrowingValue<>();
363 
364   SetCountdown();
365   ExpectNoThrow([allocated]() { delete allocated; });
366   UnsetCountdown();
367 }
368 
TEST(ThrowingBoolTest,ThrowingBool)369 TEST(ThrowingBoolTest, ThrowingBool) {
370   ThrowingBool t = true;
371 
372   // Test that it's contextually convertible to bool
373   if (t) {  // NOLINT(whitespace/empty_if_body)
374   }
375   EXPECT_TRUE(t);
376 
377   TestOp([&]() { (void)!t; });
378 }
379 
TEST(ThrowingAllocatorTest,MemoryManagement)380 TEST(ThrowingAllocatorTest, MemoryManagement) {
381   // Just exercise the memory management capabilities under LSan to make sure we
382   // don't leak.
383   ThrowingAllocator<int> int_alloc;
384   int* ip = int_alloc.allocate(1);
385   int_alloc.deallocate(ip, 1);
386   int* i_array = int_alloc.allocate(2);
387   int_alloc.deallocate(i_array, 2);
388 
389   ThrowingAllocator<ThrowingValue<>> tv_alloc;
390   ThrowingValue<>* ptr = tv_alloc.allocate(1);
391   tv_alloc.deallocate(ptr, 1);
392   ThrowingValue<>* tv_array = tv_alloc.allocate(2);
393   tv_alloc.deallocate(tv_array, 2);
394 }
395 
TEST(ThrowingAllocatorTest,CallsGlobalNew)396 TEST(ThrowingAllocatorTest, CallsGlobalNew) {
397   ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> nothrow_alloc;
398   ThrowingValue<>* ptr;
399 
400   SetCountdown();
401   // This will only throw if ThrowingValue::new is called.
402   ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
403   nothrow_alloc.deallocate(ptr, 1);
404 
405   UnsetCountdown();
406 }
407 
TEST(ThrowingAllocatorTest,ThrowingConstructors)408 TEST(ThrowingAllocatorTest, ThrowingConstructors) {
409   ThrowingAllocator<int> int_alloc;
410   int* ip = nullptr;
411 
412   SetCountdown();
413   EXPECT_THROW(ip = int_alloc.allocate(1), TestException);
414   ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
415 
416   *ip = 1;
417   SetCountdown();
418   EXPECT_THROW(int_alloc.construct(ip, 2), TestException);
419   EXPECT_EQ(*ip, 1);
420   int_alloc.deallocate(ip, 1);
421 
422   UnsetCountdown();
423 }
424 
TEST(ThrowingAllocatorTest,NonThrowingConstruction)425 TEST(ThrowingAllocatorTest, NonThrowingConstruction) {
426   {
427     ThrowingAllocator<int, AllocSpec::kNoThrowAllocate> int_alloc;
428     int* ip = nullptr;
429 
430     SetCountdown();
431     ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
432 
433     SetCountdown();
434     ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
435 
436     EXPECT_EQ(*ip, 2);
437     int_alloc.deallocate(ip, 1);
438 
439     UnsetCountdown();
440   }
441 
442   {
443     ThrowingAllocator<int> int_alloc;
444     int* ip = nullptr;
445     ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
446     ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
447     EXPECT_EQ(*ip, 2);
448     int_alloc.deallocate(ip, 1);
449   }
450 
451   {
452     ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate>
453         nothrow_alloc;
454     ThrowingValue<>* ptr;
455 
456     SetCountdown();
457     ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
458 
459     SetCountdown();
460     ExpectNoThrow(
461         [&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); });
462 
463     EXPECT_EQ(ptr->Get(), 2);
464     nothrow_alloc.destroy(ptr);
465     nothrow_alloc.deallocate(ptr, 1);
466 
467     UnsetCountdown();
468   }
469 
470   {
471     ThrowingAllocator<int> a;
472 
473     SetCountdown();
474     ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; });
475 
476     SetCountdown();
477     ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); });
478 
479     UnsetCountdown();
480   }
481 }
482 
TEST(ThrowingAllocatorTest,ThrowingAllocatorConstruction)483 TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) {
484   ThrowingAllocator<int> a;
485   TestOp([]() { ThrowingAllocator<int> a; });
486   TestOp([&]() { a.select_on_container_copy_construction(); });
487 }
488 
TEST(ThrowingAllocatorTest,State)489 TEST(ThrowingAllocatorTest, State) {
490   ThrowingAllocator<int> a1, a2;
491   EXPECT_NE(a1, a2);
492 
493   auto a3 = a1;
494   EXPECT_EQ(a3, a1);
495   int* ip = a1.allocate(1);
496   EXPECT_EQ(a3, a1);
497   a3.deallocate(ip, 1);
498   EXPECT_EQ(a3, a1);
499 }
500 
TEST(ThrowingAllocatorTest,InVector)501 TEST(ThrowingAllocatorTest, InVector) {
502   std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v;
503   for (int i = 0; i < 20; ++i) v.push_back({});
504   for (int i = 0; i < 20; ++i) v.pop_back();
505 }
506 
TEST(ThrowingAllocatorTest,InList)507 TEST(ThrowingAllocatorTest, InList) {
508   std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l;
509   for (int i = 0; i < 20; ++i) l.push_back({});
510   for (int i = 0; i < 20; ++i) l.pop_back();
511   for (int i = 0; i < 20; ++i) l.push_front({});
512   for (int i = 0; i < 20; ++i) l.pop_front();
513 }
514 
515 template <typename TesterInstance, typename = void>
516 struct NullaryTestValidator : public std::false_type {};
517 
518 template <typename TesterInstance>
519 struct NullaryTestValidator<
520     TesterInstance,
521     absl::void_t<decltype(std::declval<TesterInstance>().Test())>>
522     : public std::true_type {};
523 
524 template <typename TesterInstance>
HasNullaryTest(const TesterInstance &)525 bool HasNullaryTest(const TesterInstance&) {
526   return NullaryTestValidator<TesterInstance>::value;
527 }
528 
DummyOp(void *)529 void DummyOp(void*) {}
530 
531 template <typename TesterInstance, typename = void>
532 struct UnaryTestValidator : public std::false_type {};
533 
534 template <typename TesterInstance>
535 struct UnaryTestValidator<
536     TesterInstance,
537     absl::void_t<decltype(std::declval<TesterInstance>().Test(DummyOp))>>
538     : public std::true_type {};
539 
540 template <typename TesterInstance>
HasUnaryTest(const TesterInstance &)541 bool HasUnaryTest(const TesterInstance&) {
542   return UnaryTestValidator<TesterInstance>::value;
543 }
544 
TEST(ExceptionSafetyTesterTest,IncompleteTypesAreNotTestable)545 TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) {
546   using T = exceptions_internal::UninitializedT;
547   auto op = [](T* t) {};
548   auto inv = [](T*) { return testing::AssertionSuccess(); };
549   auto fac = []() { return absl::make_unique<T>(); };
550 
551   // Test that providing operation and inveriants still does not allow for the
552   // the invocation of .Test() and .Test(op) because it lacks a factory
553   auto without_fac =
554       testing::MakeExceptionSafetyTester().WithOperation(op).WithContracts(
555           inv, testing::strong_guarantee);
556   EXPECT_FALSE(HasNullaryTest(without_fac));
557   EXPECT_FALSE(HasUnaryTest(without_fac));
558 
559   // Test that providing contracts and factory allows the invocation of
560   // .Test(op) but does not allow for .Test() because it lacks an operation
561   auto without_op = testing::MakeExceptionSafetyTester()
562                         .WithContracts(inv, testing::strong_guarantee)
563                         .WithFactory(fac);
564   EXPECT_FALSE(HasNullaryTest(without_op));
565   EXPECT_TRUE(HasUnaryTest(without_op));
566 
567   // Test that providing operation and factory still does not allow for the
568   // the invocation of .Test() and .Test(op) because it lacks contracts
569   auto without_inv =
570       testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac);
571   EXPECT_FALSE(HasNullaryTest(without_inv));
572   EXPECT_FALSE(HasUnaryTest(without_inv));
573 }
574 
575 struct ExampleStruct {};
576 
ExampleFunctionFactory()577 std::unique_ptr<ExampleStruct> ExampleFunctionFactory() {
578   return absl::make_unique<ExampleStruct>();
579 }
580 
ExampleFunctionOperation(ExampleStruct *)581 void ExampleFunctionOperation(ExampleStruct*) {}
582 
ExampleFunctionContract(ExampleStruct *)583 testing::AssertionResult ExampleFunctionContract(ExampleStruct*) {
584   return testing::AssertionSuccess();
585 }
586 
587 struct {
operator ()testing::__anonf03d657b0111::__anonf03d657b4e08588   std::unique_ptr<ExampleStruct> operator()() const {
589     return ExampleFunctionFactory();
590   }
591 } example_struct_factory;
592 
593 struct {
operator ()testing::__anonf03d657b0111::__anonf03d657b4f08594   void operator()(ExampleStruct*) const {}
595 } example_struct_operation;
596 
597 struct {
operator ()testing::__anonf03d657b0111::__anonf03d657b5008598   testing::AssertionResult operator()(ExampleStruct* example_struct) const {
599     return ExampleFunctionContract(example_struct);
600   }
601 } example_struct_contract;
602 
__anonf03d657b5102() 603 auto example_lambda_factory = []() { return ExampleFunctionFactory(); };
604 
__anonf03d657b5202(ExampleStruct*) 605 auto example_lambda_operation = [](ExampleStruct*) {};
606 
__anonf03d657b5302(ExampleStruct* example_struct) 607 auto example_lambda_contract = [](ExampleStruct* example_struct) {
608   return ExampleFunctionContract(example_struct);
609 };
610 
611 // Testing that function references, pointers, structs with operator() and
612 // lambdas can all be used with ExceptionSafetyTester
TEST(ExceptionSafetyTesterTest,MixedFunctionTypes)613 TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) {
614   // function reference
615   EXPECT_TRUE(testing::MakeExceptionSafetyTester()
616                   .WithFactory(ExampleFunctionFactory)
617                   .WithOperation(ExampleFunctionOperation)
618                   .WithContracts(ExampleFunctionContract)
619                   .Test());
620 
621   // function pointer
622   EXPECT_TRUE(testing::MakeExceptionSafetyTester()
623                   .WithFactory(&ExampleFunctionFactory)
624                   .WithOperation(&ExampleFunctionOperation)
625                   .WithContracts(&ExampleFunctionContract)
626                   .Test());
627 
628   // struct
629   EXPECT_TRUE(testing::MakeExceptionSafetyTester()
630                   .WithFactory(example_struct_factory)
631                   .WithOperation(example_struct_operation)
632                   .WithContracts(example_struct_contract)
633                   .Test());
634 
635   // lambda
636   EXPECT_TRUE(testing::MakeExceptionSafetyTester()
637                   .WithFactory(example_lambda_factory)
638                   .WithOperation(example_lambda_operation)
639                   .WithContracts(example_lambda_contract)
640                   .Test());
641 }
642 
643 struct NonNegative {
operator ==testing::__anonf03d657b0111::NonNegative644   bool operator==(const NonNegative& other) const { return i == other.i; }
645   int i;
646 };
647 
CheckNonNegativeInvariants(NonNegative * g)648 testing::AssertionResult CheckNonNegativeInvariants(NonNegative* g) {
649   if (g->i >= 0) {
650     return testing::AssertionSuccess();
651   }
652   return testing::AssertionFailure()
653          << "i should be non-negative but is " << g->i;
654 }
655 
656 struct {
657   template <typename T>
operator ()testing::__anonf03d657b0111::__anonf03d657b5408658   void operator()(T* t) const {
659     (*t)();
660   }
661 } invoker;
662 
663 auto tester =
664     testing::MakeExceptionSafetyTester().WithOperation(invoker).WithContracts(
665         CheckNonNegativeInvariants);
666 auto strong_tester = tester.WithContracts(testing::strong_guarantee);
667 
668 struct FailsBasicGuarantee : public NonNegative {
operator ()testing::__anonf03d657b0111::FailsBasicGuarantee669   void operator()() {
670     --i;
671     ThrowingValue<> bomb;
672     ++i;
673   }
674 };
675 
TEST(ExceptionCheckTest,BasicGuaranteeFailure)676 TEST(ExceptionCheckTest, BasicGuaranteeFailure) {
677   EXPECT_FALSE(tester.WithInitialValue(FailsBasicGuarantee{}).Test());
678 }
679 
680 struct FollowsBasicGuarantee : public NonNegative {
operator ()testing::__anonf03d657b0111::FollowsBasicGuarantee681   void operator()() {
682     ++i;
683     ThrowingValue<> bomb;
684   }
685 };
686 
TEST(ExceptionCheckTest,BasicGuarantee)687 TEST(ExceptionCheckTest, BasicGuarantee) {
688   EXPECT_TRUE(tester.WithInitialValue(FollowsBasicGuarantee{}).Test());
689 }
690 
TEST(ExceptionCheckTest,StrongGuaranteeFailure)691 TEST(ExceptionCheckTest, StrongGuaranteeFailure) {
692   EXPECT_FALSE(strong_tester.WithInitialValue(FailsBasicGuarantee{}).Test());
693   EXPECT_FALSE(strong_tester.WithInitialValue(FollowsBasicGuarantee{}).Test());
694 }
695 
696 struct BasicGuaranteeWithExtraContracts : public NonNegative {
697   // After operator(), i is incremented.  If operator() throws, i is set to 9999
operator ()testing::__anonf03d657b0111::BasicGuaranteeWithExtraContracts698   void operator()() {
699     int old_i = i;
700     i = kExceptionSentinel;
701     ThrowingValue<> bomb;
702     i = ++old_i;
703   }
704 
705   static constexpr int kExceptionSentinel = 9999;
706 };
707 
708 #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
709 constexpr int BasicGuaranteeWithExtraContracts::kExceptionSentinel;
710 #endif
711 
TEST(ExceptionCheckTest,BasicGuaranteeWithExtraContracts)712 TEST(ExceptionCheckTest, BasicGuaranteeWithExtraContracts) {
713   auto tester_with_val =
714       tester.WithInitialValue(BasicGuaranteeWithExtraContracts{});
715   EXPECT_TRUE(tester_with_val.Test());
716   EXPECT_TRUE(
717       tester_with_val
718           .WithContracts([](BasicGuaranteeWithExtraContracts* o) {
719             if (o->i == BasicGuaranteeWithExtraContracts::kExceptionSentinel) {
720               return testing::AssertionSuccess();
721             }
722             return testing::AssertionFailure()
723                    << "i should be "
724                    << BasicGuaranteeWithExtraContracts::kExceptionSentinel
725                    << ", but is " << o->i;
726           })
727           .Test());
728 }
729 
730 struct FollowsStrongGuarantee : public NonNegative {
operator ()testing::__anonf03d657b0111::FollowsStrongGuarantee731   void operator()() { ThrowingValue<> bomb; }
732 };
733 
TEST(ExceptionCheckTest,StrongGuarantee)734 TEST(ExceptionCheckTest, StrongGuarantee) {
735   EXPECT_TRUE(tester.WithInitialValue(FollowsStrongGuarantee{}).Test());
736   EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}).Test());
737 }
738 
739 struct HasReset : public NonNegative {
operator ()testing::__anonf03d657b0111::HasReset740   void operator()() {
741     i = -1;
742     ThrowingValue<> bomb;
743     i = 1;
744   }
745 
resettesting::__anonf03d657b0111::HasReset746   void reset() { i = 0; }
747 };
748 
CheckHasResetContracts(HasReset * h)749 testing::AssertionResult CheckHasResetContracts(HasReset* h) {
750   h->reset();
751   return testing::AssertionResult(h->i == 0);
752 }
753 
TEST(ExceptionCheckTest,ModifyingChecker)754 TEST(ExceptionCheckTest, ModifyingChecker) {
755   auto set_to_1000 = [](FollowsBasicGuarantee* g) {
756     g->i = 1000;
757     return testing::AssertionSuccess();
758   };
759   auto is_1000 = [](FollowsBasicGuarantee* g) {
760     return testing::AssertionResult(g->i == 1000);
761   };
762   auto increment = [](FollowsStrongGuarantee* g) {
763     ++g->i;
764     return testing::AssertionSuccess();
765   };
766 
767   EXPECT_FALSE(tester.WithInitialValue(FollowsBasicGuarantee{})
768                    .WithContracts(set_to_1000, is_1000)
769                    .Test());
770   EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{})
771                   .WithContracts(increment)
772                   .Test());
773   EXPECT_TRUE(testing::MakeExceptionSafetyTester()
774                   .WithInitialValue(HasReset{})
775                   .WithContracts(CheckHasResetContracts)
776                   .Test(invoker));
777 }
778 
TEST(ExceptionSafetyTesterTest,ResetsCountdown)779 TEST(ExceptionSafetyTesterTest, ResetsCountdown) {
780   auto test =
781       testing::MakeExceptionSafetyTester()
782           .WithInitialValue(ThrowingValue<>())
783           .WithContracts([](ThrowingValue<>*) { return AssertionSuccess(); })
784           .WithOperation([](ThrowingValue<>*) {});
785   ASSERT_TRUE(test.Test());
786   // If the countdown isn't reset because there were no exceptions thrown, then
787   // this will fail with a termination from an unhandled exception
788   EXPECT_TRUE(test.Test());
789 }
790 
791 struct NonCopyable : public NonNegative {
792   NonCopyable(const NonCopyable&) = delete;
NonCopyabletesting::__anonf03d657b0111::NonCopyable793   NonCopyable() : NonNegative{0} {}
794 
operator ()testing::__anonf03d657b0111::NonCopyable795   void operator()() { ThrowingValue<> bomb; }
796 };
797 
TEST(ExceptionCheckTest,NonCopyable)798 TEST(ExceptionCheckTest, NonCopyable) {
799   auto factory = []() { return absl::make_unique<NonCopyable>(); };
800   EXPECT_TRUE(tester.WithFactory(factory).Test());
801   EXPECT_TRUE(strong_tester.WithFactory(factory).Test());
802 }
803 
804 struct NonEqualityComparable : public NonNegative {
operator ()testing::__anonf03d657b0111::NonEqualityComparable805   void operator()() { ThrowingValue<> bomb; }
806 
ModifyOnThrowtesting::__anonf03d657b0111::NonEqualityComparable807   void ModifyOnThrow() {
808     ++i;
809     ThrowingValue<> bomb;
810     static_cast<void>(bomb);
811     --i;
812   }
813 };
814 
TEST(ExceptionCheckTest,NonEqualityComparable)815 TEST(ExceptionCheckTest, NonEqualityComparable) {
816   auto nec_is_strong = [](NonEqualityComparable* nec) {
817     return testing::AssertionResult(nec->i == NonEqualityComparable().i);
818   };
819   auto strong_nec_tester = tester.WithInitialValue(NonEqualityComparable{})
820                                .WithContracts(nec_is_strong);
821 
822   EXPECT_TRUE(strong_nec_tester.Test());
823   EXPECT_FALSE(strong_nec_tester.Test(
824       [](NonEqualityComparable* n) { n->ModifyOnThrow(); }));
825 }
826 
827 template <typename T>
828 struct ExhaustivenessTester {
operator ()testing::__anonf03d657b0111::ExhaustivenessTester829   void operator()() {
830     successes |= 1;
831     T b1;
832     static_cast<void>(b1);
833     successes |= (1 << 1);
834     T b2;
835     static_cast<void>(b2);
836     successes |= (1 << 2);
837     T b3;
838     static_cast<void>(b3);
839     successes |= (1 << 3);
840   }
841 
operator ==testing::__anonf03d657b0111::ExhaustivenessTester842   bool operator==(const ExhaustivenessTester<ThrowingValue<>>&) const {
843     return true;
844   }
845 
846   static unsigned char successes;
847 };
848 
849 struct {
850   template <typename T>
operator ()testing::__anonf03d657b0111::__anonf03d657b5e08851   testing::AssertionResult operator()(ExhaustivenessTester<T>*) const {
852     return testing::AssertionSuccess();
853   }
854 } CheckExhaustivenessTesterContracts;
855 
856 template <typename T>
857 unsigned char ExhaustivenessTester<T>::successes = 0;
858 
TEST(ExceptionCheckTest,Exhaustiveness)859 TEST(ExceptionCheckTest, Exhaustiveness) {
860   auto exhaust_tester = testing::MakeExceptionSafetyTester()
861                             .WithContracts(CheckExhaustivenessTesterContracts)
862                             .WithOperation(invoker);
863 
864   EXPECT_TRUE(
865       exhaust_tester.WithInitialValue(ExhaustivenessTester<int>{}).Test());
866   EXPECT_EQ(ExhaustivenessTester<int>::successes, 0xF);
867 
868   EXPECT_TRUE(
869       exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{})
870           .WithContracts(testing::strong_guarantee)
871           .Test());
872   EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF);
873 }
874 
875 struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject {
LeaksIfCtorThrowstesting::__anonf03d657b0111::LeaksIfCtorThrows876   LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) {
877     ++counter;
878     ThrowingValue<> v;
879     static_cast<void>(v);
880     --counter;
881   }
LeaksIfCtorThrowstesting::__anonf03d657b0111::LeaksIfCtorThrows882   LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept
883       : TrackedObject(ABSL_PRETTY_FUNCTION) {}
884   static int counter;
885 };
886 int LeaksIfCtorThrows::counter = 0;
887 
TEST(ExceptionCheckTest,TestLeakyCtor)888 TEST(ExceptionCheckTest, TestLeakyCtor) {
889   testing::TestThrowingCtor<LeaksIfCtorThrows>();
890   EXPECT_EQ(LeaksIfCtorThrows::counter, 1);
891   LeaksIfCtorThrows::counter = 0;
892 }
893 
894 struct Tracked : private exceptions_internal::TrackedObject {
Trackedtesting::__anonf03d657b0111::Tracked895   Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {}
896 };
897 
TEST(ConstructorTrackerTest,CreatedBefore)898 TEST(ConstructorTrackerTest, CreatedBefore) {
899   Tracked a, b, c;
900   exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
901 }
902 
TEST(ConstructorTrackerTest,CreatedAfter)903 TEST(ConstructorTrackerTest, CreatedAfter) {
904   exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
905   Tracked a, b, c;
906 }
907 
TEST(ConstructorTrackerTest,NotDestroyedAfter)908 TEST(ConstructorTrackerTest, NotDestroyedAfter) {
909   alignas(Tracked) unsigned char storage[sizeof(Tracked)];
910   EXPECT_NONFATAL_FAILURE(
911       {
912         exceptions_internal::ConstructorTracker ct(
913             exceptions_internal::countdown);
914         new (&storage) Tracked();
915       },
916       "not destroyed");
917 }
918 
TEST(ConstructorTrackerTest,DestroyedTwice)919 TEST(ConstructorTrackerTest, DestroyedTwice) {
920   exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
921   EXPECT_NONFATAL_FAILURE(
922       {
923         Tracked t;
924         t.~Tracked();
925       },
926       "re-destroyed");
927 }
928 
TEST(ConstructorTrackerTest,ConstructedTwice)929 TEST(ConstructorTrackerTest, ConstructedTwice) {
930   exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
931   alignas(Tracked) unsigned char storage[sizeof(Tracked)];
932   EXPECT_NONFATAL_FAILURE(
933       {
934         new (&storage) Tracked();
935         new (&storage) Tracked();
936         reinterpret_cast<Tracked*>(&storage)->~Tracked();
937       },
938       "re-constructed");
939 }
940 
TEST(ThrowingValueTraitsTest,RelationalOperators)941 TEST(ThrowingValueTraitsTest, RelationalOperators) {
942   ThrowingValue<> a, b;
943   EXPECT_TRUE((std::is_convertible<decltype(a == b), bool>::value));
944   EXPECT_TRUE((std::is_convertible<decltype(a != b), bool>::value));
945   EXPECT_TRUE((std::is_convertible<decltype(a < b), bool>::value));
946   EXPECT_TRUE((std::is_convertible<decltype(a <= b), bool>::value));
947   EXPECT_TRUE((std::is_convertible<decltype(a > b), bool>::value));
948   EXPECT_TRUE((std::is_convertible<decltype(a >= b), bool>::value));
949 }
950 
TEST(ThrowingAllocatorTraitsTest,Assignablility)951 TEST(ThrowingAllocatorTraitsTest, Assignablility) {
952   EXPECT_TRUE(absl::is_move_assignable<ThrowingAllocator<int>>::value);
953   EXPECT_TRUE(absl::is_copy_assignable<ThrowingAllocator<int>>::value);
954   EXPECT_TRUE(std::is_nothrow_move_assignable<ThrowingAllocator<int>>::value);
955   EXPECT_TRUE(std::is_nothrow_copy_assignable<ThrowingAllocator<int>>::value);
956 }
957 
958 }  // namespace
959 
960 }  // namespace testing
961 
962 #endif  // ABSL_HAVE_EXCEPTIONS
963