Consistently have the namespace closing comment
[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 class MoveConstructOnly {
41  public:
42   MoveConstructOnly() = default;
43   MoveConstructOnly(const MoveConstructOnly&) = delete;
44   MoveConstructOnly(MoveConstructOnly&&) = default;
45 };
46
47 class MutableContainer {
48  public:
49   mutable MoveConstructOnly val;
50 };
51 } // namespace
52
53 TEST(Try, basic) {
54   A a(5);
55   Try<A> t_a(std::move(a));
56
57   Try<Unit> t_void;
58
59   EXPECT_EQ(5, t_a.value().x());
60 }
61
62 TEST(Try, in_place) {
63   Try<A> t_a(in_place, 5);
64
65   EXPECT_EQ(5, t_a.value().x());
66 }
67
68 TEST(Try, in_place_nested) {
69   Try<Try<A>> t_t_a(in_place, in_place, 5);
70
71   EXPECT_EQ(5, t_t_a.value().value().x());
72 }
73
74 TEST(Try, MoveDereference) {
75   auto ptr = std::make_unique<int>(1);
76   auto t = Try<std::unique_ptr<int>>{std::move(ptr)};
77   auto result = *std::move(t);
78   EXPECT_EQ(*result, 1);
79 }
80
81 TEST(Try, MoveConstRvalue) {
82   // tests to see if Try returns a const Rvalue, this is required in the case
83   // where for example MutableContainer has a mutable memebr that is move only
84   // and you want to fetch the value from the Try and move it into a member
85   {
86     const Try<MutableContainer> t{in_place};
87     auto val = MoveConstructOnly{std::move(t).value().val};
88     static_cast<void>(val);
89   }
90   {
91     const Try<MutableContainer> t{in_place};
92     auto val = (*(std::move(t))).val;
93     static_cast<void>(val);
94   }
95 }
96
97 TEST(Try, ValueOverloads) {
98   using ML = int&;
99   using MR = int&&;
100   using CL = const int&;
101   using CR = const int&&;
102
103   {
104     auto obj = Try<int>{};
105     using ActualML = decltype(obj.value());
106     using ActualMR = decltype(std::move(obj).value());
107     using ActualCL = decltype(as_const(obj).value());
108     using ActualCR = decltype(std::move(as_const(obj)).value());
109     EXPECT_TRUE((std::is_same<ML, ActualML>::value));
110     EXPECT_TRUE((std::is_same<MR, ActualMR>::value));
111     EXPECT_TRUE((std::is_same<CL, ActualCL>::value));
112     EXPECT_TRUE((std::is_same<CR, ActualCR>::value));
113   }
114
115   {
116     auto obj = Try<int>{3};
117     EXPECT_EQ(obj.value(), 3);
118     EXPECT_EQ(std::move(obj).value(), 3);
119     EXPECT_EQ(as_const(obj).value(), 3);
120     EXPECT_EQ(std::move(as_const(obj)).value(), 3);
121   }
122
123   {
124     auto obj = Try<int>{make_exception_wrapper<std::range_error>("oops")};
125     EXPECT_THROW(obj.value(), std::range_error);
126     EXPECT_THROW(std::move(obj.value()), std::range_error);
127     EXPECT_THROW(as_const(obj.value()), std::range_error);
128     EXPECT_THROW(std::move(as_const(obj.value())), std::range_error);
129   }
130 }
131
132 // Make sure we can copy Trys for copyable types
133 TEST(Try, copy) {
134   Try<int> t;
135   auto t2 = t;
136 }
137
138 // But don't choke on move-only types
139 TEST(Try, moveOnly) {
140   Try<std::unique_ptr<int>> t;
141   std::vector<Try<std::unique_ptr<int>>> v;
142   v.reserve(10);
143 }
144
145 TEST(Try, makeTryWith) {
146   auto func = []() {
147     return std::make_unique<int>(1);
148   };
149
150   auto result = makeTryWith(func);
151   EXPECT_TRUE(result.hasValue());
152   EXPECT_EQ(*result.value(), 1);
153 }
154
155 TEST(Try, makeTryWithThrow) {
156   auto func = []() -> std::unique_ptr<int> {
157     throw std::runtime_error("Runtime");
158   };
159
160   auto result = makeTryWith(func);
161   EXPECT_TRUE(result.hasException<std::runtime_error>());
162 }
163
164 TEST(Try, makeTryWithVoid) {
165   auto func = []() {
166     return;
167   };
168
169   auto result = makeTryWith(func);
170   EXPECT_TRUE(result.hasValue());
171 }
172
173 TEST(Try, makeTryWithVoidThrow) {
174   auto func = []() {
175     throw std::runtime_error("Runtime");
176   };
177
178   auto result = makeTryWith(func);
179   EXPECT_TRUE(result.hasException<std::runtime_error>());
180 }
181
182 TEST(Try, exception) {
183   using ML = exception_wrapper&;
184   using MR = exception_wrapper&&;
185   using CL = exception_wrapper const&;
186   using CR = exception_wrapper const&&;
187
188   {
189     auto obj = Try<int>();
190     using ActualML = decltype(obj.exception());
191     using ActualMR = decltype(std::move(obj).exception());
192     using ActualCL = decltype(as_const(obj).exception());
193     using ActualCR = decltype(std::move(as_const(obj)).exception());
194     EXPECT_TRUE((std::is_same<ML, ActualML>::value));
195     EXPECT_TRUE((std::is_same<MR, ActualMR>::value));
196     EXPECT_TRUE((std::is_same<CL, ActualCL>::value));
197     EXPECT_TRUE((std::is_same<CR, ActualCR>::value));
198   }
199
200   {
201     auto obj = Try<int>(3);
202     EXPECT_THROW(obj.exception(), TryException);
203     EXPECT_THROW(std::move(obj).exception(), TryException);
204     EXPECT_THROW(as_const(obj).exception(), TryException);
205     EXPECT_THROW(std::move(as_const(obj)).exception(), TryException);
206   }
207
208   {
209     auto obj = Try<int>(make_exception_wrapper<int>(-3));
210     EXPECT_EQ(-3, *obj.exception().get_exception<int>());
211     EXPECT_EQ(-3, *std::move(obj).exception().get_exception<int>());
212     EXPECT_EQ(-3, *as_const(obj).exception().get_exception<int>());
213     EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception<int>());
214   }
215
216   {
217     auto obj = Try<void>();
218     using ActualML = decltype(obj.exception());
219     using ActualMR = decltype(std::move(obj).exception());
220     using ActualCL = decltype(as_const(obj).exception());
221     using ActualCR = decltype(std::move(as_const(obj)).exception());
222     EXPECT_TRUE((std::is_same<ML, ActualML>::value));
223     EXPECT_TRUE((std::is_same<MR, ActualMR>::value));
224     EXPECT_TRUE((std::is_same<CL, ActualCL>::value));
225     EXPECT_TRUE((std::is_same<CR, ActualCR>::value));
226   }
227
228   {
229     auto obj = Try<void>();
230     EXPECT_THROW(obj.exception(), TryException);
231     EXPECT_THROW(std::move(obj).exception(), TryException);
232     EXPECT_THROW(as_const(obj).exception(), TryException);
233     EXPECT_THROW(std::move(as_const(obj)).exception(), TryException);
234   }
235
236   {
237     auto obj = Try<void>(make_exception_wrapper<int>(-3));
238     EXPECT_EQ(-3, *obj.exception().get_exception<int>());
239     EXPECT_EQ(-3, *std::move(obj).exception().get_exception<int>());
240     EXPECT_EQ(-3, *as_const(obj).exception().get_exception<int>());
241     EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception<int>());
242   }
243 }
244
245 template <typename E>
246 static E* get_exception(std::exception_ptr eptr) {
247   try {
248     std::rethrow_exception(eptr);
249   } catch (E& e) {
250     return &e;
251   } catch (...) {
252     return nullptr;
253   }
254 }
255
256 TEST(Try, tryGetExceptionObject) {
257   auto epexn = std::make_exception_ptr(std::range_error("oops"));
258   auto epnum = std::make_exception_ptr(17);
259
260   auto exn = CHECK_NOTNULL(get_exception<std::range_error>(epexn));
261   auto num = CHECK_NOTNULL(get_exception<int>(epnum));
262
263   {
264     auto t = Try<bool>(true);
265     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
266     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
267     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
268   }
269
270   {
271     auto t = Try<bool>(exception_wrapper(epexn, *exn));
272     EXPECT_EQ(exn, t.tryGetExceptionObject());
273     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
274     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
275   }
276
277   {
278     auto t = Try<bool>(exception_wrapper(epnum, *num));
279     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
280     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
281     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
282   }
283
284   {
285     auto t = Try<void>();
286     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
287     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
288     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
289   }
290
291   {
292     auto t = Try<void>(exception_wrapper(epexn, *exn));
293     EXPECT_EQ(exn, t.tryGetExceptionObject());
294     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
295     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
296   }
297
298   {
299     auto t = Try<void>(exception_wrapper(epnum, *num));
300     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
301     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
302     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
303   }
304
305   {
306     auto const t = Try<bool>(true);
307     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
308     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
309     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
310   }
311
312   {
313     auto const t = Try<bool>(exception_wrapper(epexn, *exn));
314     EXPECT_EQ(exn, t.tryGetExceptionObject());
315     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
316     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
317   }
318
319   {
320     auto const t = Try<bool>(exception_wrapper(epnum, *num));
321     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
322     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
323     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
324   }
325
326   {
327     auto const t = Try<void>();
328     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
329     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
330     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
331   }
332
333   {
334     auto const t = Try<void>(exception_wrapper(epexn, *exn));
335     EXPECT_EQ(exn, t.tryGetExceptionObject());
336     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
337     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
338   }
339
340   {
341     auto const t = Try<void>(exception_wrapper(epnum, *num));
342     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
343     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
344     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
345   }
346 }
347
348 TEST(Try, withException) {
349   auto ew = make_exception_wrapper<std::range_error>("oops");
350
351   {
352     auto t = Try<bool>(true);
353     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
354     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
355     EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
356     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
357   }
358
359   {
360     auto t = Try<bool>(ew);
361     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
362     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
363     EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
364     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
365   }
366
367   {
368     auto t = Try<void>();
369     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
370     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
371     EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
372     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
373   }
374
375   {
376     auto t = Try<void>(ew);
377     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
378     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
379     EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
380     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
381   }
382
383   {
384     auto const t = Try<bool>(true);
385     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
386     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
387     EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
388     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
389   }
390
391   {
392     auto const t = Try<bool>(ew);
393     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
394     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
395     EXPECT_TRUE(t.withException([](std::runtime_error const&) {}));
396     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
397   }
398
399   {
400     auto const t = Try<void>();
401     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
402     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
403     EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
404     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
405   }
406
407   {
408     auto const t = Try<void>(ew);
409     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
410     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
411     EXPECT_TRUE(t.withException([](std::runtime_error const&) {}));
412     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
413   }
414 }
415
416 TEST(Try, TestUnwrapTuple) {
417   auto original = std::make_tuple(Try<int>{1}, Try<int>{2});
418   EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(original));
419   EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(folly::copy(original)));
420   EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(folly::as_const(original)));
421 }
422
423 TEST(Try, TestUnwrapPair) {
424   auto original = std::make_pair(Try<int>{1}, Try<int>{2});
425   EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(original));
426   EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(folly::copy(original)));
427   EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(folly::as_const(original)));
428 }
429
430 TEST(Try, TestUnwrapForward) {
431   using UPtr_t = std::unique_ptr<int>;
432   auto original = std::make_tuple(Try<UPtr_t>{std::make_unique<int>(1)});
433   auto unwrapped = unwrapTryTuple(std::move(original));
434   EXPECT_EQ(*std::get<0>(unwrapped), 1);
435 }