2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/Try.h>
19 #include <glog/logging.h>
21 #include <folly/Memory.h>
22 #include <folly/Traits.h>
23 #include <folly/portability/GTest.h>
25 using namespace folly;
31 explicit A(int x) : x_(x) {}
40 class MoveConstructOnly {
42 MoveConstructOnly() = default;
43 MoveConstructOnly(const MoveConstructOnly&) = delete;
44 MoveConstructOnly(MoveConstructOnly&&) = default;
47 class MutableContainer {
49 mutable MoveConstructOnly val;
55 Try<A> t_a(std::move(a));
59 EXPECT_EQ(5, t_a.value().x());
63 Try<A> t_a(in_place, 5);
65 EXPECT_EQ(5, t_a.value().x());
68 TEST(Try, in_place_nested) {
69 Try<Try<A>> t_t_a(in_place, in_place, 5);
71 EXPECT_EQ(5, t_t_a.value().value().x());
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);
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
86 const Try<MutableContainer> t{in_place};
87 auto val = MoveConstructOnly{std::move(t).value().val};
88 static_cast<void>(val);
91 const Try<MutableContainer> t{in_place};
92 auto val = (*(std::move(t))).val;
93 static_cast<void>(val);
97 TEST(Try, ValueOverloads) {
100 using CL = const int&;
101 using CR = const int&&;
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));
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);
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);
132 // Make sure we can copy Trys for copyable types
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;
145 TEST(Try, makeTryWith) {
147 return std::make_unique<int>(1);
150 auto result = makeTryWith(func);
151 EXPECT_TRUE(result.hasValue());
152 EXPECT_EQ(*result.value(), 1);
155 TEST(Try, makeTryWithThrow) {
156 auto func = []() -> std::unique_ptr<int> {
157 throw std::runtime_error("Runtime");
160 auto result = makeTryWith(func);
161 EXPECT_TRUE(result.hasException<std::runtime_error>());
164 TEST(Try, makeTryWithVoid) {
169 auto result = makeTryWith(func);
170 EXPECT_TRUE(result.hasValue());
173 TEST(Try, makeTryWithVoidThrow) {
175 throw std::runtime_error("Runtime");
178 auto result = makeTryWith(func);
179 EXPECT_TRUE(result.hasException<std::runtime_error>());
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&&;
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));
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);
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>());
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));
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);
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>());
245 template <typename E>
246 static E* get_exception(std::exception_ptr eptr) {
248 std::rethrow_exception(eptr);
256 TEST(Try, tryGetExceptionObject) {
257 auto epexn = std::make_exception_ptr(std::range_error("oops"));
258 auto epnum = std::make_exception_ptr(17);
260 auto exn = CHECK_NOTNULL(get_exception<std::range_error>(epexn));
261 auto num = CHECK_NOTNULL(get_exception<int>(epnum));
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>());
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>());
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>());
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>());
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>());
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>());
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>());
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>());
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>());
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>());
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>());
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>());
348 TEST(Try, withException) {
349 auto ew = make_exception_wrapper<std::range_error>("oops");
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&) {}));
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&) {}));
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&) {}));
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&) {}));
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&) {}));
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&) {}));
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&) {}));
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&) {}));
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)));
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)));
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);