X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ftest%2FTryTest.cpp;h=45f1dec9523985804b9b17f8a8ad04c3aa2dca28;hb=7bf1486094cccb266e789a378d8e5f91e3cb7780;hp=e9b600a35b3c7fe27a1637e8233e5a91b7a04fc1;hpb=6a6ac91e1fda65d7871390f03be8d19b3591ba45;p=folly.git diff --git a/folly/test/TryTest.cpp b/folly/test/TryTest.cpp index e9b600a3..45f1dec9 100644 --- a/folly/test/TryTest.cpp +++ b/folly/test/TryTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,24 +14,43 @@ * limitations under the License. */ -#include #include + +#include + +#include +#include #include using namespace folly; -TEST(Try, basic) { - class A { - public: - A(int x) : x_(x) {} - - int x() const { - return x_; - } - private: - int x_; - }; +namespace { + +class A { + public: + explicit A(int x) : x_(x) {} + + int x() const { + return x_; + } + private: + int x_; +}; + +class MoveConstructOnly { + public: + MoveConstructOnly() = default; + MoveConstructOnly(const MoveConstructOnly&) = delete; + MoveConstructOnly(MoveConstructOnly&&) = default; +}; +class MutableContainer { + public: + mutable MoveConstructOnly val; +}; +} // namespace + +TEST(Try, basic) { A a(5); Try t_a(std::move(a)); @@ -40,6 +59,76 @@ TEST(Try, basic) { EXPECT_EQ(5, t_a.value().x()); } +TEST(Try, in_place) { + Try t_a(in_place, 5); + + EXPECT_EQ(5, t_a.value().x()); +} + +TEST(Try, in_place_nested) { + Try> t_t_a(in_place, in_place, 5); + + EXPECT_EQ(5, t_t_a.value().value().x()); +} + +TEST(Try, MoveDereference) { + auto ptr = std::make_unique(1); + auto t = Try>{std::move(ptr)}; + auto result = *std::move(t); + EXPECT_EQ(*result, 1); +} + +TEST(Try, MoveConstRvalue) { + // tests to see if Try returns a const Rvalue, this is required in the case + // where for example MutableContainer has a mutable memebr that is move only + // and you want to fetch the value from the Try and move it into a member + { + const Try t{in_place}; + auto val = MoveConstructOnly{std::move(t).value().val}; + static_cast(val); + } + { + const Try t{in_place}; + auto val = (*(std::move(t))).val; + static_cast(val); + } +} + +TEST(Try, ValueOverloads) { + using ML = int&; + using MR = int&&; + using CL = const int&; + using CR = const int&&; + + { + auto obj = Try{}; + using ActualML = decltype(obj.value()); + using ActualMR = decltype(std::move(obj).value()); + using ActualCL = decltype(as_const(obj).value()); + using ActualCR = decltype(std::move(as_const(obj)).value()); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + } + + { + auto obj = Try{3}; + EXPECT_EQ(obj.value(), 3); + EXPECT_EQ(std::move(obj).value(), 3); + EXPECT_EQ(as_const(obj).value(), 3); + EXPECT_EQ(std::move(as_const(obj)).value(), 3); + } + + { + auto obj = Try{make_exception_wrapper("oops")}; + EXPECT_THROW(obj.value(), std::range_error); + EXPECT_THROW(std::move(obj.value()), std::range_error); + EXPECT_THROW(as_const(obj.value()), std::range_error); + EXPECT_THROW(std::move(as_const(obj.value())), std::range_error); + } +} + // Make sure we can copy Trys for copyable types TEST(Try, copy) { Try t; @@ -55,7 +144,7 @@ TEST(Try, moveOnly) { TEST(Try, makeTryWith) { auto func = []() { - return folly::make_unique(1); + return std::make_unique(1); }; auto result = makeTryWith(func); @@ -64,9 +153,8 @@ TEST(Try, makeTryWith) { } TEST(Try, makeTryWithThrow) { - auto func = []() { + auto func = []() -> std::unique_ptr { throw std::runtime_error("Runtime"); - return folly::make_unique(1); }; auto result = makeTryWith(func); @@ -85,9 +173,263 @@ TEST(Try, makeTryWithVoid) { TEST(Try, makeTryWithVoidThrow) { auto func = []() { throw std::runtime_error("Runtime"); - return; }; auto result = makeTryWith(func); EXPECT_TRUE(result.hasException()); } + +TEST(Try, exception) { + using ML = exception_wrapper&; + using MR = exception_wrapper&&; + using CL = exception_wrapper const&; + using CR = exception_wrapper const&&; + + { + auto obj = Try(); + using ActualML = decltype(obj.exception()); + using ActualMR = decltype(std::move(obj).exception()); + using ActualCL = decltype(as_const(obj).exception()); + using ActualCR = decltype(std::move(as_const(obj)).exception()); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + } + + { + auto obj = Try(3); + EXPECT_THROW(obj.exception(), TryException); + EXPECT_THROW(std::move(obj).exception(), TryException); + EXPECT_THROW(as_const(obj).exception(), TryException); + EXPECT_THROW(std::move(as_const(obj)).exception(), TryException); + } + + { + auto obj = Try(make_exception_wrapper(-3)); + EXPECT_EQ(-3, *obj.exception().get_exception()); + EXPECT_EQ(-3, *std::move(obj).exception().get_exception()); + EXPECT_EQ(-3, *as_const(obj).exception().get_exception()); + EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception()); + } + + { + auto obj = Try(); + using ActualML = decltype(obj.exception()); + using ActualMR = decltype(std::move(obj).exception()); + using ActualCL = decltype(as_const(obj).exception()); + using ActualCR = decltype(std::move(as_const(obj)).exception()); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + } + + { + auto obj = Try(); + EXPECT_THROW(obj.exception(), TryException); + EXPECT_THROW(std::move(obj).exception(), TryException); + EXPECT_THROW(as_const(obj).exception(), TryException); + EXPECT_THROW(std::move(as_const(obj)).exception(), TryException); + } + + { + auto obj = Try(make_exception_wrapper(-3)); + EXPECT_EQ(-3, *obj.exception().get_exception()); + EXPECT_EQ(-3, *std::move(obj).exception().get_exception()); + EXPECT_EQ(-3, *as_const(obj).exception().get_exception()); + EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception()); + } +} + +template +static E* get_exception(std::exception_ptr eptr) { + try { + std::rethrow_exception(eptr); + } catch (E& e) { + return &e; + } catch (...) { + return nullptr; + } +} + +TEST(Try, tryGetExceptionObject) { + auto epexn = std::make_exception_ptr(std::range_error("oops")); + auto epnum = std::make_exception_ptr(17); + + auto exn = CHECK_NOTNULL(get_exception(epexn)); + auto num = CHECK_NOTNULL(get_exception(epnum)); + + { + auto t = Try(true); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + } + + { + auto t = Try(exception_wrapper(epexn, *exn)); + EXPECT_EQ(exn, t.tryGetExceptionObject()); + EXPECT_EQ(exn, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + } + + { + auto t = Try(exception_wrapper(epnum, *num)); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(num, t.tryGetExceptionObject()); + } + + { + auto t = Try(); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + } + + { + auto t = Try(exception_wrapper(epexn, *exn)); + EXPECT_EQ(exn, t.tryGetExceptionObject()); + EXPECT_EQ(exn, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + } + + { + auto t = Try(exception_wrapper(epnum, *num)); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(num, t.tryGetExceptionObject()); + } + + { + auto const t = Try(true); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + } + + { + auto const t = Try(exception_wrapper(epexn, *exn)); + EXPECT_EQ(exn, t.tryGetExceptionObject()); + EXPECT_EQ(exn, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + } + + { + auto const t = Try(exception_wrapper(epnum, *num)); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(num, t.tryGetExceptionObject()); + } + + { + auto const t = Try(); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + } + + { + auto const t = Try(exception_wrapper(epexn, *exn)); + EXPECT_EQ(exn, t.tryGetExceptionObject()); + EXPECT_EQ(exn, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + } + + { + auto const t = Try(exception_wrapper(epnum, *num)); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(nullptr, t.tryGetExceptionObject()); + EXPECT_EQ(num, t.tryGetExceptionObject()); + } +} + +TEST(Try, withException) { + auto ew = make_exception_wrapper("oops"); + + { + auto t = Try(true); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](std::runtime_error&) {})); + EXPECT_FALSE(t.withException([](std::logic_error&) {})); + } + + { + auto t = Try(ew); + EXPECT_TRUE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_TRUE(t.withException([](std::runtime_error&) {})); + EXPECT_FALSE(t.withException([](std::logic_error&) {})); + } + + { + auto t = Try(); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](std::runtime_error&) {})); + EXPECT_FALSE(t.withException([](std::logic_error&) {})); + } + + { + auto t = Try(ew); + EXPECT_TRUE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_TRUE(t.withException([](std::runtime_error&) {})); + EXPECT_FALSE(t.withException([](std::logic_error&) {})); + } + + { + auto const t = Try(true); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](std::runtime_error const&) {})); + EXPECT_FALSE(t.withException([](std::logic_error const&) {})); + } + + { + auto const t = Try(ew); + EXPECT_TRUE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_TRUE(t.withException([](std::runtime_error const&) {})); + EXPECT_FALSE(t.withException([](std::logic_error const&) {})); + } + + { + auto const t = Try(); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](std::runtime_error const&) {})); + EXPECT_FALSE(t.withException([](std::logic_error const&) {})); + } + + { + auto const t = Try(ew); + EXPECT_TRUE(t.withException([](auto&) {})); + EXPECT_FALSE(t.withException([](auto&) {})); + EXPECT_TRUE(t.withException([](std::runtime_error const&) {})); + EXPECT_FALSE(t.withException([](std::logic_error const&) {})); + } +} + +TEST(Try, TestUnwrapTuple) { + auto original = std::make_tuple(Try{1}, Try{2}); + EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(original)); + EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(folly::copy(original))); + EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(folly::as_const(original))); +} + +TEST(Try, TestUnwrapPair) { + auto original = std::make_pair(Try{1}, Try{2}); + EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(original)); + EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(folly::copy(original))); + EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(folly::as_const(original))); +} + +TEST(Try, TestUnwrapForward) { + using UPtr_t = std::unique_ptr; + auto original = std::make_tuple(Try{std::make_unique(1)}); + auto unwrapped = unwrapTryTuple(std::move(original)); + EXPECT_EQ(*std::get<0>(unwrapped), 1); +}