unwrapTryTuple only accepted rvalue tuple types
[folly.git] / folly / test / TryTest.cpp
index e1f2c4e9c65b4448a7660e850377446ec50d1af7..8e675f1f7738d7b6d3945759009c8a1870aa811c 100644 (file)
@@ -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.
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
+#include <folly/Try.h>
+
+#include <glog/logging.h>
 
 #include <folly/Memory.h>
-#include <folly/Try.h>
+#include <folly/Traits.h>
+#include <folly/portability/GTest.h>
 
 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_;
+};
+}
 
+TEST(Try, basic) {
   A a(5);
   Try<A> t_a(std::move(a));
 
@@ -41,6 +47,18 @@ TEST(Try, basic) {
   EXPECT_EQ(5, t_a.value().x());
 }
 
+TEST(Try, in_place) {
+  Try<A> t_a(in_place, 5);
+
+  EXPECT_EQ(5, t_a.value().x());
+}
+
+TEST(Try, in_place_nested) {
+  Try<Try<A>> t_t_a(in_place, in_place, 5);
+
+  EXPECT_EQ(5, t_t_a.value().value().x());
+}
+
 // Make sure we can copy Trys for copyable types
 TEST(Try, copy) {
   Try<int> t;
@@ -56,7 +74,7 @@ TEST(Try, moveOnly) {
 
 TEST(Try, makeTryWith) {
   auto func = []() {
-    return folly::make_unique<int>(1);
+    return std::make_unique<int>(1);
   };
 
   auto result = makeTryWith(func);
@@ -65,9 +83,8 @@ TEST(Try, makeTryWith) {
 }
 
 TEST(Try, makeTryWithThrow) {
-  auto func = []() {
+  auto func = []() -> std::unique_ptr<int> {
     throw std::runtime_error("Runtime");
-    return folly::make_unique<int>(1);
   };
 
   auto result = makeTryWith(func);
@@ -86,9 +103,263 @@ TEST(Try, makeTryWithVoid) {
 TEST(Try, makeTryWithVoidThrow) {
   auto func = []() {
     throw std::runtime_error("Runtime");
-    return;
   };
 
   auto result = makeTryWith(func);
   EXPECT_TRUE(result.hasException<std::runtime_error>());
 }
+
+TEST(Try, exception) {
+  using ML = exception_wrapper&;
+  using MR = exception_wrapper&&;
+  using CL = exception_wrapper const&;
+  using CR = exception_wrapper const&&;
+
+  {
+    auto obj = Try<int>();
+    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<ML, ActualML>::value));
+    EXPECT_TRUE((std::is_same<MR, ActualMR>::value));
+    EXPECT_TRUE((std::is_same<CL, ActualCL>::value));
+    EXPECT_TRUE((std::is_same<CR, ActualCR>::value));
+  }
+
+  {
+    auto obj = Try<int>(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<int>(make_exception_wrapper<int>(-3));
+    EXPECT_EQ(-3, *obj.exception().get_exception<int>());
+    EXPECT_EQ(-3, *std::move(obj).exception().get_exception<int>());
+    EXPECT_EQ(-3, *as_const(obj).exception().get_exception<int>());
+    EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception<int>());
+  }
+
+  {
+    auto obj = Try<void>();
+    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<ML, ActualML>::value));
+    EXPECT_TRUE((std::is_same<MR, ActualMR>::value));
+    EXPECT_TRUE((std::is_same<CL, ActualCL>::value));
+    EXPECT_TRUE((std::is_same<CR, ActualCR>::value));
+  }
+
+  {
+    auto obj = Try<void>();
+    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<void>(make_exception_wrapper<int>(-3));
+    EXPECT_EQ(-3, *obj.exception().get_exception<int>());
+    EXPECT_EQ(-3, *std::move(obj).exception().get_exception<int>());
+    EXPECT_EQ(-3, *as_const(obj).exception().get_exception<int>());
+    EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception<int>());
+  }
+}
+
+template <typename E>
+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<std::range_error>(epexn));
+  auto num = CHECK_NOTNULL(get_exception<int>(epnum));
+
+  {
+    auto t = Try<bool>(true);
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto t = Try<bool>(exception_wrapper(epexn, *exn));
+    EXPECT_EQ(exn, t.tryGetExceptionObject());
+    EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto t = Try<bool>(exception_wrapper(epnum, *num));
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(num, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto t = Try<void>();
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto t = Try<void>(exception_wrapper(epexn, *exn));
+    EXPECT_EQ(exn, t.tryGetExceptionObject());
+    EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto t = Try<void>(exception_wrapper(epnum, *num));
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(num, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto const t = Try<bool>(true);
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto const t = Try<bool>(exception_wrapper(epexn, *exn));
+    EXPECT_EQ(exn, t.tryGetExceptionObject());
+    EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto const t = Try<bool>(exception_wrapper(epnum, *num));
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(num, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto const t = Try<void>();
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto const t = Try<void>(exception_wrapper(epexn, *exn));
+    EXPECT_EQ(exn, t.tryGetExceptionObject());
+    EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
+  }
+
+  {
+    auto const t = Try<void>(exception_wrapper(epnum, *num));
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject());
+    EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
+    EXPECT_EQ(num, t.tryGetExceptionObject<int>());
+  }
+}
+
+TEST(Try, withException) {
+  auto ew = make_exception_wrapper<std::range_error>("oops");
+
+  {
+    auto t = Try<bool>(true);
+    EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
+    EXPECT_FALSE(t.withException([](std::logic_error&) {}));
+  }
+
+  {
+    auto t = Try<bool>(ew);
+    EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
+    EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
+    EXPECT_FALSE(t.withException([](std::logic_error&) {}));
+  }
+
+  {
+    auto t = Try<void>();
+    EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
+    EXPECT_FALSE(t.withException([](std::logic_error&) {}));
+  }
+
+  {
+    auto t = Try<void>(ew);
+    EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
+    EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
+    EXPECT_FALSE(t.withException([](std::logic_error&) {}));
+  }
+
+  {
+    auto const t = Try<bool>(true);
+    EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
+    EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
+  }
+
+  {
+    auto const t = Try<bool>(ew);
+    EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
+    EXPECT_TRUE(t.withException([](std::runtime_error const&) {}));
+    EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
+  }
+
+  {
+    auto const t = Try<void>();
+    EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
+    EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
+  }
+
+  {
+    auto const t = Try<void>(ew);
+    EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
+    EXPECT_FALSE(t.withException<std::logic_error>([](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<int>{1}, Try<int>{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<int>{1}, Try<int>{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<int>;
+  auto original = std::make_tuple(Try<UPtr_t>{std::make_unique<int>(1)});
+  auto unwrapped = unwrapTryTuple(std::move(original));
+  EXPECT_EQ(*std::get<0>(unwrapped), 1);
+}