From ae0cef35ae5a7bfd873fb87babdd4900cbdb073c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 22 Nov 2017 07:42:54 -0800 Subject: Changes imported from Abseil "staging" branch: - 55c7dd8ad1570b4e6ce2103ed4d4b6becdea0d96 Remove line continuations which require CMake >= 3.0. Al... by Jon Cohen - ee66ad72a90259d6286bbfea7241ed976bb0f6fb Change absl::ParseDuration() to avoid double. This allow... by Abseil Team - 89cf4cd49d8ff25cb3d29f06b2090029a2024e89 Internal change by Gennadiy Rozental - cdb5879bf6aaf6bbd2ad1fe4a2b144bbdf0389c7 Internal change by Gennadiy Rozental - e7b29d11bf24a63bf7637689ada8be7d619844fc Internal change by Gennadiy Rozental - 2d4fc08d5d64a7760ad6230eccdb5b8014c2b0c3 Update the exception-safety testing framework. by Jon Cohen GitOrigin-RevId: 55c7dd8ad1570b4e6ce2103ed4d4b6becdea0d96 Change-Id: I6b560cbc4570dfc5aa9a2f90e84d69904df7eac5 --- absl/base/exception_safety_testing_test.cc | 185 ++++++++++++++++++++++++----- 1 file changed, 158 insertions(+), 27 deletions(-) (limited to 'absl/base/exception_safety_testing_test.cc') diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc index 365732c6..c1b5df26 100644 --- a/absl/base/exception_safety_testing_test.cc +++ b/absl/base/exception_safety_testing_test.cc @@ -14,10 +14,6 @@ namespace absl { namespace { using ::absl::exceptions_internal::TestException; -void SetCountdown() { exceptions_internal::countdown = 0; } - -void UnsetCountdown() { exceptions_internal::countdown = -1; } - // EXPECT_NO_THROW can't inspect the thrown inspection in general. template void ExpectNoThrow(const F& f) { @@ -395,12 +391,15 @@ struct FailsBasicGuarantee { ++i; } - bool operator!=(const FailsBasicGuarantee& other) const { + bool operator==(const FailsBasicGuarantee& other) const { return i != other.i; } - friend bool AbslCheckInvariants(const FailsBasicGuarantee& g) { - return g.i >= 0; + friend testing::AssertionResult AbslCheckInvariants( + const FailsBasicGuarantee& g) { + if (g.i >= 0) return testing::AssertionSuccess(); + return testing::AssertionFailure() + << "i should be non-negative but is " << g.i; } int i = 0; @@ -408,7 +407,7 @@ struct FailsBasicGuarantee { TEST(ExceptionCheckTest, BasicGuaranteeFailure) { FailsBasicGuarantee g; - EXPECT_FALSE(TestBasicGuarantee(&g, CallOperator{})); + EXPECT_FALSE(TestExceptionSafety(&g, CallOperator{})); } struct FollowsBasicGuarantee { @@ -417,12 +416,15 @@ struct FollowsBasicGuarantee { ThrowingValue<> bomb; } - bool operator!=(const FollowsBasicGuarantee& other) const { - return i != other.i; + bool operator==(const FollowsBasicGuarantee& other) const { + return i == other.i; } - friend bool AbslCheckInvariants(const FollowsBasicGuarantee& g) { - return g.i >= 0; + friend testing::AssertionResult AbslCheckInvariants( + const FollowsBasicGuarantee& g) { + if (g.i >= 0) return testing::AssertionSuccess(); + return testing::AssertionFailure() + << "i should be non-negative but is " << g.i; } int i = 0; @@ -430,30 +432,79 @@ struct FollowsBasicGuarantee { TEST(ExceptionCheckTest, BasicGuarantee) { FollowsBasicGuarantee g; - EXPECT_TRUE(TestBasicGuarantee(&g, CallOperator{})); + EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{})); } TEST(ExceptionCheckTest, StrongGuaranteeFailure) { { FailsBasicGuarantee g; - EXPECT_FALSE(TestStrongGuarantee(&g, CallOperator{})); + EXPECT_FALSE(TestExceptionSafety(&g, CallOperator{}, StrongGuarantee(g))); } { FollowsBasicGuarantee g; - EXPECT_FALSE(TestStrongGuarantee(&g, CallOperator{})); + EXPECT_FALSE(TestExceptionSafety(&g, CallOperator{}, StrongGuarantee(g))); + } +} + +struct BasicGuaranteeWithExtraInvariants { + // After operator(), i is incremented. If operator() throws, i is set to 9999 + void operator()() { + int old_i = i; + i = kExceptionSentinel; + ThrowingValue<> bomb; + i = ++old_i; + } + + bool operator==(const FollowsBasicGuarantee& other) const { + return i == other.i; + } + + friend testing::AssertionResult AbslCheckInvariants( + const BasicGuaranteeWithExtraInvariants& g) { + if (g.i >= 0) return testing::AssertionSuccess(); + return testing::AssertionFailure() + << "i should be non-negative but is " << g.i; + } + + int i = 0; + static constexpr int kExceptionSentinel = 9999; +}; +constexpr int BasicGuaranteeWithExtraInvariants::kExceptionSentinel; + +TEST(ExceptionCheckTest, BasicGuaranteeWithInvariants) { + { + BasicGuaranteeWithExtraInvariants g; + EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{})); + } + + { + BasicGuaranteeWithExtraInvariants g; + EXPECT_TRUE(TestExceptionSafety( + &g, CallOperator{}, [](const BasicGuaranteeWithExtraInvariants& w) { + if (w.i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) { + return testing::AssertionSuccess(); + } + return testing::AssertionFailure() + << "i should be " + << BasicGuaranteeWithExtraInvariants::kExceptionSentinel + << ", but is " << w.i; + })); } } struct FollowsStrongGuarantee { void operator()() { ThrowingValue<> bomb; } - bool operator!=(const FollowsStrongGuarantee& other) const { - return i != other.i; + bool operator==(const FollowsStrongGuarantee& other) const { + return i == other.i; } - friend bool AbslCheckInvariants(const FollowsStrongGuarantee& g) { - return g.i >= 0; + friend testing::AssertionResult AbslCheckInvariants( + const FollowsStrongGuarantee& g) { + if (g.i >= 0) return testing::AssertionSuccess(); + return testing::AssertionFailure() + << "i should be non-negative but is " << g.i; } int i = 0; @@ -461,8 +512,65 @@ struct FollowsStrongGuarantee { TEST(ExceptionCheckTest, StrongGuarantee) { FollowsStrongGuarantee g; - EXPECT_TRUE(TestBasicGuarantee(&g, CallOperator{})); - EXPECT_TRUE(TestStrongGuarantee(&g, CallOperator{})); + EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{})); + EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{}, StrongGuarantee(g))); +} + +struct NonCopyable { + NonCopyable(const NonCopyable&) = delete; + explicit NonCopyable(int ii) : i(ii) {} + + void operator()() { ThrowingValue<> bomb; } + + bool operator==(const NonCopyable& other) const { return i == other.i; } + + friend testing::AssertionResult AbslCheckInvariants(const NonCopyable& g) { + if (g.i >= 0) return testing::AssertionSuccess(); + return testing::AssertionFailure() + << "i should be non-negative but is " << g.i; + } + + int i; +}; + +TEST(ExceptionCheckTest, NonCopyable) { + NonCopyable g(0); + EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{})); + EXPECT_TRUE(TestExceptionSafety( + &g, CallOperator{}, + PointeeStrongGuarantee(absl::make_unique(g.i)))); +} + +struct NonEqualityComparable { + void operator()() { ThrowingValue<> bomb; } + + void ModifyOnThrow() { + ++i; + ThrowingValue<> bomb; + static_cast(bomb); + --i; + } + + friend testing::AssertionResult AbslCheckInvariants( + const NonEqualityComparable& g) { + if (g.i >= 0) return testing::AssertionSuccess(); + return testing::AssertionFailure() + << "i should be non-negative but is " << g.i; + } + + int i = 0; +}; + +TEST(ExceptionCheckTest, NonEqualityComparable) { + NonEqualityComparable g; + auto comp = [](const NonEqualityComparable& a, + const NonEqualityComparable& b) { return a.i == b.i; }; + EXPECT_TRUE(TestExceptionSafety(&g, CallOperator{})); + EXPECT_TRUE( + TestExceptionSafety(&g, CallOperator{}, absl::StrongGuarantee(g, comp))); + EXPECT_FALSE(TestExceptionSafety( + &g, [&](NonEqualityComparable* n) { n->ModifyOnThrow(); }, + absl::StrongGuarantee(g, comp))); } template @@ -480,11 +588,14 @@ struct InstructionCounter { ++counter; } - bool operator!=(const InstructionCounter>& other) const { - return false; + bool operator==(const InstructionCounter>&) const { + return true; } - friend bool AbslCheckInvariants(const InstructionCounter&) { return true; } + friend testing::AssertionResult AbslCheckInvariants( + const InstructionCounter&) { + return testing::AssertionSuccess(); + } static int counter; }; @@ -493,18 +604,38 @@ int InstructionCounter::counter = 0; TEST(ExceptionCheckTest, Exhaustiveness) { InstructionCounter int_factory; - EXPECT_TRUE(TestBasicGuarantee(&int_factory, CallOperator{})); + EXPECT_TRUE(TestExceptionSafety(&int_factory, CallOperator{})); EXPECT_EQ(InstructionCounter::counter, 4); InstructionCounter> bomb_factory; - EXPECT_TRUE(TestBasicGuarantee(&bomb_factory, CallOperator{})); + EXPECT_TRUE(TestExceptionSafety(&bomb_factory, CallOperator{})); EXPECT_EQ(InstructionCounter>::counter, 10); InstructionCounter>::counter = 0; - EXPECT_TRUE(TestStrongGuarantee(&bomb_factory, CallOperator{})); + EXPECT_TRUE(TestExceptionSafety(&bomb_factory, CallOperator{}, + StrongGuarantee(bomb_factory))); EXPECT_EQ(InstructionCounter>::counter, 10); } +struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject { + LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) { + ++counter; + ThrowingValue<> v; + static_cast(v); + --counter; + } + LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept + : TrackedObject(ABSL_PRETTY_FUNCTION) {} + static int counter; +}; +int LeaksIfCtorThrows::counter = 0; + +TEST(ExceptionCheckTest, TestLeakyCtor) { + absl::TestThrowingCtor(); + EXPECT_EQ(LeaksIfCtorThrows::counter, 1); + LeaksIfCtorThrows::counter = 0; +} + struct Tracked : private exceptions_internal::TrackedObject { Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {} }; -- cgit v1.2.3