aboutsummaryrefslogtreecommitdiffhomepage
path: root/absl/types/any_exception_safety_test.cc
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2018-01-05 07:54:33 -0800
committerGravatar Derek Mauro <dmauro@google.com>2018-01-08 10:38:50 -0500
commit4132ce25956a91e1224e0f205b7f8c326304a995 (patch)
tree724485e8778f91d865db86af663af9e7be3293db /absl/types/any_exception_safety_test.cc
parent0271cd35577599fa99b59202da17d3136956e4c0 (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.cc201
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 0000000..eadba30
--- /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