/*
- * 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.
* 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>
#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>
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);
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());
TEST(SemiFuture, MakeSemiFutureFromNotReadyFuture) {
Promise<int> p;
- auto f = SemiFuture<int>{p.getFuture()};
+ auto f = p.getSemiFuture();
EXPECT_THROW(f.value(), eggs_t);
}
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;
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;
});
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");
+}