Make consistent set of get and getTry methods on SemiFuture.
[folly.git] / folly / futures / test / SemiFutureTest.cpp
index 1471d42b8a13acc38f65c78bba055aa457e7a564..36942645297c4296b005146d7fa8a770d2978b9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Facebook, Inc.
+ * Copyright 2017-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#include <folly/Baton.h>
 #include <folly/Executor.h>
 #include <folly/Memory.h>
 #include <folly/Unit.h>
@@ -22,6 +20,7 @@
 #include <folly/futures/Future.h>
 #include <folly/io/async/EventBase.h>
 #include <folly/portability/GTest.h>
+#include <folly/synchronization/Baton.h>
 
 #include <algorithm>
 #include <atomic>
@@ -143,6 +142,10 @@ TEST(SemiFuture, makeSemiFutureNoThrow) {
   makeSemiFuture().value();
 }
 
+TEST(SemiFuture, ViaThrowOnNull) {
+  EXPECT_THROW(makeSemiFuture().via(nullptr), NoExecutor);
+}
+
 TEST(SemiFuture, ConstructSemiFutureFromEmptyFuture) {
   auto f = SemiFuture<int>{Future<int>::makeEmpty()};
   EXPECT_THROW(f.isReady(), NoState);
@@ -167,7 +170,7 @@ TEST(SemiFuture, MakeSemiFutureFromFutureWithValue) {
 
 TEST(SemiFuture, MakeSemiFutureFromReadyFuture) {
   Promise<int> p;
-  auto f = SemiFuture<int>{p.getFuture()};
+  auto f = p.getSemiFuture();
   EXPECT_FALSE(f.isReady());
   p.setValue(42);
   EXPECT_TRUE(f.isReady());
@@ -175,7 +178,7 @@ TEST(SemiFuture, MakeSemiFutureFromReadyFuture) {
 
 TEST(SemiFuture, MakeSemiFutureFromNotReadyFuture) {
   Promise<int> p;
-  auto f = SemiFuture<int>{p.getFuture()};
+  auto f = p.getSemiFuture();
   EXPECT_THROW(f.value(), eggs_t);
 }
 
@@ -183,7 +186,7 @@ TEST(SemiFuture, MakeFutureFromSemiFuture) {
   folly::EventBase e;
   Promise<int> p;
   std::atomic<int> result{0};
-  auto f = SemiFuture<int>{p.getFuture()};
+  auto f = p.getSemiFuture();
   auto future = std::move(f).via(&e).then([&](int value) {
     result = value;
     return value;
@@ -198,12 +201,55 @@ TEST(SemiFuture, MakeFutureFromSemiFuture) {
   ASSERT_EQ(result, 42);
 }
 
+TEST(SemiFuture, MakeFutureFromSemiFutureReturnFuture) {
+  folly::EventBase e;
+  Promise<int> p;
+  int result{0};
+  auto f = p.getSemiFuture();
+  auto future = std::move(f).via(&e).then([&](int value) {
+    result = value;
+    return folly::makeFuture(std::move(value));
+  });
+  e.loop();
+  EXPECT_EQ(result, 0);
+  EXPECT_FALSE(future.isReady());
+  p.setValue(42);
+  e.loop();
+  EXPECT_TRUE(future.isReady());
+  ASSERT_EQ(future.value(), 42);
+  ASSERT_EQ(result, 42);
+}
+
+TEST(SemiFuture, MakeFutureFromSemiFutureReturnSemiFuture) {
+  folly::EventBase e;
+  Promise<int> p;
+  int result{0};
+  auto f = p.getSemiFuture();
+  auto future = std::move(f)
+                    .via(&e)
+                    .then([&](int value) {
+                      result = value;
+                      return folly::makeSemiFuture(std::move(value));
+                    })
+                    .then([&](int value) {
+                      return folly::makeSemiFuture(std::move(value));
+                    });
+  e.loop();
+  EXPECT_EQ(result, 0);
+  EXPECT_FALSE(future.isReady());
+  p.setValue(42);
+  e.loop();
+  EXPECT_TRUE(future.isReady());
+  ASSERT_EQ(future.value(), 42);
+  ASSERT_EQ(result, 42);
+}
+
 TEST(SemiFuture, MakeFutureFromSemiFutureLValue) {
   folly::EventBase e;
   Promise<int> p;
   std::atomic<int> result{0};
-  auto f = SemiFuture<int>{p.getFuture()};
-  auto future = f.via(&e).then([&](int value) {
+  auto f = p.getSemiFuture();
+  auto future = std::move(f).via(&e).then([&](int value) {
     result = value;
     return value;
   });
@@ -216,3 +262,161 @@ TEST(SemiFuture, MakeFutureFromSemiFutureLValue) {
   ASSERT_EQ(future.value(), 42);
   ASSERT_EQ(result, 42);
 }
+
+TEST(SemiFuture, SimpleGet) {
+  EventBase e2;
+  Promise<int> p;
+  auto sf = p.getSemiFuture();
+  p.setValue(3);
+  auto v = std::move(sf).get();
+  ASSERT_EQ(v, 3);
+}
+
+TEST(SemiFuture, SimpleGetTry) {
+  EventBase e2;
+  Promise<int> p;
+  auto sf = p.getSemiFuture();
+  p.setValue(3);
+  auto v = std::move(sf).getTry();
+  ASSERT_EQ(v.value(), 3);
+}
+
+TEST(SemiFuture, SimpleTimedGet) {
+  EventBase e2;
+  Promise<folly::Unit> p;
+  auto sf = p.getSemiFuture();
+  EXPECT_THROW(std::move(sf).get(std::chrono::seconds(1)), TimedOut);
+}
+
+TEST(SemiFuture, SimpleTimedGetTry) {
+  EventBase e2;
+  Promise<folly::Unit> p;
+  auto sf = p.getSemiFuture();
+  EXPECT_THROW(std::move(sf).getTry(std::chrono::seconds(1)), TimedOut);
+}
+
+TEST(SemiFuture, SimpleValue) {
+  EventBase e2;
+  Promise<int> p;
+  auto sf = p.getSemiFuture();
+  p.setValue(3);
+  auto v = std::move(sf).value();
+  ASSERT_EQ(v, 3);
+}
+
+TEST(SemiFuture, SimpleValueThrow) {
+  EventBase e2;
+  Promise<folly::Unit> p;
+  auto sf = p.getSemiFuture();
+  EXPECT_THROW(std::move(sf).value(), FutureNotReady);
+}
+
+TEST(SemiFuture, SimpleResult) {
+  EventBase e2;
+  Promise<int> p;
+  auto sf = p.getSemiFuture();
+  p.setValue(3);
+  auto v = std::move(sf).result();
+  ASSERT_EQ(v.value(), 3);
+}
+
+TEST(SemiFuture, SimpleResultThrow) {
+  EventBase e2;
+  Promise<folly::Unit> p;
+  auto sf = p.getSemiFuture();
+  EXPECT_THROW(std::move(sf).result(), FutureNotReady);
+}
+
+TEST(SemiFuture, SimpleDefer) {
+  std::atomic<int> innerResult{0};
+  Promise<folly::Unit> p;
+  auto f = p.getFuture();
+  auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
+  p.setValue();
+  // Run "F" here inline in the calling thread
+  std::move(sf).get();
+  ASSERT_EQ(innerResult, 17);
+}
+
+TEST(SemiFuture, DeferWithGetVia) {
+  std::atomic<int> innerResult{0};
+  EventBase e2;
+  Promise<folly::Unit> p;
+  auto f = p.getFuture();
+  auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
+  p.setValue();
+  std::move(sf).getVia(&e2);
+  ASSERT_EQ(innerResult, 17);
+}
+
+TEST(SemiFuture, DeferWithVia) {
+  std::atomic<int> innerResult{0};
+  EventBase e2;
+  Promise<folly::Unit> p;
+  auto f = p.getFuture();
+  auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
+  // Run "F" here inline in the calling thread
+  auto tf = std::move(sf).via(&e2);
+  p.setValue();
+  tf.getVia(&e2);
+  ASSERT_EQ(innerResult, 17);
+}
+
+TEST(SemiFuture, ChainingDefertoThen) {
+  std::atomic<int> innerResult{0};
+  std::atomic<int> result{0};
+  EventBase e2;
+  Promise<folly::Unit> p;
+  auto f = p.getFuture();
+  auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
+  // Run "F" here inline in a task running on the eventbase
+  auto tf = std::move(sf).via(&e2).then([&]() { result = 42; });
+  p.setValue();
+  tf.getVia(&e2);
+  ASSERT_EQ(innerResult, 17);
+  ASSERT_EQ(result, 42);
+}
+
+TEST(SemiFuture, SimpleDeferWithValue) {
+  std::atomic<int> innerResult{0};
+  Promise<int> p;
+  auto f = p.getFuture();
+  auto sf = std::move(f).semi().defer([&](int a) { innerResult = a; });
+  p.setValue(7);
+  // Run "F" here inline in the calling thread
+  std::move(sf).get();
+  ASSERT_EQ(innerResult, 7);
+}
+
+TEST(SemiFuture, ChainingDefertoThenWithValue) {
+  std::atomic<int> innerResult{0};
+  std::atomic<int> result{0};
+  EventBase e2;
+  Promise<int> p;
+  auto f = p.getFuture();
+  auto sf = std::move(f).semi().defer([&](int a) {
+    innerResult = a;
+    return a;
+  });
+  // Run "F" here inline in a task running on the eventbase
+  auto tf = std::move(sf).via(&e2).then([&](int a) { result = a; });
+  p.setValue(7);
+  tf.getVia(&e2);
+  ASSERT_EQ(innerResult, 7);
+  ASSERT_EQ(result, 7);
+}
+
+TEST(SemiFuture, MakeSemiFutureFromFutureWithTry) {
+  Promise<int> p;
+  auto f = p.getFuture();
+  auto sf = std::move(f).semi().defer([&](Try<int> t) {
+    if (auto err = t.tryGetExceptionObject<std::logic_error>()) {
+      return Try<std::string>(err->what());
+    }
+    return Try<std::string>(
+        make_exception_wrapper<std::logic_error>("Exception"));
+  });
+  p.setException(make_exception_wrapper<std::logic_error>("Try"));
+  auto tryResult = std::move(sf).get();
+  ASSERT_EQ(tryResult.value(), "Try");
+}