In-place construction for Try
[folly.git] / folly / test / TryTest.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/Try.h>
18
19 #include <glog/logging.h>
20
21 #include <folly/Memory.h>
22 #include <folly/Traits.h>
23 #include <folly/portability/GTest.h>
24
25 using namespace folly;
26
27 namespace {
28
29 class A {
30  public:
31   explicit A(int x) : x_(x) {}
32
33   int x() const {
34     return x_;
35   }
36  private:
37   int x_;
38 };
39 }
40
41 TEST(Try, basic) {
42   A a(5);
43   Try<A> t_a(std::move(a));
44
45   Try<Unit> t_void;
46
47   EXPECT_EQ(5, t_a.value().x());
48 }
49
50 TEST(Try, in_place) {
51   Try<A> t_a(in_place, 5);
52
53   EXPECT_EQ(5, t_a.value().x());
54 }
55
56 TEST(Try, in_place_nested) {
57   Try<Try<A>> t_t_a(in_place, in_place, 5);
58
59   EXPECT_EQ(5, t_t_a.value().value().x());
60 }
61
62 // Make sure we can copy Trys for copyable types
63 TEST(Try, copy) {
64   Try<int> t;
65   auto t2 = t;
66 }
67
68 // But don't choke on move-only types
69 TEST(Try, moveOnly) {
70   Try<std::unique_ptr<int>> t;
71   std::vector<Try<std::unique_ptr<int>>> v;
72   v.reserve(10);
73 }
74
75 TEST(Try, makeTryWith) {
76   auto func = []() {
77     return std::make_unique<int>(1);
78   };
79
80   auto result = makeTryWith(func);
81   EXPECT_TRUE(result.hasValue());
82   EXPECT_EQ(*result.value(), 1);
83 }
84
85 TEST(Try, makeTryWithThrow) {
86   auto func = []() -> std::unique_ptr<int> {
87     throw std::runtime_error("Runtime");
88   };
89
90   auto result = makeTryWith(func);
91   EXPECT_TRUE(result.hasException<std::runtime_error>());
92 }
93
94 TEST(Try, makeTryWithVoid) {
95   auto func = []() {
96     return;
97   };
98
99   auto result = makeTryWith(func);
100   EXPECT_TRUE(result.hasValue());
101 }
102
103 TEST(Try, makeTryWithVoidThrow) {
104   auto func = []() {
105     throw std::runtime_error("Runtime");
106   };
107
108   auto result = makeTryWith(func);
109   EXPECT_TRUE(result.hasException<std::runtime_error>());
110 }
111
112 template <typename E>
113 static E* get_exception(std::exception_ptr eptr) {
114   try {
115     std::rethrow_exception(eptr);
116   } catch (E& e) {
117     return &e;
118   } catch (...) {
119     return nullptr;
120   }
121 }
122
123 TEST(Try, tryGetExceptionObject) {
124   auto epexn = std::make_exception_ptr(std::range_error("oops"));
125   auto epnum = std::make_exception_ptr(17);
126
127   auto exn = CHECK_NOTNULL(get_exception<std::range_error>(epexn));
128   auto num = CHECK_NOTNULL(get_exception<int>(epnum));
129
130   {
131     auto t = Try<bool>(true);
132     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
133     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
134     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
135   }
136
137   {
138     auto t = Try<bool>(exception_wrapper(epexn, *exn));
139     EXPECT_EQ(exn, t.tryGetExceptionObject());
140     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
141     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
142   }
143
144   {
145     auto t = Try<bool>(exception_wrapper(epnum, *num));
146     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
147     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
148     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
149   }
150
151   {
152     auto t = Try<void>();
153     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
154     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
155     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
156   }
157
158   {
159     auto t = Try<void>(exception_wrapper(epexn, *exn));
160     EXPECT_EQ(exn, t.tryGetExceptionObject());
161     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
162     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
163   }
164
165   {
166     auto t = Try<void>(exception_wrapper(epnum, *num));
167     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
168     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
169     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
170   }
171
172   {
173     auto const t = Try<bool>(true);
174     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
175     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
176     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
177   }
178
179   {
180     auto const t = Try<bool>(exception_wrapper(epexn, *exn));
181     EXPECT_EQ(exn, t.tryGetExceptionObject());
182     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
183     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
184   }
185
186   {
187     auto const t = Try<bool>(exception_wrapper(epnum, *num));
188     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
189     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
190     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
191   }
192
193   {
194     auto const t = Try<void>();
195     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
196     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
197     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
198   }
199
200   {
201     auto const t = Try<void>(exception_wrapper(epexn, *exn));
202     EXPECT_EQ(exn, t.tryGetExceptionObject());
203     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
204     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
205   }
206
207   {
208     auto const t = Try<void>(exception_wrapper(epnum, *num));
209     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
210     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
211     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
212   }
213 }
214
215 TEST(Try, withException) {
216   auto ew = make_exception_wrapper<std::range_error>("oops");
217
218   {
219     auto t = Try<bool>(true);
220     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
221     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
222     EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
223     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
224   }
225
226   {
227     auto t = Try<bool>(ew);
228     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
229     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
230     EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
231     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
232   }
233
234   {
235     auto t = Try<void>();
236     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
237     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
238     EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
239     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
240   }
241
242   {
243     auto t = Try<void>(ew);
244     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
245     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
246     EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
247     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
248   }
249
250   {
251     auto const t = Try<bool>(true);
252     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
253     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
254     EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
255     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
256   }
257
258   {
259     auto const t = Try<bool>(ew);
260     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
261     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
262     EXPECT_TRUE(t.withException([](std::runtime_error const&) {}));
263     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
264   }
265
266   {
267     auto const t = Try<void>();
268     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
269     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
270     EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
271     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
272   }
273
274   {
275     auto const t = Try<void>(ew);
276     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
277     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
278     EXPECT_TRUE(t.withException([](std::runtime_error const&) {}));
279     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
280   }
281 }