/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 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/futures/Future.h>
#include <folly/futures/InlineExecutor.h>
#include <folly/futures/ManualExecutor.h>
#include <folly/futures/DrivableExecutor.h>
#include <folly/Baton.h>
#include <folly/MPMCQueue.h>
+#include <folly/portability/GTest.h>
#include <thread>
explicit ManualWaiter(std::shared_ptr<ManualExecutor> ex) : ex(ex) {}
void add(Func f) override {
- ex->add(f);
+ ex->add(std::move(f));
}
void drive() override {
});
}
- ~ViaFixture() {
+ ~ViaFixture() override {
done = true;
eastExecutor->add([=]() { });
t.join();
std::shared_ptr<ManualExecutor> eastExecutor;
std::shared_ptr<ManualWaiter> waiter;
InlineExecutor inlineExecutor;
- bool done;
+ std::atomic<bool> done;
std::thread t;
};
TEST_F(ViaFixture, threadHops) {
auto westThreadId = std::this_thread::get_id();
- auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
- EXPECT_NE(std::this_thread::get_id(), westThreadId);
- return makeFuture<int>(1);
- }).via(westExecutor.get()
- ).then([=](Try<int>&& t) {
- EXPECT_EQ(std::this_thread::get_id(), westThreadId);
- return t.value();
- });
+ auto f = via(eastExecutor.get())
+ .then([=](Try<Unit>&& /* t */) {
+ EXPECT_NE(std::this_thread::get_id(), westThreadId);
+ return makeFuture<int>(1);
+ })
+ .via(westExecutor.get())
+ .then([=](Try<int>&& t) {
+ EXPECT_EQ(std::this_thread::get_id(), westThreadId);
+ return t.value();
+ });
EXPECT_EQ(f.getVia(waiter.get()), 1);
}
}
struct PriorityExecutor : public Executor {
- void add(Func f) override {}
+ void add(Func /* f */) override {}
- void addWithPriority(Func, int8_t priority) override {
+ void addWithPriority(Func f, int8_t priority) override {
int mid = getNumPriorities() / 2;
int p = priority < 0 ?
std::max(0, mid + priority) :
} else if (p == 2) {
count2++;
}
+ f();
}
uint8_t getNumPriorities() const override {
}
TEST(Via, then2Variadic) {
- struct Foo { bool a = false; void foo(Try<void>) { a = true; } };
+ struct Foo { bool a = false; void foo(Try<Unit>) { a = true; } };
Foo f;
ManualExecutor x;
makeFuture().then(&x, &Foo::foo, &f);
EXPECT_TRUE(f.a);
}
+#ifndef __APPLE__ // TODO #7372389
/// Simple executor that does work in another thread
class ThreadExecutor : public Executor {
folly::MPMCQueue<Func> funcs;
worker = std::thread(std::bind(&ThreadExecutor::work, this));
}
- ~ThreadExecutor() {
+ ~ThreadExecutor() override {
done = true;
funcs.write([]{});
worker.join();
EXPECT_EQ(42, *val);
}
+TEST(Via, callbackRace) {
+ ThreadExecutor x;
+
+ auto fn = [&x]{
+ auto promises = std::make_shared<std::vector<Promise<Unit>>>(4);
+ std::vector<Future<Unit>> futures;
+
+ for (auto& p : *promises) {
+ futures.emplace_back(
+ p.getFuture()
+ .via(&x)
+ .then([](Try<Unit>&&){}));
+ }
+
+ x.waitForStartup();
+ x.add([promises]{
+ for (auto& p : *promises) {
+ p.setValue();
+ }
+ });
+
+ return collectAll(futures);
+ };
+
+ fn().wait();
+}
+#endif
+
class DummyDrivableExecutor : public DrivableExecutor {
public:
- void add(Func f) override {}
+ void add(Func /* f */) override {}
void drive() override { ran = true; }
bool ran{false};
};
TEST(Via, viaRaces) {
ManualExecutor x;
- Promise<void> p;
+ Promise<Unit> p;
auto tid = std::this_thread::get_id();
bool done = false;
std::thread t1([&] {
p.getFuture()
.via(&x)
- .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
- .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
- .then([&](Try<void>&&) { done = true; });
+ .then([&](Try<Unit>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
+ .then([&](Try<Unit>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
+ .then([&](Try<Unit>&&) { done = true; });
});
std::thread t2([&] {
t2.join();
}
-TEST(Via, callbackRace) {
- ThreadExecutor x;
-
- auto fn = [&x]{
- auto promises = std::make_shared<std::vector<Promise<void>>>(4);
- std::vector<Future<void>> futures;
-
- for (auto& p : *promises) {
- futures.emplace_back(
- p.getFuture()
- .via(&x)
- .then([](Try<void>&&){}));
- }
-
- x.waitForStartup();
- x.add([promises]{
- for (auto& p : *promises) {
- p.setValue();
- }
- });
-
- return collectAll(futures);
- };
-
- fn().wait();
-}
-
TEST(ViaFunc, liftsVoid) {
ManualExecutor x;
int count = 0;
- Future<void> f = via(&x, [&]{ count++; });
+ Future<Unit> f = via(&x, [&]{ count++; });
EXPECT_EQ(0, count);
x.run();
x.run();
EXPECT_EQ(2, count);
}
+
+TEST(ViaFunc, moveOnly) {
+ ManualExecutor x;
+ auto intp = folly::make_unique<int>(42);
+
+ EXPECT_EQ(42, via(&x, [intp = std::move(intp)] { return *intp; }).getVia(&x));
+}