optional_exception_safety_test.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
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   // Check the current state post-throw for validity
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   // Reset to a known state
00062   optional.reset();
00063 
00064   // Confirm that the known post-reset state is valid
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));  // NOLINT
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   // This constructor is marked noexcept. If it throws, the program will
00119   // terminate.
00120   testing::TestThrowingCtor<MoveOptional>(MoveOptional(kUpdatedInteger));
00121 }
00122 
00123 TEST(OptionalExceptionSafety, Emplace) {
00124   // Test the basic guarantee plus test the result of optional::has_value()
00125   // is false in all cases
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   // Test the basic guarantee plus test the result of optional::has_value()
00148   // remains the same
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   // Tests the nothrow guarantee for optional of T with non-throwing move
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   // Test the basic guarantee plus test the result of optional::has_value()
00193   // remains the same
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   // Test the basic guarantee plus test the result of optional::has_value()
00219   // remains the same
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   // Tests the nothrow guarantee for optional of T with non-throwing move
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 }  // namespace
00281 
00282 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15