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/variant.h"
00016
00017 #include <iostream>
00018 #include <memory>
00019 #include <utility>
00020 #include <vector>
00021
00022 #include "gmock/gmock.h"
00023 #include "gtest/gtest.h"
00024 #include "absl/base/config.h"
00025 #include "absl/base/internal/exception_safety_testing.h"
00026 #include "absl/memory/memory.h"
00027
00028
00029 #if !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
00030
00031 namespace absl {
00032 namespace {
00033
00034 using ::testing::MakeExceptionSafetyTester;
00035 using ::testing::strong_guarantee;
00036 using ::testing::TestNothrowOp;
00037 using ::testing::TestThrowingCtor;
00038
00039 using Thrower = testing::ThrowingValue<>;
00040 using CopyNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowCopy>;
00041 using MoveNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
00042 using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
00043 using ThrowerVec = std::vector<Thrower, ThrowingAlloc>;
00044 using ThrowingVariant =
00045 absl::variant<Thrower, CopyNothrow, MoveNothrow, ThrowerVec>;
00046
00047 struct ConversionException {};
00048
00049 template <class T>
00050 struct ExceptionOnConversion {
00051 operator T() const {
00052 throw ConversionException();
00053 }
00054 };
00055
00056
00057 void ToValuelessByException(ThrowingVariant& v) {
00058 try {
00059 v.emplace<Thrower>();
00060 v.emplace<Thrower>(ExceptionOnConversion<Thrower>());
00061 } catch (const ConversionException&) {
00062
00063 }
00064 }
00065
00066
00067 testing::AssertionResult VariantInvariants(ThrowingVariant* v) {
00068 using testing::AssertionFailure;
00069 using testing::AssertionSuccess;
00070
00071
00072 if (absl::holds_alternative<Thrower>(*v)) {
00073 auto& t = absl::get<Thrower>(*v);
00074 t = Thrower{-100};
00075 if (t.Get() != -100) {
00076 return AssertionFailure() << "Thrower should be assigned -100";
00077 }
00078 } else if (absl::holds_alternative<ThrowerVec>(*v)) {
00079 auto& tv = absl::get<ThrowerVec>(*v);
00080 tv.clear();
00081 tv.emplace_back(-100);
00082 if (tv.size() != 1 || tv[0].Get() != -100) {
00083 return AssertionFailure() << "ThrowerVec should be {Thrower{-100}}";
00084 }
00085 } else if (absl::holds_alternative<CopyNothrow>(*v)) {
00086 auto& t = absl::get<CopyNothrow>(*v);
00087 t = CopyNothrow{-100};
00088 if (t.Get() != -100) {
00089 return AssertionFailure() << "CopyNothrow should be assigned -100";
00090 }
00091 } else if (absl::holds_alternative<MoveNothrow>(*v)) {
00092 auto& t = absl::get<MoveNothrow>(*v);
00093 t = MoveNothrow{-100};
00094 if (t.Get() != -100) {
00095 return AssertionFailure() << "MoveNothrow should be assigned -100";
00096 }
00097 }
00098
00099
00100 if (!v->valueless_by_exception()) ToValuelessByException(*v);
00101 if (!v->valueless_by_exception()) {
00102 return AssertionFailure() << "Variant should be valueless_by_exception";
00103 }
00104 try {
00105 auto unused = absl::get<Thrower>(*v);
00106 static_cast<void>(unused);
00107 return AssertionFailure() << "Variant should not contain Thrower";
00108 } catch (const absl::bad_variant_access&) {
00109 } catch (...) {
00110 return AssertionFailure() << "Unexpected exception throw from absl::get";
00111 }
00112
00113
00114 v->emplace<Thrower>(100);
00115 if (!absl::holds_alternative<Thrower>(*v) ||
00116 absl::get<Thrower>(*v) != Thrower(100)) {
00117 return AssertionFailure() << "Variant should contain Thrower(100)";
00118 }
00119 v->emplace<ThrowerVec>({Thrower(100)});
00120 if (!absl::holds_alternative<ThrowerVec>(*v) ||
00121 absl::get<ThrowerVec>(*v)[0] != Thrower(100)) {
00122 return AssertionFailure()
00123 << "Variant should contain ThrowerVec{Thrower(100)}";
00124 }
00125 return AssertionSuccess();
00126 }
00127
00128 template <typename... Args>
00129 Thrower ExpectedThrower(Args&&... args) {
00130 return Thrower(42, args...);
00131 }
00132
00133 ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; }
00134 ThrowingVariant ValuelessByException() {
00135 ThrowingVariant v;
00136 ToValuelessByException(v);
00137 return v;
00138 }
00139 ThrowingVariant WithThrower() { return Thrower(39); }
00140 ThrowingVariant WithThrowerVec() {
00141 return ThrowerVec{Thrower(1), Thrower(2), Thrower(3)};
00142 }
00143 ThrowingVariant WithCopyNoThrow() { return CopyNothrow(39); }
00144 ThrowingVariant WithMoveNoThrow() { return MoveNothrow(39); }
00145
00146 TEST(VariantExceptionSafetyTest, DefaultConstructor) {
00147 TestThrowingCtor<ThrowingVariant>();
00148 }
00149
00150 TEST(VariantExceptionSafetyTest, CopyConstructor) {
00151 {
00152 ThrowingVariant v(ExpectedThrower());
00153 TestThrowingCtor<ThrowingVariant>(v);
00154 }
00155 {
00156 ThrowingVariant v(ExpectedThrowerVec());
00157 TestThrowingCtor<ThrowingVariant>(v);
00158 }
00159 {
00160 ThrowingVariant v(ValuelessByException());
00161 TestThrowingCtor<ThrowingVariant>(v);
00162 }
00163 }
00164
00165 TEST(VariantExceptionSafetyTest, MoveConstructor) {
00166 {
00167 ThrowingVariant v(ExpectedThrower());
00168 TestThrowingCtor<ThrowingVariant>(std::move(v));
00169 }
00170 {
00171 ThrowingVariant v(ExpectedThrowerVec());
00172 TestThrowingCtor<ThrowingVariant>(std::move(v));
00173 }
00174 {
00175 ThrowingVariant v(ValuelessByException());
00176 TestThrowingCtor<ThrowingVariant>(std::move(v));
00177 }
00178 }
00179
00180 TEST(VariantExceptionSafetyTest, ValueConstructor) {
00181 TestThrowingCtor<ThrowingVariant>(ExpectedThrower());
00182 TestThrowingCtor<ThrowingVariant>(ExpectedThrowerVec());
00183 }
00184
00185 TEST(VariantExceptionSafetyTest, InPlaceTypeConstructor) {
00186 TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<Thrower>{},
00187 ExpectedThrower());
00188 TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<ThrowerVec>{},
00189 ExpectedThrowerVec());
00190 }
00191
00192 TEST(VariantExceptionSafetyTest, InPlaceIndexConstructor) {
00193 TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<0>{},
00194 ExpectedThrower());
00195 TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<3>{},
00196 ExpectedThrowerVec());
00197 }
00198
00199 TEST(VariantExceptionSafetyTest, CopyAssign) {
00200
00201
00202 {
00203
00204 const ThrowingVariant rhs = ValuelessByException();
00205 ThrowingVariant lhs = ValuelessByException();
00206 EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
00207 }
00208 {
00209
00210 const ThrowingVariant rhs = ValuelessByException();
00211 ThrowingVariant lhs = WithThrower();
00212 EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
00213 }
00214
00215 {
00216 const ThrowingVariant rhs(ExpectedThrower());
00217 auto tester =
00218 MakeExceptionSafetyTester()
00219 .WithInitialValue(WithThrower())
00220 .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
00221 EXPECT_TRUE(tester.WithContracts(VariantInvariants).Test());
00222 EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
00223 }
00224 {
00225 const ThrowingVariant rhs(ExpectedThrowerVec());
00226 auto tester =
00227 MakeExceptionSafetyTester()
00228 .WithInitialValue(WithThrowerVec())
00229 .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
00230 EXPECT_TRUE(tester.WithContracts(VariantInvariants).Test());
00231 EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
00232 }
00233
00234
00235 #if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
00236
00237
00238
00239
00240 {
00241
00242
00243
00244 const ThrowingVariant rhs(CopyNothrow{});
00245 ThrowingVariant lhs = WithThrower();
00246 EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
00247 }
00248 {
00249
00250
00251
00252
00253 const ThrowingVariant rhs(ExpectedThrower());
00254 auto tester =
00255 MakeExceptionSafetyTester()
00256 .WithInitialValue(WithCopyNoThrow())
00257 .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
00258 EXPECT_TRUE(tester
00259 .WithContracts(VariantInvariants,
00260 [](ThrowingVariant* lhs) {
00261 return lhs->valueless_by_exception();
00262 })
00263 .Test());
00264 EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
00265 }
00266 #endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
00267 {
00268
00269
00270
00271
00272
00273 const ThrowingVariant rhs(MoveNothrow{});
00274 EXPECT_TRUE(MakeExceptionSafetyTester()
00275 .WithInitialValue(WithThrower())
00276 .WithContracts(VariantInvariants, strong_guarantee)
00277 .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
00278 }
00279 }
00280
00281 TEST(VariantExceptionSafetyTest, MoveAssign) {
00282
00283
00284 {
00285
00286 ThrowingVariant rhs = ValuelessByException();
00287 ThrowingVariant lhs = ValuelessByException();
00288 EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
00289 }
00290 {
00291
00292 ThrowingVariant rhs = ValuelessByException();
00293 ThrowingVariant lhs = WithThrower();
00294 EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
00295 }
00296 {
00297
00298
00299
00300
00301
00302 ThrowingVariant rhs(ExpectedThrower());
00303 size_t j = rhs.index();
00304
00305 auto tester = MakeExceptionSafetyTester()
00306 .WithInitialValue(WithThrower())
00307 .WithOperation([&](ThrowingVariant* lhs) {
00308 auto copy = rhs;
00309 *lhs = std::move(copy);
00310 });
00311 EXPECT_TRUE(tester
00312 .WithContracts(
00313 VariantInvariants,
00314 [&](ThrowingVariant* lhs) { return lhs->index() == j; })
00315 .Test());
00316 EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
00317 }
00318 {
00319
00320
00321
00322
00323 #if !(defined(ABSL_HAVE_STD_VARIANT) && \
00324 defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
00325
00326
00327
00328
00329 ThrowingVariant rhs(CopyNothrow{});
00330 EXPECT_TRUE(MakeExceptionSafetyTester()
00331 .WithInitialValue(WithThrower())
00332 .WithContracts(VariantInvariants,
00333 [](ThrowingVariant* lhs) {
00334 return lhs->valueless_by_exception();
00335 })
00336 .Test([&](ThrowingVariant* lhs) {
00337 auto copy = rhs;
00338 *lhs = std::move(copy);
00339 }));
00340 #endif // !(defined(ABSL_HAVE_STD_VARIANT) &&
00341
00342 }
00343 }
00344
00345 TEST(VariantExceptionSafetyTest, ValueAssign) {
00346
00347
00348 {
00349
00350
00351
00352
00353
00354
00355
00356 Thrower rhs = ExpectedThrower();
00357
00358 auto copy_tester =
00359 MakeExceptionSafetyTester()
00360 .WithInitialValue(WithThrower())
00361 .WithOperation([rhs](ThrowingVariant* lhs) { *lhs = rhs; });
00362 EXPECT_TRUE(copy_tester
00363 .WithContracts(VariantInvariants,
00364 [](ThrowingVariant* lhs) {
00365 return !lhs->valueless_by_exception();
00366 })
00367 .Test());
00368 EXPECT_FALSE(copy_tester.WithContracts(strong_guarantee).Test());
00369
00370 auto move_tester = MakeExceptionSafetyTester()
00371 .WithInitialValue(WithThrower())
00372 .WithOperation([&](ThrowingVariant* lhs) {
00373 auto copy = rhs;
00374 *lhs = std::move(copy);
00375 });
00376 EXPECT_TRUE(move_tester
00377 .WithContracts(VariantInvariants,
00378 [](ThrowingVariant* lhs) {
00379 return !lhs->valueless_by_exception();
00380 })
00381 .Test());
00382
00383 EXPECT_FALSE(move_tester.WithContracts(strong_guarantee).Test());
00384 }
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 {
00395 const CopyNothrow rhs;
00396 ThrowingVariant lhs = WithThrower();
00397 EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
00398 }
00399 {
00400 MoveNothrow rhs;
00401 ThrowingVariant lhs = WithThrower();
00402 EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
00403 }
00404
00405
00406
00407
00408 {
00409 Thrower rhs = ExpectedThrower();
00410
00411 auto copy_tester =
00412 MakeExceptionSafetyTester()
00413 .WithInitialValue(WithCopyNoThrow())
00414 .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
00415 EXPECT_TRUE(copy_tester
00416 .WithContracts(VariantInvariants,
00417 [](ThrowingVariant* lhs) {
00418 return lhs->valueless_by_exception();
00419 })
00420 .Test());
00421 EXPECT_FALSE(copy_tester.WithContracts(strong_guarantee).Test());
00422
00423 auto move_tester = MakeExceptionSafetyTester()
00424 .WithInitialValue(WithCopyNoThrow())
00425 .WithOperation([](ThrowingVariant* lhs) {
00426 *lhs = ExpectedThrower(testing::nothrow_ctor);
00427 });
00428 EXPECT_TRUE(move_tester
00429 .WithContracts(VariantInvariants,
00430 [](ThrowingVariant* lhs) {
00431 return lhs->valueless_by_exception();
00432 })
00433 .Test());
00434 EXPECT_FALSE(move_tester.WithContracts(strong_guarantee).Test());
00435 }
00436
00437
00438
00439
00440
00441
00442
00443 #if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
00444 {
00445 MoveNothrow rhs;
00446 EXPECT_TRUE(MakeExceptionSafetyTester()
00447 .WithInitialValue(WithThrower())
00448 .WithContracts(VariantInvariants, strong_guarantee)
00449 .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
00450 }
00451 #endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
00452 }
00453
00454 TEST(VariantExceptionSafetyTest, Emplace) {
00455
00456
00457
00458 {
00459 Thrower args = ExpectedThrower();
00460 auto tester = MakeExceptionSafetyTester()
00461 .WithInitialValue(WithThrower())
00462 .WithOperation([&args](ThrowingVariant* v) {
00463 v->emplace<Thrower>(args);
00464 });
00465 EXPECT_TRUE(tester
00466 .WithContracts(VariantInvariants,
00467 [](ThrowingVariant* v) {
00468 return v->valueless_by_exception();
00469 })
00470 .Test());
00471 EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
00472 }
00473 }
00474
00475 TEST(VariantExceptionSafetyTest, Swap) {
00476
00477 {
00478 ThrowingVariant rhs = ValuelessByException();
00479 ThrowingVariant lhs = ValuelessByException();
00480 EXPECT_TRUE(TestNothrowOp([&]() { lhs.swap(rhs); }));
00481 }
00482
00483
00484 {
00485 ThrowingVariant rhs = ExpectedThrower();
00486 EXPECT_TRUE(MakeExceptionSafetyTester()
00487 .WithInitialValue(WithThrower())
00488 .WithContracts(VariantInvariants)
00489 .Test([&](ThrowingVariant* lhs) {
00490 auto copy = rhs;
00491 lhs->swap(copy);
00492 }));
00493 }
00494
00495
00496
00497
00498 {
00499 ThrowingVariant rhs = ExpectedThrower();
00500 EXPECT_TRUE(MakeExceptionSafetyTester()
00501 .WithInitialValue(WithCopyNoThrow())
00502 .WithContracts(VariantInvariants)
00503 .Test([&](ThrowingVariant* lhs) {
00504 auto copy = rhs;
00505 lhs->swap(copy);
00506 }));
00507 }
00508 {
00509 ThrowingVariant rhs = ExpectedThrower();
00510 EXPECT_TRUE(MakeExceptionSafetyTester()
00511 .WithInitialValue(WithCopyNoThrow())
00512 .WithContracts(VariantInvariants)
00513 .Test([&](ThrowingVariant* lhs) {
00514 auto copy = rhs;
00515 copy.swap(*lhs);
00516 }));
00517 }
00518 }
00519
00520 }
00521 }
00522
00523 #endif // !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)