8e675f1f7738d7b6d3945759009c8a1870aa811c
[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 TEST(Try, exception) {
113   using ML = exception_wrapper&;
114   using MR = exception_wrapper&&;
115   using CL = exception_wrapper const&;
116   using CR = exception_wrapper const&&;
117
118   {
119     auto obj = Try<int>();
120     using ActualML = decltype(obj.exception());
121     using ActualMR = decltype(std::move(obj).exception());
122     using ActualCL = decltype(as_const(obj).exception());
123     using ActualCR = decltype(std::move(as_const(obj)).exception());
124     EXPECT_TRUE((std::is_same<ML, ActualML>::value));
125     EXPECT_TRUE((std::is_same<MR, ActualMR>::value));
126     EXPECT_TRUE((std::is_same<CL, ActualCL>::value));
127     EXPECT_TRUE((std::is_same<CR, ActualCR>::value));
128   }
129
130   {
131     auto obj = Try<int>(3);
132     EXPECT_THROW(obj.exception(), TryException);
133     EXPECT_THROW(std::move(obj).exception(), TryException);
134     EXPECT_THROW(as_const(obj).exception(), TryException);
135     EXPECT_THROW(std::move(as_const(obj)).exception(), TryException);
136   }
137
138   {
139     auto obj = Try<int>(make_exception_wrapper<int>(-3));
140     EXPECT_EQ(-3, *obj.exception().get_exception<int>());
141     EXPECT_EQ(-3, *std::move(obj).exception().get_exception<int>());
142     EXPECT_EQ(-3, *as_const(obj).exception().get_exception<int>());
143     EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception<int>());
144   }
145
146   {
147     auto obj = Try<void>();
148     using ActualML = decltype(obj.exception());
149     using ActualMR = decltype(std::move(obj).exception());
150     using ActualCL = decltype(as_const(obj).exception());
151     using ActualCR = decltype(std::move(as_const(obj)).exception());
152     EXPECT_TRUE((std::is_same<ML, ActualML>::value));
153     EXPECT_TRUE((std::is_same<MR, ActualMR>::value));
154     EXPECT_TRUE((std::is_same<CL, ActualCL>::value));
155     EXPECT_TRUE((std::is_same<CR, ActualCR>::value));
156   }
157
158   {
159     auto obj = Try<void>();
160     EXPECT_THROW(obj.exception(), TryException);
161     EXPECT_THROW(std::move(obj).exception(), TryException);
162     EXPECT_THROW(as_const(obj).exception(), TryException);
163     EXPECT_THROW(std::move(as_const(obj)).exception(), TryException);
164   }
165
166   {
167     auto obj = Try<void>(make_exception_wrapper<int>(-3));
168     EXPECT_EQ(-3, *obj.exception().get_exception<int>());
169     EXPECT_EQ(-3, *std::move(obj).exception().get_exception<int>());
170     EXPECT_EQ(-3, *as_const(obj).exception().get_exception<int>());
171     EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception<int>());
172   }
173 }
174
175 template <typename E>
176 static E* get_exception(std::exception_ptr eptr) {
177   try {
178     std::rethrow_exception(eptr);
179   } catch (E& e) {
180     return &e;
181   } catch (...) {
182     return nullptr;
183   }
184 }
185
186 TEST(Try, tryGetExceptionObject) {
187   auto epexn = std::make_exception_ptr(std::range_error("oops"));
188   auto epnum = std::make_exception_ptr(17);
189
190   auto exn = CHECK_NOTNULL(get_exception<std::range_error>(epexn));
191   auto num = CHECK_NOTNULL(get_exception<int>(epnum));
192
193   {
194     auto t = Try<bool>(true);
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 t = Try<bool>(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 t = Try<bool>(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     auto t = Try<void>();
216     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
217     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
218     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
219   }
220
221   {
222     auto t = Try<void>(exception_wrapper(epexn, *exn));
223     EXPECT_EQ(exn, t.tryGetExceptionObject());
224     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
225     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
226   }
227
228   {
229     auto t = Try<void>(exception_wrapper(epnum, *num));
230     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
231     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
232     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
233   }
234
235   {
236     auto const t = Try<bool>(true);
237     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
238     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
239     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
240   }
241
242   {
243     auto const t = Try<bool>(exception_wrapper(epexn, *exn));
244     EXPECT_EQ(exn, t.tryGetExceptionObject());
245     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
246     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
247   }
248
249   {
250     auto const t = Try<bool>(exception_wrapper(epnum, *num));
251     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
252     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
253     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
254   }
255
256   {
257     auto const t = Try<void>();
258     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
259     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
260     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
261   }
262
263   {
264     auto const t = Try<void>(exception_wrapper(epexn, *exn));
265     EXPECT_EQ(exn, t.tryGetExceptionObject());
266     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
267     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
268   }
269
270   {
271     auto const t = Try<void>(exception_wrapper(epnum, *num));
272     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
273     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
274     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
275   }
276 }
277
278 TEST(Try, withException) {
279   auto ew = make_exception_wrapper<std::range_error>("oops");
280
281   {
282     auto t = Try<bool>(true);
283     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
284     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
285     EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
286     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
287   }
288
289   {
290     auto t = Try<bool>(ew);
291     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
292     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
293     EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
294     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
295   }
296
297   {
298     auto t = Try<void>();
299     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
300     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
301     EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
302     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
303   }
304
305   {
306     auto t = Try<void>(ew);
307     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
308     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
309     EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
310     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
311   }
312
313   {
314     auto const t = Try<bool>(true);
315     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
316     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
317     EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
318     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
319   }
320
321   {
322     auto const t = Try<bool>(ew);
323     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
324     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
325     EXPECT_TRUE(t.withException([](std::runtime_error const&) {}));
326     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
327   }
328
329   {
330     auto const t = Try<void>();
331     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
332     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
333     EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
334     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
335   }
336
337   {
338     auto const t = Try<void>(ew);
339     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
340     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
341     EXPECT_TRUE(t.withException([](std::runtime_error const&) {}));
342     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
343   }
344 }
345
346 TEST(Try, TestUnwrapTuple) {
347   auto original = std::make_tuple(Try<int>{1}, Try<int>{2});
348   EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(original));
349   EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(folly::copy(original)));
350   EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(folly::as_const(original)));
351 }
352
353 TEST(Try, TestUnwrapPair) {
354   auto original = std::make_pair(Try<int>{1}, Try<int>{2});
355   EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(original));
356   EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(folly::copy(original)));
357   EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(folly::as_const(original)));
358 }
359
360 TEST(Try, TestUnwrapForward) {
361   using UPtr_t = std::unique_ptr<int>;
362   auto original = std::make_tuple(Try<UPtr_t>{std::make_unique<int>(1)});
363   auto unwrapped = unwrapTryTuple(std::move(original));
364   EXPECT_EQ(*std::get<0>(unwrapped), 1);
365 }