blob: c1b5df265467fcd9c1cb500d9a208b30b5c994d8 [file] [log] [blame]
Abseil Team8db6cfd2017-10-30 15:55:37 -07001#include "absl/base/internal/exception_safety_testing.h"
2
3#include <cstddef>
4#include <exception>
5#include <iostream>
6#include <list>
7#include <vector>
8
9#include "gtest/gtest-spi.h"
10#include "gtest/gtest.h"
11#include "absl/memory/memory.h"
12
13namespace absl {
14namespace {
15using ::absl::exceptions_internal::TestException;
16
Abseil Team8db6cfd2017-10-30 15:55:37 -070017// EXPECT_NO_THROW can't inspect the thrown inspection in general.
18template <typename F>
19void ExpectNoThrow(const F& f) {
20 try {
21 f();
22 } catch (TestException e) {
23 ADD_FAILURE() << "Unexpected exception thrown from " << e.what();
24 }
25}
26
27class ThrowingValueTest : public ::testing::Test {
28 protected:
29 void SetUp() override { UnsetCountdown(); }
30
31 private:
32 AllocInspector clouseau_;
33};
34
35TEST_F(ThrowingValueTest, Throws) {
36 SetCountdown();
37 EXPECT_THROW(ThrowingValue<> bomb, TestException);
38
39 // It's not guaranteed that every operator only throws *once*. The default
40 // ctor only throws once, though, so use it to make sure we only throw when
41 // the countdown hits 0
42 exceptions_internal::countdown = 2;
43 ExpectNoThrow([]() { ThrowingValue<> bomb; });
44 ExpectNoThrow([]() { ThrowingValue<> bomb; });
45 EXPECT_THROW(ThrowingValue<> bomb, TestException);
46}
47
48// Tests that an operation throws when the countdown is at 0, doesn't throw when
49// the countdown doesn't hit 0, and doesn't modify the state of the
50// ThrowingValue if it throws
51template <typename F>
52void TestOp(F&& f) {
53 UnsetCountdown();
54 ExpectNoThrow(f);
55
56 SetCountdown();
57 EXPECT_THROW(f(), TestException);
58 UnsetCountdown();
59}
60
61TEST_F(ThrowingValueTest, ThrowingCtors) {
62 ThrowingValue<> bomb;
63
64 TestOp([]() { ThrowingValue<> bomb(1); });
65 TestOp([&]() { ThrowingValue<> bomb1 = bomb; });
66 TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); });
67}
68
69TEST_F(ThrowingValueTest, ThrowingAssignment) {
70 ThrowingValue<> bomb, bomb1;
71
72 TestOp([&]() { bomb = bomb1; });
73 TestOp([&]() { bomb = std::move(bomb1); });
74}
75
76TEST_F(ThrowingValueTest, ThrowingComparisons) {
77 ThrowingValue<> bomb1, bomb2;
78 TestOp([&]() { return bomb1 == bomb2; });
79 TestOp([&]() { return bomb1 != bomb2; });
80 TestOp([&]() { return bomb1 < bomb2; });
81 TestOp([&]() { return bomb1 <= bomb2; });
82 TestOp([&]() { return bomb1 > bomb2; });
83 TestOp([&]() { return bomb1 >= bomb2; });
84}
85
86TEST_F(ThrowingValueTest, ThrowingArithmeticOps) {
87 ThrowingValue<> bomb1(1), bomb2(2);
88
89 TestOp([&bomb1]() { +bomb1; });
90 TestOp([&bomb1]() { -bomb1; });
91 TestOp([&bomb1]() { ++bomb1; });
92 TestOp([&bomb1]() { bomb1++; });
93 TestOp([&bomb1]() { --bomb1; });
94 TestOp([&bomb1]() { bomb1--; });
95
96 TestOp([&]() { bomb1 + bomb2; });
97 TestOp([&]() { bomb1 - bomb2; });
98 TestOp([&]() { bomb1* bomb2; });
99 TestOp([&]() { bomb1 / bomb2; });
100 TestOp([&]() { bomb1 << 1; });
101 TestOp([&]() { bomb1 >> 1; });
102}
103
104TEST_F(ThrowingValueTest, ThrowingLogicalOps) {
105 ThrowingValue<> bomb1, bomb2;
106
107 TestOp([&bomb1]() { !bomb1; });
108 TestOp([&]() { bomb1&& bomb2; });
109 TestOp([&]() { bomb1 || bomb2; });
110}
111
112TEST_F(ThrowingValueTest, ThrowingBitwiseOps) {
113 ThrowingValue<> bomb1, bomb2;
114
115 TestOp([&bomb1]() { ~bomb1; });
116 TestOp([&]() { bomb1& bomb2; });
117 TestOp([&]() { bomb1 | bomb2; });
118 TestOp([&]() { bomb1 ^ bomb2; });
119}
120
121TEST_F(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
122 ThrowingValue<> bomb1(1), bomb2(2);
123
124 TestOp([&]() { bomb1 += bomb2; });
125 TestOp([&]() { bomb1 -= bomb2; });
126 TestOp([&]() { bomb1 *= bomb2; });
127 TestOp([&]() { bomb1 /= bomb2; });
128 TestOp([&]() { bomb1 %= bomb2; });
129 TestOp([&]() { bomb1 &= bomb2; });
130 TestOp([&]() { bomb1 |= bomb2; });
131 TestOp([&]() { bomb1 ^= bomb2; });
132 TestOp([&]() { bomb1 *= bomb2; });
133}
134
135TEST_F(ThrowingValueTest, ThrowingStreamOps) {
136 ThrowingValue<> bomb;
137
138 TestOp([&]() { std::cin >> bomb; });
139 TestOp([&]() { std::cout << bomb; });
140}
141
142TEST_F(ThrowingValueTest, ThrowingAllocatingOps) {
143 // make_unique calls unqualified operator new, so these exercise the
144 // ThrowingValue overloads.
145 TestOp([]() { return absl::make_unique<ThrowingValue<>>(1); });
146 TestOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); });
147}
148
149TEST_F(ThrowingValueTest, NonThrowingMoveCtor) {
150 ThrowingValue<NoThrow::kMoveCtor> nothrow_ctor;
151
152 SetCountdown();
153 ExpectNoThrow([&nothrow_ctor]() {
154 ThrowingValue<NoThrow::kMoveCtor> nothrow1 = std::move(nothrow_ctor);
155 });
156}
157
158TEST_F(ThrowingValueTest, NonThrowingMoveAssign) {
159 ThrowingValue<NoThrow::kMoveAssign> nothrow_assign1, nothrow_assign2;
160
161 SetCountdown();
162 ExpectNoThrow([&nothrow_assign1, &nothrow_assign2]() {
163 nothrow_assign1 = std::move(nothrow_assign2);
164 });
165}
166
167TEST_F(ThrowingValueTest, ThrowingSwap) {
168 ThrowingValue<> bomb1, bomb2;
169 TestOp([&]() { std::swap(bomb1, bomb2); });
170
171 ThrowingValue<NoThrow::kMoveCtor> bomb3, bomb4;
172 TestOp([&]() { std::swap(bomb3, bomb4); });
173
174 ThrowingValue<NoThrow::kMoveAssign> bomb5, bomb6;
175 TestOp([&]() { std::swap(bomb5, bomb6); });
176}
177
178TEST_F(ThrowingValueTest, NonThrowingSwap) {
179 ThrowingValue<NoThrow::kMoveAssign | NoThrow::kMoveCtor> bomb1, bomb2;
180 ExpectNoThrow([&]() { std::swap(bomb1, bomb2); });
181}
182
183TEST_F(ThrowingValueTest, NonThrowingAllocation) {
184 ThrowingValue<NoThrow::kAllocation>* allocated;
185 ThrowingValue<NoThrow::kAllocation>* array;
186
187 ExpectNoThrow([&allocated]() {
188 allocated = new ThrowingValue<NoThrow::kAllocation>(1);
189 delete allocated;
190 });
191 ExpectNoThrow([&array]() {
192 array = new ThrowingValue<NoThrow::kAllocation>[2];
193 delete[] array;
194 });
195}
196
197TEST_F(ThrowingValueTest, NonThrowingDelete) {
198 auto* allocated = new ThrowingValue<>(1);
199 auto* array = new ThrowingValue<>[2];
200
201 SetCountdown();
202 ExpectNoThrow([allocated]() { delete allocated; });
203 SetCountdown();
204 ExpectNoThrow([array]() { delete[] array; });
205}
206
207using Storage =
208 absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>;
209
210TEST_F(ThrowingValueTest, NonThrowingPlacementDelete) {
211 constexpr int kArrayLen = 2;
212 // We intentionally create extra space to store the tag allocated by placement
213 // new[].
214 constexpr int kStorageLen = 4;
215
216 Storage buf;
217 Storage array_buf[kStorageLen];
218 auto* placed = new (&buf) ThrowingValue<>(1);
219 auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen];
220
221 SetCountdown();
222 ExpectNoThrow([placed, &buf]() {
223 placed->~ThrowingValue<>();
224 ThrowingValue<>::operator delete(placed, &buf);
225 });
226
227 SetCountdown();
228 ExpectNoThrow([&, placed_array]() {
229 for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>();
230 ThrowingValue<>::operator delete[](placed_array, &array_buf);
231 });
232}
233
234TEST_F(ThrowingValueTest, NonThrowingDestructor) {
235 auto* allocated = new ThrowingValue<>();
236 SetCountdown();
237 ExpectNoThrow([allocated]() { delete allocated; });
238}
239
240TEST(ThrowingBoolTest, ThrowingBool) {
241 UnsetCountdown();
242 ThrowingBool t = true;
243
244 // Test that it's contextually convertible to bool
245 if (t) { // NOLINT(whitespace/empty_if_body)
246 }
247 EXPECT_TRUE(t);
248
249 TestOp([&]() { (void)!t; });
250}
251
252class ThrowingAllocatorTest : public ::testing::Test {
253 protected:
254 void SetUp() override { UnsetCountdown(); }
255
256 private:
257 AllocInspector borlu_;
258};
259
260TEST_F(ThrowingAllocatorTest, MemoryManagement) {
261 // Just exercise the memory management capabilities under LSan to make sure we
262 // don't leak.
263 ThrowingAllocator<int> int_alloc;
264 int* ip = int_alloc.allocate(1);
265 int_alloc.deallocate(ip, 1);
266 int* i_array = int_alloc.allocate(2);
267 int_alloc.deallocate(i_array, 2);
268
269 ThrowingAllocator<ThrowingValue<>> ef_alloc;
270 ThrowingValue<>* efp = ef_alloc.allocate(1);
271 ef_alloc.deallocate(efp, 1);
272 ThrowingValue<>* ef_array = ef_alloc.allocate(2);
273 ef_alloc.deallocate(ef_array, 2);
274}
275
276TEST_F(ThrowingAllocatorTest, CallsGlobalNew) {
277 ThrowingAllocator<ThrowingValue<>, NoThrow::kNoThrow> nothrow_alloc;
278 ThrowingValue<>* ptr;
279
280 SetCountdown();
281 // This will only throw if ThrowingValue::new is called.
282 ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
283 nothrow_alloc.deallocate(ptr, 1);
284}
285
286TEST_F(ThrowingAllocatorTest, ThrowingConstructors) {
287 ThrowingAllocator<int> int_alloc;
288 int* ip = nullptr;
289
290 SetCountdown();
291 EXPECT_THROW(ip = int_alloc.allocate(1), TestException);
292 ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
293
294 *ip = 1;
295 SetCountdown();
296 EXPECT_THROW(int_alloc.construct(ip, 2), TestException);
297 EXPECT_EQ(*ip, 1);
298 int_alloc.deallocate(ip, 1);
299}
300
301TEST_F(ThrowingAllocatorTest, NonThrowingConstruction) {
302 {
303 ThrowingAllocator<int, NoThrow::kNoThrow> int_alloc;
304 int* ip = nullptr;
305
306 SetCountdown();
307 ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
308 SetCountdown();
309 ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
310 EXPECT_EQ(*ip, 2);
311 int_alloc.deallocate(ip, 1);
312 }
313
314 UnsetCountdown();
315 {
316 ThrowingAllocator<int> int_alloc;
317 int* ip = nullptr;
318 ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
319 ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
320 EXPECT_EQ(*ip, 2);
321 int_alloc.deallocate(ip, 1);
322 }
323
324 UnsetCountdown();
325 {
326 ThrowingAllocator<ThrowingValue<NoThrow::kIntCtor>, NoThrow::kNoThrow>
327 ef_alloc;
328 ThrowingValue<NoThrow::kIntCtor>* efp;
329 SetCountdown();
330 ExpectNoThrow([&]() { efp = ef_alloc.allocate(1); });
331 SetCountdown();
332 ExpectNoThrow([&]() { ef_alloc.construct(efp, 2); });
333 EXPECT_EQ(efp->Get(), 2);
334 ef_alloc.destroy(efp);
335 ef_alloc.deallocate(efp, 1);
336 }
337
338 UnsetCountdown();
339 {
340 ThrowingAllocator<int> a;
341 SetCountdown();
342 ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; });
343 SetCountdown();
344 ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); });
345 }
346}
347
348TEST_F(ThrowingAllocatorTest, ThrowingAllocatorConstruction) {
349 ThrowingAllocator<int> a;
350 TestOp([]() { ThrowingAllocator<int> a; });
351 TestOp([&]() { a.select_on_container_copy_construction(); });
352}
353
354TEST_F(ThrowingAllocatorTest, State) {
355 ThrowingAllocator<int> a1, a2;
356 EXPECT_NE(a1, a2);
357
358 auto a3 = a1;
359 EXPECT_EQ(a3, a1);
360 int* ip = a1.allocate(1);
361 EXPECT_EQ(a3, a1);
362 a3.deallocate(ip, 1);
363 EXPECT_EQ(a3, a1);
364}
365
366TEST_F(ThrowingAllocatorTest, InVector) {
367 std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v;
368 for (int i = 0; i < 20; ++i) v.push_back({});
369 for (int i = 0; i < 20; ++i) v.pop_back();
370}
371
372TEST_F(ThrowingAllocatorTest, InList) {
373 std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l;
374 for (int i = 0; i < 20; ++i) l.push_back({});
375 for (int i = 0; i < 20; ++i) l.pop_back();
376 for (int i = 0; i < 20; ++i) l.push_front({});
377 for (int i = 0; i < 20; ++i) l.pop_front();
378}
379
380struct CallOperator {
381 template <typename T>
382 void operator()(T* t) const {
383 (*t)();
384 }
385};
386
387struct FailsBasicGuarantee {
388 void operator()() {
389 --i;
390 ThrowingValue<> bomb;
391 ++i;
392 }
393
Abseil Teamae0cef32017-11-22 07:42:54 -0800394 bool operator==(const FailsBasicGuarantee& other) const {
Abseil Team8db6cfd2017-10-30 15:55:37 -0700395 return i != other.i;
396 }
397
Abseil Teamae0cef32017-11-22 07:42:54 -0800398 friend testing::AssertionResult AbslCheckInvariants(
399 const FailsBasicGuarantee& g) {
400 if (g.i >= 0) return testing::AssertionSuccess();
401 return testing::AssertionFailure()
402 << "i should be non-negative but is " << g.i;
Abseil Team8db6cfd2017-10-30 15:55:37 -0700403 }
404
405 int i = 0;
406};
407
408TEST(ExceptionCheckTest, BasicGuaranteeFailure) {
409 FailsBasicGuarantee g;
Abseil Teamae0cef32017-11-22 07:42:54 -0800410 EXPECT_FALSE(TestExceptionSafety(&g, CallOperator{}));
Abseil Team8db6cfd2017-10-30 15:55:37 -0700411}
412
413struct FollowsBasicGuarantee {
414 void operator()() {
415 ++i;
416 ThrowingValue<> bomb;
417 }
418
Abseil Teamae0cef32017-11-22 07:42:54 -0800419 bool operator==(const FollowsBasicGuarantee& other) const {
420 return i == other.i;
Abseil Team8db6cfd2017-10-30 15:55:37 -0700421 }
422
Abseil Teamae0cef32017-11-22 07:42:54 -0800423 friend testing::AssertionResult AbslCheckInvariants(
424 const FollowsBasicGuarantee& g) {
425 if (g.i >= 0) return testing::AssertionSuccess();
426 return testing::AssertionFailure()
427 << "i should be non-negative but is " << g.i;
Abseil Team8db6cfd2017-10-30 15:55:37 -0700428 }
429
430 int i = 0;
431};
432
433TEST(ExceptionCheckTest, BasicGuarantee) {
434 FollowsBasicGuarantee g;
Abseil Teamae0cef32017-11-22 07:42:54 -0800435 EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{}));
Abseil Team8db6cfd2017-10-30 15:55:37 -0700436}
437
438TEST(ExceptionCheckTest, StrongGuaranteeFailure) {
439 {
440 FailsBasicGuarantee g;
Abseil Teamae0cef32017-11-22 07:42:54 -0800441 EXPECT_FALSE(TestExceptionSafety(&g, CallOperator{}, StrongGuarantee(g)));
Abseil Team8db6cfd2017-10-30 15:55:37 -0700442 }
443
444 {
445 FollowsBasicGuarantee g;
Abseil Teamae0cef32017-11-22 07:42:54 -0800446 EXPECT_FALSE(TestExceptionSafety(&g, CallOperator{}, StrongGuarantee(g)));
447 }
448}
449
450struct BasicGuaranteeWithExtraInvariants {
451 // After operator(), i is incremented. If operator() throws, i is set to 9999
452 void operator()() {
453 int old_i = i;
454 i = kExceptionSentinel;
455 ThrowingValue<> bomb;
456 i = ++old_i;
457 }
458
459 bool operator==(const FollowsBasicGuarantee& other) const {
460 return i == other.i;
461 }
462
463 friend testing::AssertionResult AbslCheckInvariants(
464 const BasicGuaranteeWithExtraInvariants& g) {
465 if (g.i >= 0) return testing::AssertionSuccess();
466 return testing::AssertionFailure()
467 << "i should be non-negative but is " << g.i;
468 }
469
470 int i = 0;
471 static constexpr int kExceptionSentinel = 9999;
472};
473constexpr int BasicGuaranteeWithExtraInvariants::kExceptionSentinel;
474
475TEST(ExceptionCheckTest, BasicGuaranteeWithInvariants) {
476 {
477 BasicGuaranteeWithExtraInvariants g;
478 EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{}));
479 }
480
481 {
482 BasicGuaranteeWithExtraInvariants g;
483 EXPECT_TRUE(TestExceptionSafety(
484 &g, CallOperator{}, [](const BasicGuaranteeWithExtraInvariants& w) {
485 if (w.i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) {
486 return testing::AssertionSuccess();
487 }
488 return testing::AssertionFailure()
489 << "i should be "
490 << BasicGuaranteeWithExtraInvariants::kExceptionSentinel
491 << ", but is " << w.i;
492 }));
Abseil Team8db6cfd2017-10-30 15:55:37 -0700493 }
494}
495
496struct FollowsStrongGuarantee {
497 void operator()() { ThrowingValue<> bomb; }
498
Abseil Teamae0cef32017-11-22 07:42:54 -0800499 bool operator==(const FollowsStrongGuarantee& other) const {
500 return i == other.i;
Abseil Team8db6cfd2017-10-30 15:55:37 -0700501 }
502
Abseil Teamae0cef32017-11-22 07:42:54 -0800503 friend testing::AssertionResult AbslCheckInvariants(
504 const FollowsStrongGuarantee& g) {
505 if (g.i >= 0) return testing::AssertionSuccess();
506 return testing::AssertionFailure()
507 << "i should be non-negative but is " << g.i;
Abseil Team8db6cfd2017-10-30 15:55:37 -0700508 }
509
510 int i = 0;
511};
512
513TEST(ExceptionCheckTest, StrongGuarantee) {
514 FollowsStrongGuarantee g;
Abseil Teamae0cef32017-11-22 07:42:54 -0800515 EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{}));
516 EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{}, StrongGuarantee(g)));
517}
518
519struct NonCopyable {
520 NonCopyable(const NonCopyable&) = delete;
521 explicit NonCopyable(int ii) : i(ii) {}
522
523 void operator()() { ThrowingValue<> bomb; }
524
525 bool operator==(const NonCopyable& other) const { return i == other.i; }
526
527 friend testing::AssertionResult AbslCheckInvariants(const NonCopyable& g) {
528 if (g.i >= 0) return testing::AssertionSuccess();
529 return testing::AssertionFailure()
530 << "i should be non-negative but is " << g.i;
531 }
532
533 int i;
534};
535
536TEST(ExceptionCheckTest, NonCopyable) {
537 NonCopyable g(0);
538 EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{}));
539 EXPECT_TRUE(TestExceptionSafety(
540 &g, CallOperator{},
541 PointeeStrongGuarantee(absl::make_unique<NonCopyable>(g.i))));
542}
543
544struct NonEqualityComparable {
545 void operator()() { ThrowingValue<> bomb; }
546
547 void ModifyOnThrow() {
548 ++i;
549 ThrowingValue<> bomb;
550 static_cast<void>(bomb);
551 --i;
552 }
553
554 friend testing::AssertionResult AbslCheckInvariants(
555 const NonEqualityComparable& g) {
556 if (g.i >= 0) return testing::AssertionSuccess();
557 return testing::AssertionFailure()
558 << "i should be non-negative but is " << g.i;
559 }
560
561 int i = 0;
562};
563
564TEST(ExceptionCheckTest, NonEqualityComparable) {
565 NonEqualityComparable g;
566 auto comp = [](const NonEqualityComparable& a,
567 const NonEqualityComparable& b) { return a.i == b.i; };
568 EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{}));
569 EXPECT_TRUE(
570 TestExceptionSafety(&g, CallOperator{}, absl::StrongGuarantee(g, comp)));
571 EXPECT_FALSE(TestExceptionSafety(
572 &g, [&](NonEqualityComparable* n) { n->ModifyOnThrow(); },
573 absl::StrongGuarantee(g, comp)));
Abseil Team8db6cfd2017-10-30 15:55:37 -0700574}
575
576template <typename T>
577struct InstructionCounter {
578 void operator()() {
579 ++counter;
580 T b1;
581 static_cast<void>(b1);
582 ++counter;
583 T b2;
584 static_cast<void>(b2);
585 ++counter;
586 T b3;
587 static_cast<void>(b3);
588 ++counter;
589 }
590
Abseil Teamae0cef32017-11-22 07:42:54 -0800591 bool operator==(const InstructionCounter<ThrowingValue<>>&) const {
592 return true;
Abseil Team8db6cfd2017-10-30 15:55:37 -0700593 }
594
Abseil Teamae0cef32017-11-22 07:42:54 -0800595 friend testing::AssertionResult AbslCheckInvariants(
596 const InstructionCounter&) {
597 return testing::AssertionSuccess();
598 }
Abseil Team8db6cfd2017-10-30 15:55:37 -0700599
600 static int counter;
601};
602template <typename T>
603int InstructionCounter<T>::counter = 0;
604
605TEST(ExceptionCheckTest, Exhaustiveness) {
606 InstructionCounter<int> int_factory;
Abseil Teamae0cef32017-11-22 07:42:54 -0800607 EXPECT_TRUE(TestExceptionSafety(&int_factory, CallOperator{}));
Abseil Team8db6cfd2017-10-30 15:55:37 -0700608 EXPECT_EQ(InstructionCounter<int>::counter, 4);
609
610 InstructionCounter<ThrowingValue<>> bomb_factory;
Abseil Teamae0cef32017-11-22 07:42:54 -0800611 EXPECT_TRUE(TestExceptionSafety(&bomb_factory, CallOperator{}));
Abseil Team8db6cfd2017-10-30 15:55:37 -0700612 EXPECT_EQ(InstructionCounter<ThrowingValue<>>::counter, 10);
613
614 InstructionCounter<ThrowingValue<>>::counter = 0;
Abseil Teamae0cef32017-11-22 07:42:54 -0800615 EXPECT_TRUE(TestExceptionSafety(&bomb_factory, CallOperator{},
616 StrongGuarantee(bomb_factory)));
Abseil Team8db6cfd2017-10-30 15:55:37 -0700617 EXPECT_EQ(InstructionCounter<ThrowingValue<>>::counter, 10);
618}
619
Abseil Teamae0cef32017-11-22 07:42:54 -0800620struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject {
621 LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) {
622 ++counter;
623 ThrowingValue<> v;
624 static_cast<void>(v);
625 --counter;
626 }
627 LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept
628 : TrackedObject(ABSL_PRETTY_FUNCTION) {}
629 static int counter;
630};
631int LeaksIfCtorThrows::counter = 0;
632
633TEST(ExceptionCheckTest, TestLeakyCtor) {
634 absl::TestThrowingCtor<LeaksIfCtorThrows>();
635 EXPECT_EQ(LeaksIfCtorThrows::counter, 1);
636 LeaksIfCtorThrows::counter = 0;
637}
638
Abseil Team8db6cfd2017-10-30 15:55:37 -0700639struct Tracked : private exceptions_internal::TrackedObject {
640 Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {}
641};
642
643TEST(AllocInspectorTest, Pass) {
644 AllocInspector javert;
645 Tracked t;
646}
647
648TEST(AllocInspectorTest, NotDestroyed) {
649 absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
650 EXPECT_NONFATAL_FAILURE(
651 {
652 AllocInspector gadget;
653 new (&storage) Tracked;
654 },
655 "not destroyed");
656}
657
658TEST(AllocInspectorTest, DestroyedTwice) {
659 EXPECT_NONFATAL_FAILURE(
660 {
661 Tracked t;
662 t.~Tracked();
663 },
664 "destroyed improperly");
665}
666
667TEST(AllocInspectorTest, ConstructedTwice) {
668 absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
669 EXPECT_NONFATAL_FAILURE(
670 {
671 new (&storage) Tracked;
672 new (&storage) Tracked;
673 },
674 "re-constructed");
675}
676} // namespace
677} // namespace absl