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


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:19:56