• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/types/any.h"
16 
17 #include "absl/base/config.h"
18 
19 // This test is a no-op when absl::any is an alias for std::any and when
20 // exceptions are not enabled.
21 #if !defined(ABSL_USES_STD_ANY) && defined(ABSL_HAVE_EXCEPTIONS)
22 
23 #include <typeinfo>
24 #include <vector>
25 
26 #include "gtest/gtest.h"
27 #include "absl/base/internal/exception_safety_testing.h"
28 
29 using Thrower = testing::ThrowingValue<>;
30 using NoThrowMoveThrower =
31     testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
32 using ThrowerList = std::initializer_list<Thrower>;
33 using ThrowerVec = std::vector<Thrower>;
34 using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
35 using ThrowingThrowerVec = std::vector<Thrower, ThrowingAlloc>;
36 
37 namespace {
38 
AnyInvariants(absl::any * a)39 testing::AssertionResult AnyInvariants(absl::any* a) {
40   using testing::AssertionFailure;
41   using testing::AssertionSuccess;
42 
43   if (a->has_value()) {
44     if (a->type() == typeid(void)) {
45       return AssertionFailure()
46              << "A non-empty any should not have type `void`";
47     }
48   } else {
49     if (a->type() != typeid(void)) {
50       return AssertionFailure()
51              << "An empty any should have type void, but has type "
52              << a->type().name();
53     }
54   }
55 
56   //  Make sure that reset() changes any to a valid state.
57   a->reset();
58   if (a->has_value()) {
59     return AssertionFailure() << "A reset `any` should be valueless";
60   }
61   if (a->type() != typeid(void)) {
62     return AssertionFailure() << "A reset `any` should have type() of `void`, "
63                                  "but instead has type "
64                               << a->type().name();
65   }
66   try {
67     auto unused = absl::any_cast<Thrower>(*a);
68     static_cast<void>(unused);
69     return AssertionFailure()
70            << "A reset `any` should not be able to be any_cast";
71   } catch (const absl::bad_any_cast&) {
72   } catch (...) {
73     return AssertionFailure()
74            << "Unexpected exception thrown from absl::any_cast";
75   }
76   return AssertionSuccess();
77 }
78 
AnyIsEmpty(absl::any * a)79 testing::AssertionResult AnyIsEmpty(absl::any* a) {
80   if (!a->has_value()) {
81     return testing::AssertionSuccess();
82   }
83   return testing::AssertionFailure()
84          << "a should be empty, but instead has value "
85          << absl::any_cast<Thrower>(*a).Get();
86 }
87 
TEST(AnyExceptionSafety,Ctors)88 TEST(AnyExceptionSafety, Ctors) {
89   Thrower val(1);
90   testing::TestThrowingCtor<absl::any>(val);
91 
92   Thrower copy(val);
93   testing::TestThrowingCtor<absl::any>(copy);
94 
95   testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1);
96 
97   testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<ThrowerVec>(),
98                                        ThrowerList{val});
99 
100   testing::TestThrowingCtor<absl::any,
101                             absl::in_place_type_t<ThrowingThrowerVec>,
102                             ThrowerList, ThrowingAlloc>(
103       absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc());
104 }
105 
TEST(AnyExceptionSafety,Assignment)106 TEST(AnyExceptionSafety, Assignment) {
107   auto original =
108       absl::any(absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor);
109   auto any_is_strong = [original](absl::any* ap) {
110     return testing::AssertionResult(ap->has_value() &&
111                                     absl::any_cast<Thrower>(original) ==
112                                         absl::any_cast<Thrower>(*ap));
113   };
114   auto any_strong_tester = testing::MakeExceptionSafetyTester()
115                                .WithInitialValue(original)
116                                .WithContracts(AnyInvariants, any_is_strong);
117 
118   Thrower val(2);
119   absl::any any_val(val);
120   NoThrowMoveThrower mv_val(2);
121 
122   auto assign_any = [&any_val](absl::any* ap) { *ap = any_val; };
123   auto assign_val = [&val](absl::any* ap) { *ap = val; };
124   auto move = [&val](absl::any* ap) { *ap = std::move(val); };
125   auto move_movable = [&mv_val](absl::any* ap) { *ap = std::move(mv_val); };
126 
127   EXPECT_TRUE(any_strong_tester.Test(assign_any));
128   EXPECT_TRUE(any_strong_tester.Test(assign_val));
129   EXPECT_TRUE(any_strong_tester.Test(move));
130   EXPECT_TRUE(any_strong_tester.Test(move_movable));
131 
132   auto empty_any_is_strong = [](absl::any* ap) {
133     return testing::AssertionResult{!ap->has_value()};
134   };
135   auto strong_empty_any_tester =
136       testing::MakeExceptionSafetyTester()
137           .WithInitialValue(absl::any{})
138           .WithContracts(AnyInvariants, empty_any_is_strong);
139 
140   EXPECT_TRUE(strong_empty_any_tester.Test(assign_any));
141   EXPECT_TRUE(strong_empty_any_tester.Test(assign_val));
142   EXPECT_TRUE(strong_empty_any_tester.Test(move));
143 }
144 
TEST(AnyExceptionSafety,Emplace)145 TEST(AnyExceptionSafety, Emplace) {
146   auto initial_val =
147       absl::any{absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor};
148   auto one_tester = testing::MakeExceptionSafetyTester()
149                         .WithInitialValue(initial_val)
150                         .WithContracts(AnyInvariants, AnyIsEmpty);
151 
152   auto emp_thrower = [](absl::any* ap) { ap->emplace<Thrower>(2); };
153   auto emp_throwervec = [](absl::any* ap) {
154     std::initializer_list<Thrower> il{Thrower(2, testing::nothrow_ctor)};
155     ap->emplace<ThrowerVec>(il);
156   };
157   auto emp_movethrower = [](absl::any* ap) {
158     ap->emplace<NoThrowMoveThrower>(2);
159   };
160 
161   EXPECT_TRUE(one_tester.Test(emp_thrower));
162   EXPECT_TRUE(one_tester.Test(emp_throwervec));
163   EXPECT_TRUE(one_tester.Test(emp_movethrower));
164 
165   auto empty_tester = one_tester.WithInitialValue(absl::any{});
166 
167   EXPECT_TRUE(empty_tester.Test(emp_thrower));
168   EXPECT_TRUE(empty_tester.Test(emp_throwervec));
169 }
170 
171 }  // namespace
172 
173 #endif  // #if !defined(ABSL_USES_STD_ANY) && defined(ABSL_HAVE_EXCEPTIONS)
174