diff options
author | Abseil Team <absl-team@google.com> | 2018-01-05T15·54-0800 |
---|---|---|
committer | Derek Mauro <dmauro@google.com> | 2018-01-08T15·38-0500 |
commit | 4132ce25956a91e1224e0f205b7f8c326304a995 (patch) | |
tree | 724485e8778f91d865db86af663af9e7be3293db /absl/types/any_exception_safety_test.cc | |
parent | 0271cd35577599fa99b59202da17d3136956e4c0 (diff) |
Changes imported from Abseil "staging" branch:
- 0a519d9a4507158267cc515e0c7c83959d94fc78 Fix missing header include when compiling with _GLIBCXX_D... by Alex Strelnikov <strel@google.com> - d089af70781d92af9a5de2d84c417ddf2c87689a Internal change by Gennadiy Rozental <rogeeff@google.com> - 0d3afc89d3907923ede964d58c6bcca579e8ad65 Test absl::any for exception safety. This test is tempor... by Jon Cohen <cohenjon@google.com> - 29af424b8a3174a7b3e657e478aa30a8a425aee2 Tweak the ABSL type trait library and expand its tests. by Abseil Team <absl-team@google.com> - 99ab42b2ebbe466cc3730fb6b16b5fad848f95af Rollback GLIBCXX_DEBUG fix due to internal breakage. by Alex Strelnikov <strel@google.com> - 1a5bcb93ee16d4dd2170254e54c4b62b38fbf17b Internal change. by Abseil Team <absl-team@google.com> - 46de7d09c7d4aef5b7b5389ce9b4f96b654aac02 absl::string_view::rfind: doc fix. by Abseil Team <absl-team@google.com> - edda4c7ddd2d76fbb5b3fd5226b95082083c57d9 Fix string_view_test with c++17/clang/libc++ to address by Xiaoyi Zhang <zhangxy@google.com> GitOrigin-RevId: 0a519d9a4507158267cc515e0c7c83959d94fc78 Change-Id: Ie27de1be3e79bba011f05e924d34e8fcc62d8de5
Diffstat (limited to 'absl/types/any_exception_safety_test.cc')
-rw-r--r-- | absl/types/any_exception_safety_test.cc | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/absl/types/any_exception_safety_test.cc b/absl/types/any_exception_safety_test.cc new file mode 100644 index 000000000000..eadba3080437 --- /dev/null +++ b/absl/types/any_exception_safety_test.cc @@ -0,0 +1,201 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/types/any.h" + +#include <typeinfo> +#include <vector> + +#include "gtest/gtest.h" +#include "absl/base/internal/exception_safety_testing.h" + +using Thrower = absl::ThrowingValue<>; +using ThrowerList = std::initializer_list<Thrower>; +using ThrowerVec = std::vector<Thrower>; +using ThrowingAlloc = absl::ThrowingAllocator<Thrower>; +using ThrowingThrowerVec = std::vector<Thrower, ThrowingAlloc>; + +namespace absl { + +testing::AssertionResult AbslCheckInvariants(absl::any* a, + InternalAbslNamespaceFinder) { + using testing::AssertionFailure; + using testing::AssertionSuccess; + + if (a->has_value()) { + if (a->type() == typeid(void)) { + return AssertionFailure() + << "A non-empty any should not have type `void`"; + } + } else { + if (a->type() != typeid(void)) { + return AssertionFailure() + << "An empty any should have type void, but has type " + << a->type().name(); + } + } + + // Make sure that reset() changes any to a valid state. + a->reset(); + if (a->has_value()) { + return AssertionFailure() << "A reset `any` should be valueless"; + } + if (a->type() != typeid(void)) { + return AssertionFailure() << "A reset `any` should have type() of `void`, " + "but instead has type " + << a->type().name(); + } + try { + auto unused = absl::any_cast<Thrower>(*a); + static_cast<void>(unused); + return AssertionFailure() + << "A reset `any` should not be able to be any_cast"; + } catch (absl::bad_any_cast) { + } catch (...) { + return AssertionFailure() + << "Unexpected exception thrown from absl::any_cast"; + } + return AssertionSuccess(); +} + +} // namespace absl + +namespace { + +class AnyExceptionSafety : public ::testing::Test { + private: + absl::AllocInspector inspector_; +}; + +testing::AssertionResult AnyIsEmpty(absl::any* a) { + if (!a->has_value()) return testing::AssertionSuccess(); + return testing::AssertionFailure() + << "a should be empty, but instead has value " + << absl::any_cast<Thrower>(*a).Get(); +} + +TEST_F(AnyExceptionSafety, Ctors) { + Thrower val(1); + auto with_val = absl::TestThrowingCtor<absl::any>(val); + auto copy = absl::TestThrowingCtor<absl::any>(with_val); + auto in_place = + absl::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1); + auto in_place_list = absl::TestThrowingCtor<absl::any>( + absl::in_place_type_t<ThrowerVec>(), ThrowerList{val}); + auto in_place_list_again = + absl::TestThrowingCtor<absl::any, + absl::in_place_type_t<ThrowingThrowerVec>, + ThrowerList, ThrowingAlloc>( + absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc()); +} + +struct OneFactory { + std::unique_ptr<absl::any> operator()() const { + return absl::make_unique<absl::any>(absl::in_place_type_t<Thrower>(), 1, + absl::no_throw_ctor); + } +}; + +struct EmptyFactory { + std::unique_ptr<absl::any> operator()() const { + return absl::make_unique<absl::any>(); + } +}; + +TEST_F(AnyExceptionSafety, Assignment) { + auto thrower_comp = [](const absl::any& l, const absl::any& r) { + return absl::any_cast<Thrower>(l) == absl::any_cast<Thrower>(r); + }; + + OneFactory one_factory; + + absl::ThrowingValue<absl::NoThrow::kMoveCtor | absl::NoThrow::kMoveAssign> + moveable_val(2); + Thrower val(2); + absl::any any_val(val); + + EXPECT_TRUE(absl::TestExceptionSafety( + one_factory, [&any_val](absl::any* ap) { *ap = any_val; }, + absl::StrongGuarantee(one_factory, thrower_comp))); + + EXPECT_TRUE(absl::TestExceptionSafety( + one_factory, [&val](absl::any* ap) { *ap = val; }, + absl::StrongGuarantee(one_factory, thrower_comp))); + + EXPECT_TRUE(absl::TestExceptionSafety( + one_factory, [&val](absl::any* ap) { *ap = std::move(val); }, + absl::StrongGuarantee(one_factory, thrower_comp))); + + EXPECT_TRUE(absl::TestExceptionSafety( + one_factory, + [&moveable_val](absl::any* ap) { *ap = std::move(moveable_val); }, + absl::StrongGuarantee(one_factory, thrower_comp))); + + EmptyFactory empty_factory; + auto empty_comp = [](const absl::any& l, const absl::any& r) { + return !(l.has_value() || r.has_value()); + }; + + EXPECT_TRUE(absl::TestExceptionSafety( + empty_factory, [&any_val](absl::any* ap) { *ap = any_val; }, + absl::StrongGuarantee(empty_factory, empty_comp))); + + EXPECT_TRUE(absl::TestExceptionSafety( + empty_factory, [&val](absl::any* ap) { *ap = val; }, + absl::StrongGuarantee(empty_factory, empty_comp))); + + EXPECT_TRUE(absl::TestExceptionSafety( + empty_factory, [&val](absl::any* ap) { *ap = std::move(val); }, + absl::StrongGuarantee(empty_factory, empty_comp))); +} +// libstdc++ std::any fails this test +#if !defined(ABSL_HAVE_STD_ANY) +TEST_F(AnyExceptionSafety, Emplace) { + OneFactory one_factory; + + EXPECT_TRUE(absl::TestExceptionSafety( + one_factory, [](absl::any* ap) { ap->emplace<Thrower>(2); }, AnyIsEmpty)); + + EXPECT_TRUE(absl::TestExceptionSafety( + one_factory, + [](absl::any* ap) { + ap->emplace<absl::ThrowingValue<absl::NoThrow::kMoveCtor | + absl::NoThrow::kMoveAssign>>(2); + }, + AnyIsEmpty)); + + EXPECT_TRUE(absl::TestExceptionSafety(one_factory, + [](absl::any* ap) { + std::initializer_list<Thrower> il{ + Thrower(2, absl::no_throw_ctor)}; + ap->emplace<ThrowerVec>(il); + }, + AnyIsEmpty)); + + EmptyFactory empty_factory; + EXPECT_TRUE(absl::TestExceptionSafety( + empty_factory, [](absl::any* ap) { ap->emplace<Thrower>(2); }, + AnyIsEmpty)); + + EXPECT_TRUE(absl::TestExceptionSafety(empty_factory, + [](absl::any* ap) { + std::initializer_list<Thrower> il{ + Thrower(2, absl::no_throw_ctor)}; + ap->emplace<ThrowerVec>(il); + }, + AnyIsEmpty)); +} +#endif // ABSL_HAVE_STD_ANY + +} // namespace |