summaryrefslogtreecommitdiff
path: root/absl/base/exception_safety_testing_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/base/exception_safety_testing_test.cc')
-rw-r--r--absl/base/exception_safety_testing_test.cc185
1 files changed, 158 insertions, 27 deletions
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 <typename F>
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<NonCopyable>(g.i))));
+}
+
+struct NonEqualityComparable {
+ void operator()() { ThrowingValue<> bomb; }
+
+ void ModifyOnThrow() {
+ ++i;
+ ThrowingValue<> bomb;
+ static_cast<void>(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 <typename T>
@@ -480,11 +588,14 @@ struct InstructionCounter {
++counter;
}
- bool operator!=(const InstructionCounter<ThrowingValue<>>& other) const {
- return false;
+ bool operator==(const InstructionCounter<ThrowingValue<>>&) 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<T>::counter = 0;
TEST(ExceptionCheckTest, Exhaustiveness) {
InstructionCounter<int> int_factory;
- EXPECT_TRUE(TestBasicGuarantee(&int_factory, CallOperator{}));
+ EXPECT_TRUE(TestExceptionSafety(&int_factory, CallOperator{}));
EXPECT_EQ(InstructionCounter<int>::counter, 4);
InstructionCounter<ThrowingValue<>> bomb_factory;
- EXPECT_TRUE(TestBasicGuarantee(&bomb_factory, CallOperator{}));
+ EXPECT_TRUE(TestExceptionSafety(&bomb_factory, CallOperator{}));
EXPECT_EQ(InstructionCounter<ThrowingValue<>>::counter, 10);
InstructionCounter<ThrowingValue<>>::counter = 0;
- EXPECT_TRUE(TestStrongGuarantee(&bomb_factory, CallOperator{}));
+ EXPECT_TRUE(TestExceptionSafety(&bomb_factory, CallOperator{},
+ StrongGuarantee(bomb_factory)));
EXPECT_EQ(InstructionCounter<ThrowingValue<>>::counter, 10);
}
+struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject {
+ LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) {
+ ++counter;
+ ThrowingValue<> v;
+ static_cast<void>(v);
+ --counter;
+ }
+ LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept
+ : TrackedObject(ABSL_PRETTY_FUNCTION) {}
+ static int counter;
+};
+int LeaksIfCtorThrows::counter = 0;
+
+TEST(ExceptionCheckTest, TestLeakyCtor) {
+ absl::TestThrowingCtor<LeaksIfCtorThrows>();
+ EXPECT_EQ(LeaksIfCtorThrows::counter, 1);
+ LeaksIfCtorThrows::counter = 0;
+}
+
struct Tracked : private exceptions_internal::TrackedObject {
Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {}
};