Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "absl/types/optional.h"
00016
00017 #include "gtest/gtest.h"
00018 #include "absl/base/internal/exception_safety_testing.h"
00019
00020 namespace absl {
00021
00022 namespace {
00023
00024 using ::testing::AssertionFailure;
00025 using ::testing::AssertionResult;
00026 using ::testing::AssertionSuccess;
00027 using ::testing::MakeExceptionSafetyTester;
00028
00029 using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
00030 using Optional = absl::optional<Thrower>;
00031
00032 using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
00033 using MoveOptional = absl::optional<MoveThrower>;
00034
00035 constexpr int kInitialInteger = 5;
00036 constexpr int kUpdatedInteger = 10;
00037
00038 template <typename OptionalT>
00039 bool ValueThrowsBadOptionalAccess(const OptionalT& optional) try {
00040 return (static_cast<void>(optional.value()), false);
00041 } catch (const absl::bad_optional_access&) {
00042 return true;
00043 }
00044
00045 template <typename OptionalT>
00046 AssertionResult OptionalInvariants(OptionalT* optional_ptr) {
00047
00048 auto& optional = *optional_ptr;
00049
00050 if (optional.has_value() && ValueThrowsBadOptionalAccess(optional)) {
00051 return AssertionFailure()
00052 << "Optional with value should not throw bad_optional_access when "
00053 "accessing the value.";
00054 }
00055 if (!optional.has_value() && !ValueThrowsBadOptionalAccess(optional)) {
00056 return AssertionFailure()
00057 << "Optional without a value should throw bad_optional_access when "
00058 "accessing the value.";
00059 }
00060
00061
00062 optional.reset();
00063
00064
00065 if (optional.has_value()) {
00066 return AssertionFailure()
00067 << "Optional should not contain a value after being reset.";
00068 }
00069 if (!ValueThrowsBadOptionalAccess(optional)) {
00070 return AssertionFailure() << "Optional should throw bad_optional_access "
00071 "when accessing the value after being reset.";
00072 }
00073
00074 return AssertionSuccess();
00075 }
00076
00077 template <typename OptionalT>
00078 AssertionResult CheckDisengaged(OptionalT* optional_ptr) {
00079 auto& optional = *optional_ptr;
00080
00081 if (optional.has_value()) {
00082 return AssertionFailure()
00083 << "Expected optional to not contain a value but a value was found.";
00084 }
00085
00086 return AssertionSuccess();
00087 }
00088
00089 template <typename OptionalT>
00090 AssertionResult CheckEngaged(OptionalT* optional_ptr) {
00091 auto& optional = *optional_ptr;
00092
00093 if (!optional.has_value()) {
00094 return AssertionFailure()
00095 << "Expected optional to contain a value but no value was found.";
00096 }
00097
00098 return AssertionSuccess();
00099 }
00100
00101 TEST(OptionalExceptionSafety, ThrowingConstructors) {
00102 auto thrower_nonempty = Optional(Thrower(kInitialInteger));
00103 testing::TestThrowingCtor<Optional>(thrower_nonempty);
00104
00105 auto integer_nonempty = absl::optional<int>(kInitialInteger);
00106 testing::TestThrowingCtor<Optional>(integer_nonempty);
00107 testing::TestThrowingCtor<Optional>(std::move(integer_nonempty));
00108
00109 testing::TestThrowingCtor<Optional>(kInitialInteger);
00110 using ThrowerVec = std::vector<Thrower, testing::ThrowingAllocator<Thrower>>;
00111 testing::TestThrowingCtor<absl::optional<ThrowerVec>>(
00112 absl::in_place,
00113 std::initializer_list<Thrower>{Thrower(), Thrower(), Thrower()},
00114 testing::ThrowingAllocator<Thrower>());
00115 }
00116
00117 TEST(OptionalExceptionSafety, NothrowConstructors) {
00118
00119
00120 testing::TestThrowingCtor<MoveOptional>(MoveOptional(kUpdatedInteger));
00121 }
00122
00123 TEST(OptionalExceptionSafety, Emplace) {
00124
00125
00126 auto disengaged_test = MakeExceptionSafetyTester().WithContracts(
00127 OptionalInvariants<Optional>, CheckDisengaged<Optional>);
00128 auto disengaged_test_empty = disengaged_test.WithInitialValue(Optional());
00129 auto disengaged_test_nonempty =
00130 disengaged_test.WithInitialValue(Optional(kInitialInteger));
00131
00132 auto emplace_thrower_directly = [](Optional* optional_ptr) {
00133 optional_ptr->emplace(kUpdatedInteger);
00134 };
00135 EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_directly));
00136 EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_directly));
00137
00138 auto emplace_thrower_copy = [](Optional* optional_ptr) {
00139 auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor);
00140 optional_ptr->emplace(thrower);
00141 };
00142 EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_copy));
00143 EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_copy));
00144 }
00145
00146 TEST(OptionalExceptionSafety, EverythingThrowsSwap) {
00147
00148
00149 auto test =
00150 MakeExceptionSafetyTester().WithContracts(OptionalInvariants<Optional>);
00151 auto disengaged_test_empty = test.WithInitialValue(Optional())
00152 .WithContracts(CheckDisengaged<Optional>);
00153 auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger))
00154 .WithContracts(CheckEngaged<Optional>);
00155
00156 auto swap_empty = [](Optional* optional_ptr) {
00157 auto empty = Optional();
00158 optional_ptr->swap(empty);
00159 };
00160 EXPECT_TRUE(engaged_test_nonempty.Test(swap_empty));
00161
00162 auto swap_nonempty = [](Optional* optional_ptr) {
00163 auto nonempty =
00164 Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
00165 optional_ptr->swap(nonempty);
00166 };
00167 EXPECT_TRUE(disengaged_test_empty.Test(swap_nonempty));
00168 EXPECT_TRUE(engaged_test_nonempty.Test(swap_nonempty));
00169 }
00170
00171 TEST(OptionalExceptionSafety, NoThrowMoveSwap) {
00172
00173 {
00174 auto empty = MoveOptional();
00175 auto nonempty = MoveOptional(kInitialInteger);
00176 EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty.swap(empty); }));
00177 }
00178 {
00179 auto nonempty = MoveOptional(kUpdatedInteger);
00180 auto empty = MoveOptional();
00181 EXPECT_TRUE(testing::TestNothrowOp([&]() { empty.swap(nonempty); }));
00182 }
00183 {
00184 auto nonempty_from = MoveOptional(kUpdatedInteger);
00185 auto nonempty_to = MoveOptional(kInitialInteger);
00186 EXPECT_TRUE(
00187 testing::TestNothrowOp([&]() { nonempty_to.swap(nonempty_from); }));
00188 }
00189 }
00190
00191 TEST(OptionalExceptionSafety, CopyAssign) {
00192
00193
00194 auto test =
00195 MakeExceptionSafetyTester().WithContracts(OptionalInvariants<Optional>);
00196 auto disengaged_test_empty = test.WithInitialValue(Optional())
00197 .WithContracts(CheckDisengaged<Optional>);
00198 auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger))
00199 .WithContracts(CheckEngaged<Optional>);
00200
00201 auto copyassign_nonempty = [](Optional* optional_ptr) {
00202 auto nonempty =
00203 Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
00204 *optional_ptr = nonempty;
00205 };
00206 EXPECT_TRUE(disengaged_test_empty.Test(copyassign_nonempty));
00207 EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_nonempty));
00208
00209 auto copyassign_thrower = [](Optional* optional_ptr) {
00210 auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor);
00211 *optional_ptr = thrower;
00212 };
00213 EXPECT_TRUE(disengaged_test_empty.Test(copyassign_thrower));
00214 EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_thrower));
00215 }
00216
00217 TEST(OptionalExceptionSafety, MoveAssign) {
00218
00219
00220 auto test =
00221 MakeExceptionSafetyTester().WithContracts(OptionalInvariants<Optional>);
00222 auto disengaged_test_empty = test.WithInitialValue(Optional())
00223 .WithContracts(CheckDisengaged<Optional>);
00224 auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger))
00225 .WithContracts(CheckEngaged<Optional>);
00226
00227 auto moveassign_empty = [](Optional* optional_ptr) {
00228 auto empty = Optional();
00229 *optional_ptr = std::move(empty);
00230 };
00231 EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_empty));
00232
00233 auto moveassign_nonempty = [](Optional* optional_ptr) {
00234 auto nonempty =
00235 Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
00236 *optional_ptr = std::move(nonempty);
00237 };
00238 EXPECT_TRUE(disengaged_test_empty.Test(moveassign_nonempty));
00239 EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_nonempty));
00240
00241 auto moveassign_thrower = [](Optional* optional_ptr) {
00242 auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor);
00243 *optional_ptr = std::move(thrower);
00244 };
00245 EXPECT_TRUE(disengaged_test_empty.Test(moveassign_thrower));
00246 EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_thrower));
00247 }
00248
00249 TEST(OptionalExceptionSafety, NothrowMoveAssign) {
00250
00251 {
00252 auto empty = MoveOptional();
00253 auto nonempty = MoveOptional(kInitialInteger);
00254 EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty = std::move(empty); }));
00255 }
00256 {
00257 auto nonempty = MoveOptional(kInitialInteger);
00258 auto empty = MoveOptional();
00259 EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(nonempty); }));
00260 }
00261 {
00262 auto nonempty_from = MoveOptional(kUpdatedInteger);
00263 auto nonempty_to = MoveOptional(kInitialInteger);
00264 EXPECT_TRUE(testing::TestNothrowOp(
00265 [&]() { nonempty_to = std::move(nonempty_from); }));
00266 }
00267 {
00268 auto thrower = MoveThrower(kUpdatedInteger);
00269 auto empty = MoveOptional();
00270 EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(thrower); }));
00271 }
00272 {
00273 auto thrower = MoveThrower(kUpdatedInteger);
00274 auto nonempty = MoveOptional(kInitialInteger);
00275 EXPECT_TRUE(
00276 testing::TestNothrowOp([&]() { nonempty = std::move(thrower); }));
00277 }
00278 }
00279
00280 }
00281
00282 }