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([¬hrow_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([¬hrow_assign1, ¬hrow_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([¬hrow_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([¬hrow_assign1, ¬hrow_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