17 #include "gtest/gtest.h" 24 using ::testing::AssertionFailure;
25 using ::testing::AssertionResult;
26 using ::testing::AssertionSuccess;
35 constexpr
int kInitialInteger = 5;
36 constexpr
int kUpdatedInteger = 10;
38 template <
typename OptionalT>
39 bool ValueThrowsBadOptionalAccess(
const OptionalT& optional)
try {
40 return (static_cast<void>(optional.value()),
false);
45 template <
typename OptionalT>
46 AssertionResult OptionalInvariants(OptionalT* optional_ptr) {
48 auto& optional = *optional_ptr;
50 if (optional.has_value() && ValueThrowsBadOptionalAccess(optional)) {
51 return AssertionFailure()
52 <<
"Optional with value should not throw bad_optional_access when " 53 "accessing the value.";
55 if (!optional.has_value() && !ValueThrowsBadOptionalAccess(optional)) {
56 return AssertionFailure()
57 <<
"Optional without a value should throw bad_optional_access when " 58 "accessing the value.";
65 if (optional.has_value()) {
66 return AssertionFailure()
67 <<
"Optional should not contain a value after being reset.";
69 if (!ValueThrowsBadOptionalAccess(optional)) {
70 return AssertionFailure() <<
"Optional should throw bad_optional_access " 71 "when accessing the value after being reset.";
74 return AssertionSuccess();
77 template <
typename OptionalT>
78 AssertionResult CheckDisengaged(OptionalT* optional_ptr) {
79 auto& optional = *optional_ptr;
81 if (optional.has_value()) {
82 return AssertionFailure()
83 <<
"Expected optional to not contain a value but a value was found.";
86 return AssertionSuccess();
89 template <
typename OptionalT>
90 AssertionResult CheckEngaged(OptionalT* optional_ptr) {
91 auto& optional = *optional_ptr;
93 if (!optional.has_value()) {
94 return AssertionFailure()
95 <<
"Expected optional to contain a value but no value was found.";
98 return AssertionSuccess();
101 TEST(OptionalExceptionSafety, ThrowingConstructors) {
103 testing::TestThrowingCtor<Optional>(thrower_nonempty);
106 testing::TestThrowingCtor<Optional>(integer_nonempty);
107 testing::TestThrowingCtor<Optional>(
std::move(integer_nonempty));
109 testing::TestThrowingCtor<Optional>(kInitialInteger);
110 using ThrowerVec = std::vector<Thrower, testing::ThrowingAllocator<Thrower>>;
111 testing::TestThrowingCtor<absl::optional<ThrowerVec>>(
117 TEST(OptionalExceptionSafety, NothrowConstructors) {
120 testing::TestThrowingCtor<MoveOptional>(MoveOptional(kUpdatedInteger));
123 TEST(OptionalExceptionSafety, Emplace) {
127 OptionalInvariants<Optional>, CheckDisengaged<Optional>);
128 auto disengaged_test_empty = disengaged_test.WithInitialValue(
Optional());
129 auto disengaged_test_nonempty =
130 disengaged_test.WithInitialValue(
Optional(kInitialInteger));
132 auto emplace_thrower_directly = [](
Optional* optional_ptr) {
133 optional_ptr->emplace(kUpdatedInteger);
135 EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_directly));
136 EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_directly));
138 auto emplace_thrower_copy = [](
Optional* optional_ptr) {
140 optional_ptr->emplace(thrower);
142 EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_copy));
143 EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_copy));
146 TEST(OptionalExceptionSafety, EverythingThrowsSwap) {
151 auto disengaged_test_empty = test.WithInitialValue(
Optional())
152 .WithContracts(CheckDisengaged<Optional>);
153 auto engaged_test_nonempty = test.WithInitialValue(
Optional(kInitialInteger))
154 .WithContracts(CheckEngaged<Optional>);
156 auto swap_empty = [](
Optional* optional_ptr) {
158 optional_ptr->swap(empty);
160 EXPECT_TRUE(engaged_test_nonempty.Test(swap_empty));
162 auto swap_nonempty = [](
Optional* optional_ptr) {
165 optional_ptr->swap(nonempty);
167 EXPECT_TRUE(disengaged_test_empty.Test(swap_nonempty));
168 EXPECT_TRUE(engaged_test_nonempty.Test(swap_nonempty));
171 TEST(OptionalExceptionSafety, NoThrowMoveSwap) {
174 auto empty = MoveOptional();
175 auto nonempty = MoveOptional(kInitialInteger);
179 auto nonempty = MoveOptional(kUpdatedInteger);
180 auto empty = MoveOptional();
184 auto nonempty_from = MoveOptional(kUpdatedInteger);
185 auto nonempty_to = MoveOptional(kInitialInteger);
191 TEST(OptionalExceptionSafety, CopyAssign) {
196 auto disengaged_test_empty = test.WithInitialValue(
Optional())
197 .WithContracts(CheckDisengaged<Optional>);
198 auto engaged_test_nonempty = test.WithInitialValue(
Optional(kInitialInteger))
199 .WithContracts(CheckEngaged<Optional>);
201 auto copyassign_nonempty = [](
Optional* optional_ptr) {
204 *optional_ptr = nonempty;
206 EXPECT_TRUE(disengaged_test_empty.Test(copyassign_nonempty));
207 EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_nonempty));
209 auto copyassign_thrower = [](
Optional* optional_ptr) {
211 *optional_ptr = thrower;
213 EXPECT_TRUE(disengaged_test_empty.Test(copyassign_thrower));
214 EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_thrower));
217 TEST(OptionalExceptionSafety, MoveAssign) {
222 auto disengaged_test_empty = test.WithInitialValue(
Optional())
223 .WithContracts(CheckDisengaged<Optional>);
224 auto engaged_test_nonempty = test.WithInitialValue(
Optional(kInitialInteger))
225 .WithContracts(CheckEngaged<Optional>);
227 auto moveassign_empty = [](
Optional* optional_ptr) {
231 EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_empty));
233 auto moveassign_nonempty = [](
Optional* optional_ptr) {
238 EXPECT_TRUE(disengaged_test_empty.Test(moveassign_nonempty));
239 EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_nonempty));
241 auto moveassign_thrower = [](
Optional* optional_ptr) {
245 EXPECT_TRUE(disengaged_test_empty.Test(moveassign_thrower));
246 EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_thrower));
249 TEST(OptionalExceptionSafety, NothrowMoveAssign) {
252 auto empty = MoveOptional();
253 auto nonempty = MoveOptional(kInitialInteger);
257 auto nonempty = MoveOptional(kInitialInteger);
258 auto empty = MoveOptional();
262 auto nonempty_from = MoveOptional(kUpdatedInteger);
263 auto nonempty_to = MoveOptional(kInitialInteger);
265 [&]() { nonempty_to =
std::move(nonempty_from); }));
268 auto thrower = MoveThrower(kUpdatedInteger);
269 auto empty = MoveOptional();
273 auto thrower = MoveThrower(kUpdatedInteger);
274 auto nonempty = MoveOptional(kInitialInteger);
TEST(NotificationTest, SanityTest)
exceptions_internal::ExceptionSafetyTestBuilder MakeExceptionSafetyTester()
testing::ThrowingValue<> Thrower
exceptions_internal::NoThrowTag nothrow_ctor
ABSL_ATTRIBUTE_REINITIALIZES void reset() noexcept
testing::AssertionResult TestNothrowOp(const Operation &operation)
ExceptionSafetyTestBuilder< Factory, Operation, Contracts..., absl::decay_t< MoreContracts >... > WithContracts(const MoreContracts &... more_contracts) const
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
static bool Optional(bool)
std::vector< Thrower > ThrowerVec