*/
#include <gflags/gflags.h>
+
#include <folly/Baton.h>
#include <folly/Benchmark.h>
#include <folly/futures/Future.h>
#include <folly/futures/Promise.h>
+
#include <semaphore.h>
#include <vector>
using namespace folly;
-using namespace std;
namespace {
BENCHMARK_DRAW_LINE()
BENCHMARK(no_contention) {
- vector<Promise<int>> promises(10000);
- vector<Future<int>> futures;
+ std::vector<Promise<int>> promises(10000);
+ std::vector<Future<int>> futures;
std::thread producer, consumer;
BENCHMARK_SUSPEND {
}
BENCHMARK_RELATIVE(contention) {
- vector<Promise<int>> promises(10000);
- vector<Future<int>> futures;
+ std::vector<Promise<int>> promises(10000);
+ std::vector<Future<int>> futures;
std::thread producer, consumer;
sem_t sem;
sem_init(&sem, 0, 0);
+++ /dev/null
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// amazing what things can go wrong if you include things in an unexpected
-// order.
-#include <folly/futures/Try.h>
-#include <folly/futures/Promise.h>
-#include <folly/futures/Future.h>
-int main() { return 0; }
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+#include <folly/Random.h>
+#include <folly/small_vector.h>
+
+using namespace folly;
+
+typedef FutureException eggs_t;
+static eggs_t eggs("eggs");
+
+auto rng = std::mt19937(folly::randomNumberSeed());
+
+TEST(Collect, collectAll) {
+ // returns a vector variant
+ {
+ std::vector<Promise<int>> promises(10);
+ std::vector<Future<int>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ auto allf = collectAll(futures);
+
+ std::shuffle(promises.begin(), promises.end(), rng);
+ for (auto& p : promises) {
+ EXPECT_FALSE(allf.isReady());
+ p.setValue(42);
+ }
+
+ EXPECT_TRUE(allf.isReady());
+ auto& results = allf.value();
+ for (auto& t : results) {
+ EXPECT_EQ(42, t.value());
+ }
+ }
+
+ // check error semantics
+ {
+ std::vector<Promise<int>> promises(4);
+ std::vector<Future<int>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ auto allf = collectAll(futures);
+
+
+ promises[0].setValue(42);
+ promises[1].setException(eggs);
+
+ EXPECT_FALSE(allf.isReady());
+
+ promises[2].setValue(42);
+
+ EXPECT_FALSE(allf.isReady());
+
+ promises[3].setException(eggs);
+
+ EXPECT_TRUE(allf.isReady());
+ EXPECT_FALSE(allf.getTry().hasException());
+
+ auto& results = allf.value();
+ EXPECT_EQ(42, results[0].value());
+ EXPECT_TRUE(results[1].hasException());
+ EXPECT_EQ(42, results[2].value());
+ EXPECT_TRUE(results[3].hasException());
+ }
+
+ // check that futures are ready in then()
+ {
+ std::vector<Promise<void>> promises(10);
+ std::vector<Future<void>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ auto allf = collectAll(futures)
+ .then([](Try<std::vector<Try<void>>>&& ts) {
+ for (auto& f : ts.value())
+ f.value();
+ });
+
+ std::shuffle(promises.begin(), promises.end(), rng);
+ for (auto& p : promises)
+ p.setValue();
+ EXPECT_TRUE(allf.isReady());
+ }
+}
+
+TEST(Collect, collect) {
+ // success case
+ {
+ std::vector<Promise<int>> promises(10);
+ std::vector<Future<int>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ auto allf = collect(futures);
+
+ std::shuffle(promises.begin(), promises.end(), rng);
+ for (auto& p : promises) {
+ EXPECT_FALSE(allf.isReady());
+ p.setValue(42);
+ }
+
+ EXPECT_TRUE(allf.isReady());
+ for (auto i : allf.value()) {
+ EXPECT_EQ(42, i);
+ }
+ }
+
+ // failure case
+ {
+ std::vector<Promise<int>> promises(10);
+ std::vector<Future<int>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ auto allf = collect(futures);
+
+ std::shuffle(promises.begin(), promises.end(), rng);
+ for (int i = 0; i < 10; i++) {
+ if (i < 5) {
+ // everthing goes well so far...
+ EXPECT_FALSE(allf.isReady());
+ promises[i].setValue(42);
+ } else if (i == 5) {
+ // short circuit with an exception
+ EXPECT_FALSE(allf.isReady());
+ promises[i].setException(eggs);
+ EXPECT_TRUE(allf.isReady());
+ } else if (i < 8) {
+ // don't blow up on further values
+ EXPECT_TRUE(allf.isReady());
+ promises[i].setValue(42);
+ } else {
+ // don't blow up on further exceptions
+ EXPECT_TRUE(allf.isReady());
+ promises[i].setException(eggs);
+ }
+ }
+
+ EXPECT_THROW(allf.value(), eggs_t);
+ }
+
+ // void futures success case
+ {
+ std::vector<Promise<void>> promises(10);
+ std::vector<Future<void>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ auto allf = collect(futures);
+
+ std::shuffle(promises.begin(), promises.end(), rng);
+ for (auto& p : promises) {
+ EXPECT_FALSE(allf.isReady());
+ p.setValue();
+ }
+
+ EXPECT_TRUE(allf.isReady());
+ }
+
+ // void futures failure case
+ {
+ std::vector<Promise<void>> promises(10);
+ std::vector<Future<void>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ auto allf = collect(futures);
+
+ std::shuffle(promises.begin(), promises.end(), rng);
+ for (int i = 0; i < 10; i++) {
+ if (i < 5) {
+ // everthing goes well so far...
+ EXPECT_FALSE(allf.isReady());
+ promises[i].setValue();
+ } else if (i == 5) {
+ // short circuit with an exception
+ EXPECT_FALSE(allf.isReady());
+ promises[i].setException(eggs);
+ EXPECT_TRUE(allf.isReady());
+ } else if (i < 8) {
+ // don't blow up on further values
+ EXPECT_TRUE(allf.isReady());
+ promises[i].setValue();
+ } else {
+ // don't blow up on further exceptions
+ EXPECT_TRUE(allf.isReady());
+ promises[i].setException(eggs);
+ }
+ }
+
+ EXPECT_THROW(allf.value(), eggs_t);
+ }
+
+ // move only compiles
+ {
+ std::vector<Promise<std::unique_ptr<int>>> promises(10);
+ std::vector<Future<std::unique_ptr<int>>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ collect(futures);
+ }
+
+}
+
+struct NotDefaultConstructible {
+ NotDefaultConstructible() = delete;
+ explicit NotDefaultConstructible(int arg) : i(arg) {}
+ int i;
+};
+
+// We have a specialized implementation for non-default-constructible objects
+// Ensure that it works and preserves order
+TEST(Collect, collectNotDefaultConstructible) {
+ std::vector<Promise<NotDefaultConstructible>> promises(10);
+ std::vector<Future<NotDefaultConstructible>> futures;
+ std::vector<int> indices(10);
+ std::iota(indices.begin(), indices.end(), 0);
+ std::shuffle(indices.begin(), indices.end(), rng);
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ auto allf = collect(futures);
+
+ for (auto i : indices) {
+ EXPECT_FALSE(allf.isReady());
+ promises[i].setValue(NotDefaultConstructible(i));
+ }
+
+ EXPECT_TRUE(allf.isReady());
+ int i = 0;
+ for (auto val : allf.value()) {
+ EXPECT_EQ(i, val.i);
+ i++;
+ }
+}
+
+TEST(Collect, collectAny) {
+ {
+ std::vector<Promise<int>> promises(10);
+ std::vector<Future<int>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ for (auto& f : futures) {
+ EXPECT_FALSE(f.isReady());
+ }
+
+ auto anyf = collectAny(futures);
+
+ /* futures were moved in, so these are invalid now */
+ EXPECT_FALSE(anyf.isReady());
+
+ promises[7].setValue(42);
+ EXPECT_TRUE(anyf.isReady());
+ auto& idx_fut = anyf.value();
+
+ auto i = idx_fut.first;
+ EXPECT_EQ(7, i);
+
+ auto& f = idx_fut.second;
+ EXPECT_EQ(42, f.value());
+ }
+
+ // error
+ {
+ std::vector<Promise<void>> promises(10);
+ std::vector<Future<void>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ for (auto& f : futures) {
+ EXPECT_FALSE(f.isReady());
+ }
+
+ auto anyf = collectAny(futures);
+
+ EXPECT_FALSE(anyf.isReady());
+
+ promises[3].setException(eggs);
+ EXPECT_TRUE(anyf.isReady());
+ EXPECT_TRUE(anyf.value().second.hasException());
+ }
+
+ // then()
+ {
+ std::vector<Promise<int>> promises(10);
+ std::vector<Future<int>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ auto anyf = collectAny(futures)
+ .then([](std::pair<size_t, Try<int>> p) {
+ EXPECT_EQ(42, p.second.value());
+ });
+
+ promises[3].setValue(42);
+ EXPECT_TRUE(anyf.isReady());
+ }
+}
+
+
+TEST(Collect, alreadyCompleted) {
+ {
+ std::vector<Future<void>> fs;
+ for (int i = 0; i < 10; i++)
+ fs.push_back(makeFuture());
+
+ collectAll(fs)
+ .then([&](std::vector<Try<void>> ts) {
+ EXPECT_EQ(fs.size(), ts.size());
+ });
+ }
+ {
+ std::vector<Future<int>> fs;
+ for (int i = 0; i < 10; i++)
+ fs.push_back(makeFuture(i));
+
+ collectAny(fs)
+ .then([&](std::pair<size_t, Try<int>> p) {
+ EXPECT_EQ(p.first, p.second.value());
+ });
+ }
+}
+
+TEST(Collect, collectN) {
+ std::vector<Promise<void>> promises(10);
+ std::vector<Future<void>> futures;
+
+ for (auto& p : promises)
+ futures.push_back(p.getFuture());
+
+ bool flag = false;
+ size_t n = 3;
+ collectN(futures, n)
+ .then([&](std::vector<std::pair<size_t, Try<void>>> v) {
+ flag = true;
+ EXPECT_EQ(n, v.size());
+ for (auto& tt : v)
+ EXPECT_TRUE(tt.second.hasValue());
+ });
+
+ promises[0].setValue();
+ EXPECT_FALSE(flag);
+ promises[1].setValue();
+ EXPECT_FALSE(flag);
+ promises[2].setValue();
+ EXPECT_TRUE(flag);
+}
+
+/// Ensure that we can compile collectAll/Any with folly::small_vector
+TEST(Collect, smallVector) {
+ static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<void>),
+ "Futures should not be trivially copyable");
+ static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<int>),
+ "Futures should not be trivially copyable");
+
+ {
+ folly::small_vector<Future<void>> futures;
+
+ for (int i = 0; i < 10; i++)
+ futures.push_back(makeFuture());
+
+ auto anyf = collectAny(futures);
+ }
+ {
+ folly::small_vector<Future<void>> futures;
+
+ for (int i = 0; i < 10; i++)
+ futures.push_back(makeFuture());
+
+ auto allf = collectAll(futures);
+ }
+}
+
+TEST(Collect, collectAllVariadic) {
+ Promise<bool> pb;
+ Promise<int> pi;
+ Future<bool> fb = pb.getFuture();
+ Future<int> fi = pi.getFuture();
+ bool flag = false;
+ collectAll(std::move(fb), std::move(fi))
+ .then([&](std::tuple<Try<bool>, Try<int>> tup) {
+ flag = true;
+ EXPECT_TRUE(std::get<0>(tup).hasValue());
+ EXPECT_EQ(std::get<0>(tup).value(), true);
+ EXPECT_TRUE(std::get<1>(tup).hasValue());
+ EXPECT_EQ(std::get<1>(tup).value(), 42);
+ });
+ pb.setValue(true);
+ EXPECT_FALSE(flag);
+ pi.setValue(42);
+ EXPECT_TRUE(flag);
+}
+
+TEST(Collect, collectAllVariadicReferences) {
+ Promise<bool> pb;
+ Promise<int> pi;
+ Future<bool> fb = pb.getFuture();
+ Future<int> fi = pi.getFuture();
+ bool flag = false;
+ collectAll(fb, fi)
+ .then([&](std::tuple<Try<bool>, Try<int>> tup) {
+ flag = true;
+ EXPECT_TRUE(std::get<0>(tup).hasValue());
+ EXPECT_EQ(std::get<0>(tup).value(), true);
+ EXPECT_TRUE(std::get<1>(tup).hasValue());
+ EXPECT_EQ(std::get<1>(tup).value(), 42);
+ });
+ pb.setValue(true);
+ EXPECT_FALSE(flag);
+ pi.setValue(42);
+ EXPECT_TRUE(flag);
+}
+
+TEST(Collect, collectAllNone) {
+ std::vector<Future<int>> fs;
+ auto f = collectAll(fs);
+ EXPECT_TRUE(f.isReady());
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+using namespace folly;
+
+class TestData : public RequestData {
+ public:
+ explicit TestData(int data) : data_(data) {}
+ virtual ~TestData() {}
+ int data_;
+};
+
+TEST(Context, basic) {
+
+ // Start a new context
+ RequestContext::create();
+
+ EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
+
+ // Set some test data
+ RequestContext::get()->setContextData(
+ "test",
+ std::unique_ptr<TestData>(new TestData(10)));
+
+ // Start a future
+ Promise<void> p;
+ auto future = p.getFuture().then([&]{
+ // Check that the context followed the future
+ EXPECT_TRUE(RequestContext::get() != nullptr);
+ auto a = dynamic_cast<TestData*>(
+ RequestContext::get()->getContextData("test"));
+ auto data = a->data_;
+ EXPECT_EQ(10, data);
+ });
+
+ // Clear the context
+ RequestContext::setContext(nullptr);
+
+ EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
+
+ // Fulfill the promise
+ p.setValue();
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+#include <folly/futures/detail/Core.h>
+
+using namespace folly;
+
+TEST(Core, size) {
+ // If this number goes down, it's fine!
+ // If it goes up, please seek professional advice ;-)
+ EXPECT_EQ(192, sizeof(detail::Core<void>));
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+using namespace folly;
+
+TEST(Ensure, basic) {
+ size_t count = 0;
+ auto cob = [&]{ count++; };
+ auto f = makeFuture(42)
+ .ensure(cob)
+ .then([](int) { throw std::runtime_error("ensure"); })
+ .ensure(cob);
+
+ EXPECT_THROW(f.get(), std::runtime_error);
+ EXPECT_EQ(2, count);
+}
*/
#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
#include <folly/futures/InlineExecutor.h>
#include <folly/futures/ManualExecutor.h>
#include <folly/futures/QueuedImmediateExecutor.h>
-#include <folly/futures/Future.h>
#include <folly/Baton.h>
using namespace folly;
-using namespace std::chrono;
-using namespace testing;
TEST(ManualExecutor, runIsStable) {
ManualExecutor x;
TEST(ManualExecutor, scheduleDur) {
ManualExecutor x;
size_t count = 0;
- milliseconds dur {10};
+ std::chrono::milliseconds dur {10};
x.schedule([&]{ count++; }, dur);
EXPECT_EQ(count, 0);
x.run();
TEST(ManualExecutor, scheduleAbs) {
ManualExecutor x;
size_t count = 0;
- x.scheduleAt([&]{ count++; }, x.now() + milliseconds(10));
+ x.scheduleAt([&]{ count++; }, x.now() + std::chrono::milliseconds(10));
EXPECT_EQ(count, 0);
- x.advance(milliseconds(10));
+ x.advance(std::chrono::milliseconds(10));
EXPECT_EQ(count, 1);
}
TEST(ManualExecutor, advanceTo) {
ManualExecutor x;
size_t count = 0;
- x.scheduleAt([&]{ count++; }, steady_clock::now());
+ x.scheduleAt([&]{ count++; }, std::chrono::steady_clock::now());
EXPECT_EQ(count, 0);
- x.advanceTo(steady_clock::now());
+ x.advanceTo(std::chrono::steady_clock::now());
EXPECT_EQ(count, 1);
}
TEST(ManualExecutor, advanceBack) {
ManualExecutor x;
size_t count = 0;
- x.advance(microseconds(5));
- x.schedule([&]{ count++; }, microseconds(6));
+ x.advance(std::chrono::microseconds(5));
+ x.schedule([&]{ count++; }, std::chrono::microseconds(6));
EXPECT_EQ(count, 0);
- x.advanceTo(x.now() - microseconds(1));
+ x.advanceTo(x.now() - std::chrono::microseconds(1));
EXPECT_EQ(count, 0);
}
TEST(ManualExecutor, advanceNeg) {
ManualExecutor x;
size_t count = 0;
- x.advance(microseconds(5));
- x.schedule([&]{ count++; }, microseconds(6));
+ x.advance(std::chrono::microseconds(5));
+ x.schedule([&]{ count++; }, std::chrono::microseconds(6));
EXPECT_EQ(count, 0);
- x.advance(microseconds(-1));
+ x.advance(std::chrono::microseconds(-1));
EXPECT_EQ(count, 0);
}
+++ /dev/null
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-#include <folly/futures/detail/FSM.h>
-
-using namespace folly::detail;
-
-enum class State { A, B };
-
-TEST(FSM, example) {
- FSM<State> fsm(State::A);
- int count = 0;
- int unprotectedCount = 0;
-
- // somebody set up us the switch
- auto tryTransition = [&]{
- switch (fsm.getState()) {
- case State::A:
- return fsm.updateState(State::A, State::B, [&]{ count++; });
- case State::B:
- return fsm.updateState(State::B, State::A,
- [&]{ count--; }, [&]{ unprotectedCount--; });
- }
- return false; // unreachable
- };
-
- // keep retrying until success (like a cas)
- while (!tryTransition()) ;
- EXPECT_EQ(State::B, fsm.getState());
- EXPECT_EQ(1, count);
- EXPECT_EQ(0, unprotectedCount);
-
- while (!tryTransition()) ;
- EXPECT_EQ(State::A, fsm.getState());
- EXPECT_EQ(0, count);
- EXPECT_EQ(-1, unprotectedCount);
-}
-
-TEST(FSM, magicMacrosExample) {
- struct MyFSM {
- FSM<State> fsm_;
- int count = 0;
- int unprotectedCount = 0;
- MyFSM() : fsm_(State::A) {}
- void twiddle() {
- FSM_START(fsm_)
- FSM_CASE(fsm_, State::A, State::B, [&]{ count++; });
- FSM_CASE2(fsm_, State::B, State::A,
- [&]{ count--; }, [&]{ unprotectedCount--; });
- FSM_END
- }
- };
-
- MyFSM fsm;
-
- fsm.twiddle();
- EXPECT_EQ(State::B, fsm.fsm_.getState());
- EXPECT_EQ(1, fsm.count);
- EXPECT_EQ(0, fsm.unprotectedCount);
-
- fsm.twiddle();
- EXPECT_EQ(State::A, fsm.fsm_.getState());
- EXPECT_EQ(0, fsm.count);
- EXPECT_EQ(-1, fsm.unprotectedCount);
-}
-
-
-TEST(FSM, ctor) {
- FSM<State> fsm(State::A);
- EXPECT_EQ(State::A, fsm.getState());
-}
-
-TEST(FSM, update) {
- FSM<State> fsm(State::A);
- EXPECT_TRUE(fsm.updateState(State::A, State::B, []{}));
- EXPECT_EQ(State::B, fsm.getState());
-}
-
-TEST(FSM, badUpdate) {
- FSM<State> fsm(State::A);
- EXPECT_FALSE(fsm.updateState(State::B, State::A, []{}));
-}
-
-TEST(FSM, actionOnUpdate) {
- FSM<State> fsm(State::A);
- int count = 0;
- fsm.updateState(State::A, State::B, [&]{ count++; });
- EXPECT_EQ(1, count);
-}
-
-TEST(FSM, noActionOnBadUpdate) {
- FSM<State> fsm(State::A);
- int count = 0;
- fsm.updateState(State::B, State::A, [&]{ count++; });
- EXPECT_EQ(0, count);
-}
-
-TEST(FSM, stateTransitionAfterAction) {
- FSM<State> fsm(State::A);
- fsm.updateState(State::A, State::B,
- [&]{ EXPECT_EQ(State::A, fsm.getState()); });
-}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/detail/FSM.h>
+
+using namespace folly::detail;
+
+enum class State { A, B };
+
+TEST(FSM, example) {
+ FSM<State> fsm(State::A);
+ int count = 0;
+ int unprotectedCount = 0;
+
+ // somebody set up us the switch
+ auto tryTransition = [&]{
+ switch (fsm.getState()) {
+ case State::A:
+ return fsm.updateState(State::A, State::B, [&]{ count++; });
+ case State::B:
+ return fsm.updateState(State::B, State::A,
+ [&]{ count--; }, [&]{ unprotectedCount--; });
+ }
+ return false; // unreachable
+ };
+
+ // keep retrying until success (like a cas)
+ while (!tryTransition()) ;
+ EXPECT_EQ(State::B, fsm.getState());
+ EXPECT_EQ(1, count);
+ EXPECT_EQ(0, unprotectedCount);
+
+ while (!tryTransition()) ;
+ EXPECT_EQ(State::A, fsm.getState());
+ EXPECT_EQ(0, count);
+ EXPECT_EQ(-1, unprotectedCount);
+}
+
+TEST(FSM, magicMacrosExample) {
+ struct MyFSM {
+ FSM<State> fsm_;
+ int count = 0;
+ int unprotectedCount = 0;
+ MyFSM() : fsm_(State::A) {}
+ void twiddle() {
+ FSM_START(fsm_)
+ FSM_CASE(fsm_, State::A, State::B, [&]{ count++; });
+ FSM_CASE2(fsm_, State::B, State::A,
+ [&]{ count--; }, [&]{ unprotectedCount--; });
+ FSM_END
+ }
+ };
+
+ MyFSM fsm;
+
+ fsm.twiddle();
+ EXPECT_EQ(State::B, fsm.fsm_.getState());
+ EXPECT_EQ(1, fsm.count);
+ EXPECT_EQ(0, fsm.unprotectedCount);
+
+ fsm.twiddle();
+ EXPECT_EQ(State::A, fsm.fsm_.getState());
+ EXPECT_EQ(0, fsm.count);
+ EXPECT_EQ(-1, fsm.unprotectedCount);
+}
+
+
+TEST(FSM, ctor) {
+ FSM<State> fsm(State::A);
+ EXPECT_EQ(State::A, fsm.getState());
+}
+
+TEST(FSM, update) {
+ FSM<State> fsm(State::A);
+ EXPECT_TRUE(fsm.updateState(State::A, State::B, []{}));
+ EXPECT_EQ(State::B, fsm.getState());
+}
+
+TEST(FSM, badUpdate) {
+ FSM<State> fsm(State::A);
+ EXPECT_FALSE(fsm.updateState(State::B, State::A, []{}));
+}
+
+TEST(FSM, actionOnUpdate) {
+ FSM<State> fsm(State::A);
+ int count = 0;
+ fsm.updateState(State::A, State::B, [&]{ count++; });
+ EXPECT_EQ(1, count);
+}
+
+TEST(FSM, noActionOnBadUpdate) {
+ FSM<State> fsm(State::A);
+ int count = 0;
+ fsm.updateState(State::B, State::A, [&]{ count++; });
+ EXPECT_EQ(0, count);
+}
+
+TEST(FSM, stateTransitionAfterAction) {
+ FSM<State> fsm(State::A);
+ fsm.updateState(State::A, State::B,
+ [&]{ EXPECT_EQ(State::A, fsm.getState()); });
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+using namespace folly;
+
+TEST(Filter, alwaysTrye) {
+ EXPECT_EQ(42, makeFuture(42).filter([](int){ return true; }).get());
+}
+
+TEST(Filter, alwaysFalse) {
+ EXPECT_THROW(makeFuture(42).filter([](int){ return false; }).get(),
+ folly::PredicateDoesNotObtain);
+}
+
+TEST(Filter, moveOnlyValue) {
+ EXPECT_EQ(42,
+ *makeFuture(folly::make_unique<int>(42))
+ .filter([](std::unique_ptr<int> const&) { return true; })
+ .get());
+}
* limitations under the License.
*/
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+#include <folly/Memory.h>
+#include <folly/Executor.h>
+#include <folly/dynamic.h>
+#include <folly/Baton.h>
+
#include <algorithm>
#include <atomic>
-#include <folly/small_vector.h>
-#include <gtest/gtest.h>
#include <memory>
#include <string>
#include <thread>
#include <type_traits>
#include <unistd.h>
-#include <folly/Memory.h>
-#include <folly/Executor.h>
-#include <folly/futures/Future.h>
-#include <folly/futures/ManualExecutor.h>
-#include <folly/futures/DrivableExecutor.h>
-#include <folly/dynamic.h>
-#include <folly/Baton.h>
-#include <folly/MPMCQueue.h>
-
-#include <folly/io/async/EventBase.h>
-#include <folly/io/async/Request.h>
using namespace folly;
-using std::pair;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-using std::chrono::milliseconds;
#define EXPECT_TYPE(x, T) \
EXPECT_TRUE((std::is_same<decltype(x), T>::value))
-/// Simple executor that does work in another thread
-class ThreadExecutor : public Executor {
- folly::MPMCQueue<Func> funcs;
- std::atomic<bool> done {false};
- std::thread worker;
- folly::Baton<> baton;
-
- void work() {
- baton.post();
- Func fn;
- while (!done) {
- while (!funcs.isEmpty()) {
- funcs.blockingRead(fn);
- fn();
- }
- }
- }
-
- public:
- explicit ThreadExecutor(size_t n = 1024)
- : funcs(n) {
- worker = std::thread(std::bind(&ThreadExecutor::work, this));
- }
-
- ~ThreadExecutor() {
- done = true;
- funcs.write([]{});
- worker.join();
- }
-
- void add(Func fn) override {
- funcs.blockingWrite(std::move(fn));
- }
-
- void waitForStartup() {
- baton.wait();
- }
-};
-
typedef FutureException eggs_t;
static eggs_t eggs("eggs");
-// Core
-
-TEST(Future, coreSize) {
- // If this number goes down, it's fine!
- // If it goes up, please seek professional advice ;-)
- EXPECT_EQ(192, sizeof(detail::Core<void>));
-}
-
// Future
TEST(Future, onError) {
}
-TEST(Future, try) {
- class A {
- public:
- A(int x) : x_(x) {}
-
- int x() const {
- return x_;
- }
- private:
- int x_;
- };
-
- A a(5);
- Try<A> t_a(std::move(a));
-
- Try<void> t_void;
-
- EXPECT_EQ(5, t_a.value().x());
-}
-
TEST(Future, special) {
EXPECT_FALSE(std::is_copy_constructible<Future<int>>::value);
EXPECT_FALSE(std::is_copy_assignable<Future<int>>::value);
}
TEST(Future, then) {
- auto f = makeFuture<string>("0")
- .then([](){ return makeFuture<string>("1"); })
- .then([](Try<string>&& t) { return makeFuture(t.value() + ";2"); })
- .then([](const Try<string>&& t) { return makeFuture(t.value() + ";3"); })
- .then([](Try<string>& t) { return makeFuture(t.value() + ";4"); })
- .then([](const Try<string>& t) { return makeFuture(t.value() + ";5"); })
- .then([](Try<string> t) { return makeFuture(t.value() + ";6"); })
- .then([](const Try<string> t) { return makeFuture(t.value() + ";7"); })
- .then([](string&& s) { return makeFuture(s + ";8"); })
- .then([](const string&& s) { return makeFuture(s + ";9"); })
- .then([](string& s) { return makeFuture(s + ";10"); })
- .then([](const string& s) { return makeFuture(s + ";11"); })
- .then([](string s) { return makeFuture(s + ";12"); })
- .then([](const string s) { return makeFuture(s + ";13"); })
+ auto f = makeFuture<std::string>("0")
+ .then([](){
+ return makeFuture<std::string>("1"); })
+ .then([](Try<std::string>&& t) {
+ return makeFuture(t.value() + ";2"); })
+ .then([](const Try<std::string>&& t) {
+ return makeFuture(t.value() + ";3"); })
+ .then([](Try<std::string>& t) {
+ return makeFuture(t.value() + ";4"); })
+ .then([](const Try<std::string>& t) {
+ return makeFuture(t.value() + ";5"); })
+ .then([](Try<std::string> t) {
+ return makeFuture(t.value() + ";6"); })
+ .then([](const Try<std::string> t) {
+ return makeFuture(t.value() + ";7"); })
+ .then([](std::string&& s) {
+ return makeFuture(s + ";8"); })
+ .then([](const std::string&& s) {
+ return makeFuture(s + ";9"); })
+ .then([](std::string& s) {
+ return makeFuture(s + ";10"); })
+ .then([](const std::string& s) {
+ return makeFuture(s + ";11"); })
+ .then([](std::string s) {
+ return makeFuture(s + ";12"); })
+ .then([](const std::string s) {
+ return makeFuture(s + ";13"); })
;
EXPECT_EQ(f.value(), "1;2;3;4;5;6;7;8;9;10;11;12;13");
}
EXPECT_TRUE(flag); flag = false;
}
-static string doWorkStatic(Try<string>&& t) {
+static std::string doWorkStatic(Try<std::string>&& t) {
return t.value() + ";static";
}
TEST(Future, thenFunction) {
struct Worker {
- string doWork(Try<string>&& t) {
+ std::string doWork(Try<std::string>&& t) {
return t.value() + ";class";
}
- static string doWorkStatic(Try<string>&& t) {
+ static std::string doWorkStatic(Try<std::string>&& t) {
return t.value() + ";class-static";
}
} w;
- auto f = makeFuture<string>("start")
+ auto f = makeFuture<std::string>("start")
.then(doWorkStatic)
.then(Worker::doWorkStatic)
.then(&Worker::doWork, &w);
EXPECT_EQ(f.value(), "start;static;class-static;class");
}
-static Future<string> doWorkStaticFuture(Try<string>&& t) {
+static Future<std::string> doWorkStaticFuture(Try<std::string>&& t) {
return makeFuture(t.value() + ";static");
}
TEST(Future, thenFunctionFuture) {
struct Worker {
- Future<string> doWorkFuture(Try<string>&& t) {
+ Future<std::string> doWorkFuture(Try<std::string>&& t) {
return makeFuture(t.value() + ";class");
}
- static Future<string> doWorkStaticFuture(Try<string>&& t) {
+ static Future<std::string> doWorkStaticFuture(Try<std::string>&& t) {
return makeFuture(t.value() + ";class-static");
}
} w;
- auto f = makeFuture<string>("start")
+ auto f = makeFuture<std::string>("start")
.then(doWorkStaticFuture)
.then(Worker::doWorkStaticFuture)
.then(&Worker::doWorkFuture, &w);
}
TEST(Future, thenBindTry) {
- auto l = [](Try<string>&& t) {
+ auto l = [](Try<std::string>&& t) {
return makeFuture(t.value() + ";bind");
};
auto b = std::bind(l, std::placeholders::_1);
- auto f = makeFuture<string>("start").then(std::move(b));
+ auto f = makeFuture<std::string>("start").then(std::move(b));
EXPECT_EQ(f.value(), "start;bind");
}
TEST(Future, value) {
- auto f = makeFuture(unique_ptr<int>(new int(42)));
+ auto f = makeFuture(std::unique_ptr<int>(new int(42)));
auto up = std::move(f.value());
EXPECT_EQ(42, *up);
EXPECT_TYPE(makeFuture(), Future<void>);
}
-// Promise
-
-TEST(Promise, special) {
- EXPECT_FALSE(std::is_copy_constructible<Promise<int>>::value);
- EXPECT_FALSE(std::is_copy_assignable<Promise<int>>::value);
- EXPECT_TRUE(std::is_move_constructible<Promise<int>>::value);
- EXPECT_TRUE(std::is_move_assignable<Promise<int>>::value);
-}
-
-TEST(Promise, getFuture) {
- Promise<int> p;
- Future<int> f = p.getFuture();
- EXPECT_FALSE(f.isReady());
-}
-
-TEST(Promise, setValue) {
- Promise<int> fund;
- auto ffund = fund.getFuture();
- fund.setValue(42);
- EXPECT_EQ(42, ffund.value());
-
- struct Foo {
- string name;
- int value;
- };
-
- Promise<Foo> pod;
- auto fpod = pod.getFuture();
- Foo f = {"the answer", 42};
- pod.setValue(f);
- Foo f2 = fpod.value();
- EXPECT_EQ(f.name, f2.name);
- EXPECT_EQ(f.value, f2.value);
-
- pod = Promise<Foo>();
- fpod = pod.getFuture();
- pod.setValue(std::move(f2));
- Foo f3 = fpod.value();
- EXPECT_EQ(f.name, f3.name);
- EXPECT_EQ(f.value, f3.value);
-
- Promise<unique_ptr<int>> mov;
- auto fmov = mov.getFuture();
- mov.setValue(unique_ptr<int>(new int(42)));
- unique_ptr<int> ptr = std::move(fmov.value());
- EXPECT_EQ(42, *ptr);
-
- Promise<void> v;
- auto fv = v.getFuture();
- v.setValue();
- EXPECT_TRUE(fv.isReady());
-}
-
-TEST(Promise, setException) {
- {
- Promise<void> p;
- auto f = p.getFuture();
- p.setException(eggs);
- EXPECT_THROW(f.value(), eggs_t);
- }
- {
- Promise<void> p;
- auto f = p.getFuture();
- try {
- throw eggs;
- } catch (...) {
- p.setException(exception_wrapper(std::current_exception()));
- }
- EXPECT_THROW(f.value(), eggs_t);
- }
-}
-
-TEST(Promise, setWith) {
- {
- Promise<int> p;
- auto f = p.getFuture();
- p.setWith([] { return 42; });
- EXPECT_EQ(42, f.value());
- }
- {
- Promise<int> p;
- auto f = p.getFuture();
- p.setWith([]() -> int { throw eggs; });
- EXPECT_THROW(f.value(), eggs_t);
- }
-}
-
TEST(Future, finish) {
auto x = std::make_shared<int>(0);
{
EXPECT_EQ(7, f.value());
}
-TEST(Future, window) {
- // int -> Future<int>
- auto fn = [](vector<int> input, size_t window_size, size_t expect) {
- auto res = reduce(
- window(
- input,
- [](int i) { return makeFuture(i); },
- 2),
- 0,
- [](int sum, const Try<int>& b) {
- return sum + *b;
- }).get();
- EXPECT_EQ(expect, res);
- };
- {
- // 2 in-flight at a time
- vector<int> input = {1, 2, 3};
- fn(input, 2, 6);
- }
- {
- // 4 in-flight at a time
- vector<int> input = {1, 2, 3};
- fn(input, 4, 6);
- }
- {
- // empty inpt
- vector<int> input;
- fn(input, 1, 0);
- }
- {
- // int -> Future<void>
- auto res = reduce(
- window(
- std::vector<int>({1, 2, 3}),
- [](int i) { return makeFuture(); },
- 2),
- 0,
- [](int sum, const Try<void>& b) {
- EXPECT_TRUE(b.hasValue());
- return sum + 1;
- }).get();
- EXPECT_EQ(3, res);
- }
- {
- // string -> return Future<int>
- auto res = reduce(
- window(
- std::vector<std::string>{"1", "2", "3"},
- [](std::string s) { return makeFuture<int>(folly::to<int>(s)); },
- 2),
- 0,
- [](int sum, const Try<int>& b) {
- return sum + *b;
- }).get();
- EXPECT_EQ(6, res);
- }
-}
-
-TEST(Future, collectAll) {
- // returns a vector variant
- {
- vector<Promise<int>> promises(10);
- vector<Future<int>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- auto allf = collectAll(futures);
-
- random_shuffle(promises.begin(), promises.end());
- for (auto& p : promises) {
- EXPECT_FALSE(allf.isReady());
- p.setValue(42);
- }
-
- EXPECT_TRUE(allf.isReady());
- auto& results = allf.value();
- for (auto& t : results) {
- EXPECT_EQ(42, t.value());
- }
- }
-
- // check error semantics
- {
- vector<Promise<int>> promises(4);
- vector<Future<int>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- auto allf = collectAll(futures);
-
-
- promises[0].setValue(42);
- promises[1].setException(eggs);
-
- EXPECT_FALSE(allf.isReady());
-
- promises[2].setValue(42);
-
- EXPECT_FALSE(allf.isReady());
-
- promises[3].setException(eggs);
-
- EXPECT_TRUE(allf.isReady());
- EXPECT_FALSE(allf.getTry().hasException());
-
- auto& results = allf.value();
- EXPECT_EQ(42, results[0].value());
- EXPECT_TRUE(results[1].hasException());
- EXPECT_EQ(42, results[2].value());
- EXPECT_TRUE(results[3].hasException());
- }
-
- // check that futures are ready in then()
- {
- vector<Promise<void>> promises(10);
- vector<Future<void>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- auto allf = collectAll(futures)
- .then([](Try<vector<Try<void>>>&& ts) {
- for (auto& f : ts.value())
- f.value();
- });
-
- random_shuffle(promises.begin(), promises.end());
- for (auto& p : promises)
- p.setValue();
- EXPECT_TRUE(allf.isReady());
- }
-}
-
-TEST(Future, collect) {
- // success case
- {
- vector<Promise<int>> promises(10);
- vector<Future<int>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- auto allf = collect(futures);
-
- random_shuffle(promises.begin(), promises.end());
- for (auto& p : promises) {
- EXPECT_FALSE(allf.isReady());
- p.setValue(42);
- }
-
- EXPECT_TRUE(allf.isReady());
- for (auto i : allf.value()) {
- EXPECT_EQ(42, i);
- }
- }
-
- // failure case
- {
- vector<Promise<int>> promises(10);
- vector<Future<int>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- auto allf = collect(futures);
-
- random_shuffle(promises.begin(), promises.end());
- for (int i = 0; i < 10; i++) {
- if (i < 5) {
- // everthing goes well so far...
- EXPECT_FALSE(allf.isReady());
- promises[i].setValue(42);
- } else if (i == 5) {
- // short circuit with an exception
- EXPECT_FALSE(allf.isReady());
- promises[i].setException(eggs);
- EXPECT_TRUE(allf.isReady());
- } else if (i < 8) {
- // don't blow up on further values
- EXPECT_TRUE(allf.isReady());
- promises[i].setValue(42);
- } else {
- // don't blow up on further exceptions
- EXPECT_TRUE(allf.isReady());
- promises[i].setException(eggs);
- }
- }
-
- EXPECT_THROW(allf.value(), eggs_t);
- }
-
- // void futures success case
- {
- vector<Promise<void>> promises(10);
- vector<Future<void>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- auto allf = collect(futures);
-
- random_shuffle(promises.begin(), promises.end());
- for (auto& p : promises) {
- EXPECT_FALSE(allf.isReady());
- p.setValue();
- }
-
- EXPECT_TRUE(allf.isReady());
- }
-
- // void futures failure case
- {
- vector<Promise<void>> promises(10);
- vector<Future<void>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- auto allf = collect(futures);
-
- random_shuffle(promises.begin(), promises.end());
- for (int i = 0; i < 10; i++) {
- if (i < 5) {
- // everthing goes well so far...
- EXPECT_FALSE(allf.isReady());
- promises[i].setValue();
- } else if (i == 5) {
- // short circuit with an exception
- EXPECT_FALSE(allf.isReady());
- promises[i].setException(eggs);
- EXPECT_TRUE(allf.isReady());
- } else if (i < 8) {
- // don't blow up on further values
- EXPECT_TRUE(allf.isReady());
- promises[i].setValue();
- } else {
- // don't blow up on further exceptions
- EXPECT_TRUE(allf.isReady());
- promises[i].setException(eggs);
- }
- }
-
- EXPECT_THROW(allf.value(), eggs_t);
- }
-
- // move only compiles
- {
- vector<Promise<unique_ptr<int>>> promises(10);
- vector<Future<unique_ptr<int>>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- collect(futures);
- }
-
-}
-
-struct NotDefaultConstructible {
- NotDefaultConstructible() = delete;
- NotDefaultConstructible(int arg) : i(arg) {}
- int i;
-};
-
-// We have a specialized implementation for non-default-constructible objects
-// Ensure that it works and preserves order
-TEST(Future, collectNotDefaultConstructible) {
- vector<Promise<NotDefaultConstructible>> promises(10);
- vector<Future<NotDefaultConstructible>> futures;
- vector<int> indices(10);
- std::iota(indices.begin(), indices.end(), 0);
- random_shuffle(indices.begin(), indices.end());
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- auto allf = collect(futures);
-
- for (auto i : indices) {
- EXPECT_FALSE(allf.isReady());
- promises[i].setValue(NotDefaultConstructible(i));
- }
-
- EXPECT_TRUE(allf.isReady());
- int i = 0;
- for (auto val : allf.value()) {
- EXPECT_EQ(i, val.i);
- i++;
- }
-}
-
-TEST(Future, collectAny) {
- {
- vector<Promise<int>> promises(10);
- vector<Future<int>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- for (auto& f : futures) {
- EXPECT_FALSE(f.isReady());
- }
-
- auto anyf = collectAny(futures);
-
- /* futures were moved in, so these are invalid now */
- EXPECT_FALSE(anyf.isReady());
-
- promises[7].setValue(42);
- EXPECT_TRUE(anyf.isReady());
- auto& idx_fut = anyf.value();
-
- auto i = idx_fut.first;
- EXPECT_EQ(7, i);
-
- auto& f = idx_fut.second;
- EXPECT_EQ(42, f.value());
- }
-
- // error
- {
- vector<Promise<void>> promises(10);
- vector<Future<void>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- for (auto& f : futures) {
- EXPECT_FALSE(f.isReady());
- }
-
- auto anyf = collectAny(futures);
-
- EXPECT_FALSE(anyf.isReady());
-
- promises[3].setException(eggs);
- EXPECT_TRUE(anyf.isReady());
- EXPECT_TRUE(anyf.value().second.hasException());
- }
-
- // then()
- {
- vector<Promise<int>> promises(10);
- vector<Future<int>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- auto anyf = collectAny(futures)
- .then([](pair<size_t, Try<int>> p) {
- EXPECT_EQ(42, p.second.value());
- });
-
- promises[3].setValue(42);
- EXPECT_TRUE(anyf.isReady());
- }
-}
-
-
-TEST(when, already_completed) {
- {
- vector<Future<void>> fs;
- for (int i = 0; i < 10; i++)
- fs.push_back(makeFuture());
-
- collectAll(fs)
- .then([&](vector<Try<void>> ts) {
- EXPECT_EQ(fs.size(), ts.size());
- });
- }
- {
- vector<Future<int>> fs;
- for (int i = 0; i < 10; i++)
- fs.push_back(makeFuture(i));
-
- collectAny(fs)
- .then([&](pair<size_t, Try<int>> p) {
- EXPECT_EQ(p.first, p.second.value());
- });
- }
-}
-
-TEST(when, collectN) {
- vector<Promise<void>> promises(10);
- vector<Future<void>> futures;
-
- for (auto& p : promises)
- futures.push_back(p.getFuture());
-
- bool flag = false;
- size_t n = 3;
- collectN(futures, n)
- .then([&](vector<pair<size_t, Try<void>>> v) {
- flag = true;
- EXPECT_EQ(n, v.size());
- for (auto& tt : v)
- EXPECT_TRUE(tt.second.hasValue());
- });
-
- promises[0].setValue();
- EXPECT_FALSE(flag);
- promises[1].setValue();
- EXPECT_FALSE(flag);
- promises[2].setValue();
- EXPECT_TRUE(flag);
-}
-
-/* Ensure that we can compile when_{all,any} with folly::small_vector */
-TEST(when, small_vector) {
-
- static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<void>),
- "Futures should not be trivially copyable");
- static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<int>),
- "Futures should not be trivially copyable");
-
- using folly::small_vector;
- {
- small_vector<Future<void>> futures;
-
- for (int i = 0; i < 10; i++)
- futures.push_back(makeFuture());
-
- auto anyf = collectAny(futures);
- }
-
- {
- small_vector<Future<void>> futures;
-
- for (int i = 0; i < 10; i++)
- futures.push_back(makeFuture());
-
- auto allf = collectAll(futures);
- }
-}
-
-TEST(Future, collectAllVariadic) {
- Promise<bool> pb;
- Promise<int> pi;
- Future<bool> fb = pb.getFuture();
- Future<int> fi = pi.getFuture();
- bool flag = false;
- collectAll(std::move(fb), std::move(fi))
- .then([&](std::tuple<Try<bool>, Try<int>> tup) {
- flag = true;
- EXPECT_TRUE(std::get<0>(tup).hasValue());
- EXPECT_EQ(std::get<0>(tup).value(), true);
- EXPECT_TRUE(std::get<1>(tup).hasValue());
- EXPECT_EQ(std::get<1>(tup).value(), 42);
- });
- pb.setValue(true);
- EXPECT_FALSE(flag);
- pi.setValue(42);
- EXPECT_TRUE(flag);
-}
-
-TEST(Future, collectAllVariadicReferences) {
- Promise<bool> pb;
- Promise<int> pi;
- Future<bool> fb = pb.getFuture();
- Future<int> fi = pi.getFuture();
- bool flag = false;
- collectAll(fb, fi)
- .then([&](std::tuple<Try<bool>, Try<int>> tup) {
- flag = true;
- EXPECT_TRUE(std::get<0>(tup).hasValue());
- EXPECT_EQ(std::get<0>(tup).value(), true);
- EXPECT_TRUE(std::get<1>(tup).hasValue());
- EXPECT_EQ(std::get<1>(tup).value(), 42);
- });
- pb.setValue(true);
- EXPECT_FALSE(flag);
- pi.setValue(42);
- EXPECT_TRUE(flag);
-}
-
-TEST(Future, collectAll_none) {
- vector<Future<int>> fs;
- auto f = collectAll(fs);
- EXPECT_TRUE(f.isReady());
-}
-
TEST(Future, throwCaughtInImmediateThen) {
// Neither of these should throw "Promise already satisfied"
makeFuture().then(
});
}
-TEST(Future, waitImmediate) {
- makeFuture().wait();
- auto done = makeFuture(42).wait().value();
- EXPECT_EQ(42, done);
-
- vector<int> v{1,2,3};
- auto done_v = makeFuture(v).wait().value();
- EXPECT_EQ(v.size(), done_v.size());
- EXPECT_EQ(v, done_v);
-
- vector<Future<void>> v_f;
- v_f.push_back(makeFuture());
- v_f.push_back(makeFuture());
- auto done_v_f = collectAll(v_f).wait().value();
- EXPECT_EQ(2, done_v_f.size());
-
- vector<Future<bool>> v_fb;
- v_fb.push_back(makeFuture(true));
- v_fb.push_back(makeFuture(false));
- auto fut = collectAll(v_fb);
- auto done_v_fb = std::move(fut.wait().value());
- EXPECT_EQ(2, done_v_fb.size());
-}
-
-TEST(Future, wait) {
- Promise<int> p;
- Future<int> f = p.getFuture();
- std::atomic<bool> flag{false};
- std::atomic<int> result{1};
- std::atomic<std::thread::id> id;
-
- std::thread t([&](Future<int>&& tf){
- auto n = tf.then([&](Try<int> && t) {
- id = std::this_thread::get_id();
- return t.value();
- });
- flag = true;
- result.store(n.wait().value());
- },
- std::move(f)
- );
- while(!flag){}
- EXPECT_EQ(result.load(), 1);
- p.setValue(42);
- t.join();
- // validate that the callback ended up executing in this thread, which
- // is more to ensure that this test actually tests what it should
- EXPECT_EQ(id, std::this_thread::get_id());
- EXPECT_EQ(result.load(), 42);
-}
-
-struct MoveFlag {
- MoveFlag() = default;
- MoveFlag(const MoveFlag&) = delete;
- MoveFlag(MoveFlag&& other) noexcept {
- other.moved = true;
- }
- bool moved{false};
-};
-
-TEST(Future, waitReplacesSelf) {
- // wait
- {
- // lvalue
- auto f1 = makeFuture(MoveFlag());
- f1.wait();
- EXPECT_FALSE(f1.value().moved);
-
- // rvalue
- auto f2 = makeFuture(MoveFlag()).wait();
- EXPECT_FALSE(f2.value().moved);
- }
-
- // wait(Duration)
- {
- // lvalue
- auto f1 = makeFuture(MoveFlag());
- f1.wait(milliseconds(1));
- EXPECT_FALSE(f1.value().moved);
-
- // rvalue
- auto f2 = makeFuture(MoveFlag()).wait(milliseconds(1));
- EXPECT_FALSE(f2.value().moved);
- }
-
- // waitVia
- {
- folly::EventBase eb;
- // lvalue
- auto f1 = makeFuture(MoveFlag());
- f1.waitVia(&eb);
- EXPECT_FALSE(f1.value().moved);
-
- // rvalue
- auto f2 = makeFuture(MoveFlag()).waitVia(&eb);
- EXPECT_FALSE(f2.value().moved);
- }
-}
-
-TEST(Future, waitWithDuration) {
- {
- Promise<int> p;
- Future<int> f = p.getFuture();
- f.wait(milliseconds(1));
- EXPECT_FALSE(f.isReady());
- p.setValue(1);
- EXPECT_TRUE(f.isReady());
- }
- {
- Promise<int> p;
- Future<int> f = p.getFuture();
- p.setValue(1);
- f.wait(milliseconds(1));
- EXPECT_TRUE(f.isReady());
- }
- {
- vector<Future<bool>> v_fb;
- v_fb.push_back(makeFuture(true));
- v_fb.push_back(makeFuture(false));
- auto f = collectAll(v_fb);
- f.wait(milliseconds(1));
- EXPECT_TRUE(f.isReady());
- EXPECT_EQ(2, f.value().size());
- }
- {
- vector<Future<bool>> v_fb;
- Promise<bool> p1;
- Promise<bool> p2;
- v_fb.push_back(p1.getFuture());
- v_fb.push_back(p2.getFuture());
- auto f = collectAll(v_fb);
- f.wait(milliseconds(1));
- EXPECT_FALSE(f.isReady());
- p1.setValue(true);
- EXPECT_FALSE(f.isReady());
- p2.setValue(true);
- EXPECT_TRUE(f.isReady());
- }
- {
- auto f = makeFuture().wait(milliseconds(1));
- EXPECT_TRUE(f.isReady());
- }
-
- {
- Promise<void> p;
- auto start = std::chrono::steady_clock::now();
- auto f = p.getFuture().wait(milliseconds(100));
- auto elapsed = std::chrono::steady_clock::now() - start;
- EXPECT_GE(elapsed, milliseconds(100));
- EXPECT_FALSE(f.isReady());
- p.setValue();
- EXPECT_TRUE(f.isReady());
- }
-
- {
- // Try to trigger the race where the resultant Future is not yet complete
- // even if we didn't hit the timeout, and make sure we deal with it properly
- Promise<void> p;
- folly::Baton<> b;
- auto t = std::thread([&]{
- b.post();
- /* sleep override */ std::this_thread::sleep_for(milliseconds(100));
- p.setValue();
- });
- b.wait();
- auto f = p.getFuture().wait(std::chrono::seconds(3600));
- EXPECT_TRUE(f.isReady());
- t.join();
- }
-}
-
-class DummyDrivableExecutor : public DrivableExecutor {
- public:
- void add(Func f) override {}
- void drive() override { ran = true; }
- bool ran{false};
-};
-
-TEST(Future, getVia) {
- {
- // non-void
- ManualExecutor x;
- auto f = via(&x).then([]{ return true; });
- EXPECT_TRUE(f.getVia(&x));
- }
-
- {
- // void
- ManualExecutor x;
- auto f = via(&x).then();
- f.getVia(&x);
- }
-
- {
- DummyDrivableExecutor x;
- auto f = makeFuture(true);
- EXPECT_TRUE(f.getVia(&x));
- EXPECT_FALSE(x.ran);
- }
-}
-
-TEST(Future, waitVia) {
- {
- ManualExecutor x;
- auto f = via(&x).then();
- EXPECT_FALSE(f.isReady());
- f.waitVia(&x);
- EXPECT_TRUE(f.isReady());
- }
-
- {
- // try rvalue as well
- ManualExecutor x;
- auto f = via(&x).then().waitVia(&x);
- EXPECT_TRUE(f.isReady());
- }
-
- {
- DummyDrivableExecutor x;
- makeFuture(true).waitVia(&x);
- EXPECT_FALSE(x.ran);
- }
-}
-
-TEST(Future, viaRaces) {
- ManualExecutor x;
- Promise<void> 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; });
- });
-
- std::thread t2([&] {
- p.setValue();
- });
-
- while (!done) x.run();
- t1.join();
- t2.join();
-}
-
-TEST(Future, getFuture_after_setValue) {
+TEST(Future, getFutureAfterSetValue) {
Promise<int> p;
p.setValue(42);
EXPECT_EQ(42, p.getFuture().value());
}
-TEST(Future, getFuture_after_setException) {
+TEST(Future, getFutureAfterSetException) {
Promise<void> p;
p.setWith([]() -> void { throw std::logic_error("foo"); });
EXPECT_THROW(p.getFuture().value(), std::logic_error);
t1.join();
}
-class TestData : public RequestData {
- public:
- explicit TestData(int data) : data_(data) {}
- virtual ~TestData() {}
- int data_;
-};
-
-TEST(Future, context) {
-
- // Start a new context
- RequestContext::create();
-
- EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
-
- // Set some test data
- RequestContext::get()->setContextData(
- "test",
- std::unique_ptr<TestData>(new TestData(10)));
-
- // Start a future
- Promise<void> p;
- auto future = p.getFuture().then([&]{
- // Check that the context followed the future
- EXPECT_TRUE(RequestContext::get() != nullptr);
- auto a = dynamic_cast<TestData*>(
- RequestContext::get()->getContextData("test"));
- auto data = a->data_;
- EXPECT_EQ(10, data);
- });
-
- // Clear the context
- RequestContext::setContext(nullptr);
-
- EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
-
- // Fulfill the promise
- p.setValue();
-}
-
-
-// This only fails about 1 in 1k times when the bug is present :(
-TEST(Future, t5506504) {
- ThreadExecutor x;
-
- auto fn = [&x]{
- auto promises = std::make_shared<vector<Promise<void>>>(4);
- 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 of handling of a circular dependency. It's never recommended
// to have one because of possible memory leaks. Here we test that
// we can handle freeing of the Future while it is running.
p.setValue(2);
EXPECT_EQ(f.get(), 5);
}
-
-TEST(Future, via_then_get_was_racy) {
- ThreadExecutor x;
- std::unique_ptr<int> val = folly::via(&x)
- .then([] { return folly::make_unique<int>(42); })
- .get();
- ASSERT_TRUE(!!val);
- EXPECT_EQ(42, *val);
-}
-
-TEST(Future, ensure) {
- size_t count = 0;
- auto cob = [&]{ count++; };
- auto f = makeFuture(42)
- .ensure(cob)
- .then([](int) { throw std::runtime_error("ensure"); })
- .ensure(cob);
-
- EXPECT_THROW(f.get(), std::runtime_error);
- EXPECT_EQ(2, count);
-}
-
-TEST(Future, willEqual) {
- //both p1 and p2 already fulfilled
- {
- Promise<int> p1;
- Promise<int> p2;
- p1.setValue(27);
- p2.setValue(27);
- auto f1 = p1.getFuture();
- auto f2 = p2.getFuture();
- EXPECT_TRUE(f1.willEqual(f2).get());
- }{
- Promise<int> p1;
- Promise<int> p2;
- p1.setValue(27);
- p2.setValue(36);
- auto f1 = p1.getFuture();
- auto f2 = p2.getFuture();
- EXPECT_FALSE(f1.willEqual(f2).get());
- }
- //both p1 and p2 not yet fulfilled
- {
- Promise<int> p1;
- Promise<int> p2;
- auto f1 = p1.getFuture();
- auto f2 = p2.getFuture();
- auto f3 = f1.willEqual(f2);
- p1.setValue(27);
- p2.setValue(27);
- EXPECT_TRUE(f3.get());
- }{
- Promise<int> p1;
- Promise<int> p2;
- auto f1 = p1.getFuture();
- auto f2 = p2.getFuture();
- auto f3 = f1.willEqual(f2);
- p1.setValue(27);
- p2.setValue(36);
- EXPECT_FALSE(f3.get());
- }
- //p1 already fulfilled, p2 not yet fulfilled
- {
- Promise<int> p1;
- Promise<int> p2;
- p1.setValue(27);
- auto f1 = p1.getFuture();
- auto f2 = p2.getFuture();
- auto f3 = f1.willEqual(f2);
- p2.setValue(27);
- EXPECT_TRUE(f3.get());
- }{
- Promise<int> p1;
- Promise<int> p2;
- p1.setValue(27);
- auto f1 = p1.getFuture();
- auto f2 = p2.getFuture();
- auto f3 = f1.willEqual(f2);
- p2.setValue(36);
- EXPECT_FALSE(f3.get());
- }
- //p2 already fulfilled, p1 not yet fulfilled
- {
- Promise<int> p1;
- Promise<int> p2;
- p2.setValue(27);
- auto f1 = p1.getFuture();
- auto f2 = p2.getFuture();
- auto f3 = f1.willEqual(f2);
- p1.setValue(27);
- EXPECT_TRUE(f3.get());
- }{
- Promise<int> p1;
- Promise<int> p2;
- p2.setValue(36);
- auto f1 = p1.getFuture();
- auto f2 = p2.getFuture();
- auto f3 = f1.willEqual(f2);
- p1.setValue(27);
- EXPECT_FALSE(f3.get());
- }
-}
-
-// Unwrap tests.
-
-// A simple scenario for the unwrap call, when the promise was fulfilled
-// before calling to unwrap.
-TEST(Future, Unwrap_SimpleScenario) {
- Future<int> encapsulated_future = makeFuture(5484);
- Future<Future<int>> future = makeFuture(std::move(encapsulated_future));
- EXPECT_EQ(5484, future.unwrap().value());
-}
-
-// Makes sure that unwrap() works when chaning Future's commands.
-TEST(Future, Unwrap_ChainCommands) {
- Future<Future<int>> future = makeFuture(makeFuture(5484));
- auto unwrapped = future.unwrap().then([](int i){ return i; });
- EXPECT_EQ(5484, unwrapped.value());
-}
-
-// Makes sure that the unwrap call also works when the promise was not yet
-// fulfilled, and that the returned Future<T> becomes ready once the promise
-// is fulfilled.
-TEST(Future, Unwrap_FutureNotReady) {
- Promise<Future<int>> p;
- Future<Future<int>> future = p.getFuture();
- Future<int> unwrapped = future.unwrap();
- // Sanity - should not be ready before the promise is fulfilled.
- ASSERT_FALSE(unwrapped.isReady());
- // Fulfill the promise and make sure the unwrapped future is now ready.
- p.setValue(makeFuture(5484));
- ASSERT_TRUE(unwrapped.isReady());
- EXPECT_EQ(5484, unwrapped.value());
-}
-
-TEST(Reduce, Basic) {
- auto makeFutures = [](int count) {
- std::vector<Future<int>> fs;
- for (int i = 1; i <= count; ++i) {
- fs.emplace_back(makeFuture(i));
- }
- return fs;
- };
-
- // Empty (Try)
- {
- auto fs = makeFutures(0);
-
- Future<double> f1 = reduce(fs, 1.2,
- [](double a, Try<int>&& b){
- return a + *b + 0.1;
- });
- EXPECT_EQ(1.2, f1.get());
- }
-
- // One (Try)
- {
- auto fs = makeFutures(1);
-
- Future<double> f1 = reduce(fs, 0.0,
- [](double a, Try<int>&& b){
- return a + *b + 0.1;
- });
- EXPECT_EQ(1.1, f1.get());
- }
-
- // Returning values (Try)
- {
- auto fs = makeFutures(3);
-
- Future<double> f1 = reduce(fs, 0.0,
- [](double a, Try<int>&& b){
- return a + *b + 0.1;
- });
- EXPECT_EQ(6.3, f1.get());
- }
-
- // Returning values
- {
- auto fs = makeFutures(3);
-
- Future<double> f1 = reduce(fs, 0.0,
- [](double a, int&& b){
- return a + b + 0.1;
- });
- EXPECT_EQ(6.3, f1.get());
- }
-
- // Returning futures (Try)
- {
- auto fs = makeFutures(3);
-
- Future<double> f2 = reduce(fs, 0.0,
- [](double a, Try<int>&& b){
- return makeFuture<double>(a + *b + 0.1);
- });
- EXPECT_EQ(6.3, f2.get());
- }
-
- // Returning futures
- {
- auto fs = makeFutures(3);
-
- Future<double> f2 = reduce(fs, 0.0,
- [](double a, int&& b){
- return makeFuture<double>(a + b + 0.1);
- });
- EXPECT_EQ(6.3, f2.get());
- }
-}
-
-TEST(Reduce, Chain) {
- auto makeFutures = [](int count) {
- std::vector<Future<int>> fs;
- for (int i = 1; i <= count; ++i) {
- fs.emplace_back(makeFuture(i));
- }
- return fs;
- };
-
- {
- auto f = collectAll(makeFutures(3)).reduce(0, [](int a, Try<int>&& b){
- return a + *b;
- });
- EXPECT_EQ(6, f.get());
- }
- {
- auto f = collect(makeFutures(3)).reduce(0, [](int a, int&& b){
- return a + b;
- });
- EXPECT_EQ(6, f.get());
- }
-}
-
-TEST(Reduce, UnorderedReduce) {
- {
- std::vector<Future<int>> fs;
- fs.push_back(makeFuture(1));
- fs.push_back(makeFuture(2));
- fs.push_back(makeFuture(3));
-
- Future<double> f = unorderedReduce(fs.begin(), fs.end(), 0.0,
- [](double a, int&& b){
- return double(b);
- });
- EXPECT_EQ(3.0, f.get());
- }
- {
- Promise<int> p1;
- Promise<int> p2;
- Promise<int> p3;
-
- std::vector<Future<int>> fs;
- fs.push_back(p1.getFuture());
- fs.push_back(p2.getFuture());
- fs.push_back(p3.getFuture());
-
- Future<double> f = unorderedReduce(fs.begin(), fs.end(), 0.0,
- [](double a, int&& b){
- return double(b);
- });
- p3.setValue(3);
- p2.setValue(2);
- p1.setValue(1);
- EXPECT_EQ(1.0, f.get());
- }
-}
-
-TEST(Reduce, UnorderedReduceException) {
- Promise<int> p1;
- Promise<int> p2;
- Promise<int> p3;
-
- std::vector<Future<int>> fs;
- fs.push_back(p1.getFuture());
- fs.push_back(p2.getFuture());
- fs.push_back(p3.getFuture());
-
- Future<double> f = unorderedReduce(fs.begin(), fs.end(), 0.0,
- [](double a, int&& b){
- return b + 0.0;
- });
- p3.setValue(3);
- p2.setException(exception_wrapper(std::runtime_error("blah")));
- p1.setValue(1);
- EXPECT_THROW(f.get(), std::runtime_error);
-}
-
-TEST(Map, Basic) {
- Promise<int> p1;
- Promise<int> p2;
- Promise<int> p3;
-
- std::vector<Future<int>> fs;
- fs.push_back(p1.getFuture());
- fs.push_back(p2.getFuture());
- fs.push_back(p3.getFuture());
-
- int c = 0;
- std::vector<Future<void>> fs2 = futures::map(fs, [&](int i){
- c += i;
- });
-
- // Ensure we call the callbacks as the futures complete regardless of order
- p2.setValue(1);
- EXPECT_EQ(1, c);
- p3.setValue(1);
- EXPECT_EQ(2, c);
- p1.setValue(1);
- EXPECT_EQ(3, c);
-
- EXPECT_TRUE(collect(fs2).isReady());
-}
-
-TEST(Promise, isFulfilled) {
- Promise<int> p;
-
- EXPECT_FALSE(p.isFulfilled());
- p.setValue(42);
- EXPECT_TRUE(p.isFulfilled());
-}
-
-TEST(Promise, isFulfilledWithFuture) {
- Promise<int> p;
- auto f = p.getFuture(); // so core_ will become null
-
- EXPECT_FALSE(p.isFulfilled());
- p.setValue(42); // after here
- EXPECT_TRUE(p.isFulfilled());
-}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+// amazing what things can go wrong if you include things in an unexpected
+// order.
+#include <folly/futures/Try.h>
+#include <folly/futures/Promise.h>
+#include <folly/futures/Future.h>
+
+TEST(Basic, compiles) {
+ EXPECT_TRUE(true);
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+#include <folly/futures/Promise.h>
+
+using namespace folly;
+
+TEST(Interrupt, raise) {
+ std::runtime_error eggs("eggs");
+ Promise<void> p;
+ p.setInterruptHandler([&](const exception_wrapper& e) {
+ EXPECT_THROW(e.throwException(), decltype(eggs));
+ });
+ p.getFuture().raise(eggs);
+}
+
+TEST(Interrupt, cancel) {
+ Promise<void> p;
+ p.setInterruptHandler([&](const exception_wrapper& e) {
+ EXPECT_THROW(e.throwException(), FutureCancellation);
+ });
+ p.getFuture().cancel();
+}
+
+TEST(Interrupt, handleThenInterrupt) {
+ Promise<int> p;
+ bool flag = false;
+ p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
+ p.getFuture().cancel();
+ EXPECT_TRUE(flag);
+}
+
+TEST(Interrupt, interruptThenHandle) {
+ Promise<int> p;
+ bool flag = false;
+ p.getFuture().cancel();
+ p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
+ EXPECT_TRUE(flag);
+}
+
+TEST(Interrupt, interruptAfterFulfilNoop) {
+ Promise<void> p;
+ bool flag = false;
+ p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
+ p.setValue();
+ p.getFuture().cancel();
+ EXPECT_FALSE(flag);
+}
+
+TEST(Interrupt, secondInterruptNoop) {
+ Promise<void> p;
+ int count = 0;
+ p.setInterruptHandler([&](const exception_wrapper& e) { count++; });
+ auto f = p.getFuture();
+ f.cancel();
+ f.cancel();
+ EXPECT_EQ(1, count);
+}
+++ /dev/null
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include <folly/futures/Future.h>
-#include <folly/futures/Promise.h>
-
-using namespace folly;
-using folly::exception_wrapper;
-
-TEST(Interrupts, raise) {
- std::runtime_error eggs("eggs");
- Promise<void> p;
- p.setInterruptHandler([&](const exception_wrapper& e) {
- EXPECT_THROW(e.throwException(), decltype(eggs));
- });
- p.getFuture().raise(eggs);
-}
-
-TEST(Interrupts, cancel) {
- Promise<void> p;
- p.setInterruptHandler([&](const exception_wrapper& e) {
- EXPECT_THROW(e.throwException(), FutureCancellation);
- });
- p.getFuture().cancel();
-}
-
-TEST(Interrupts, handleThenInterrupt) {
- Promise<int> p;
- bool flag = false;
- p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
- p.getFuture().cancel();
- EXPECT_TRUE(flag);
-}
-
-TEST(Interrupts, interruptThenHandle) {
- Promise<int> p;
- bool flag = false;
- p.getFuture().cancel();
- p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
- EXPECT_TRUE(flag);
-}
-
-TEST(Interrupts, interruptAfterFulfilNoop) {
- Promise<void> p;
- bool flag = false;
- p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
- p.setValue();
- p.getFuture().cancel();
- EXPECT_FALSE(flag);
-}
-
-TEST(Interrupts, secondInterruptNoop) {
- Promise<void> p;
- int count = 0;
- p.setInterruptHandler([&](const exception_wrapper& e) { count++; });
- auto f = p.getFuture();
- f.cancel();
- f.cancel();
- EXPECT_EQ(1, count);
-}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+using namespace folly;
+
+TEST(Map, basic) {
+ Promise<int> p1;
+ Promise<int> p2;
+ Promise<int> p3;
+
+ std::vector<Future<int>> fs;
+ fs.push_back(p1.getFuture());
+ fs.push_back(p2.getFuture());
+ fs.push_back(p3.getFuture());
+
+ int c = 0;
+ std::vector<Future<void>> fs2 = futures::map(fs, [&](int i){
+ c += i;
+ });
+
+ // Ensure we call the callbacks as the futures complete regardless of order
+ p2.setValue(1);
+ EXPECT_EQ(1, c);
+ p3.setValue(1);
+ EXPECT_EQ(2, c);
+ p1.setValue(1);
+ EXPECT_EQ(3, c);
+
+ EXPECT_TRUE(collect(fs2).isReady());
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+using namespace folly;
+
+TEST(Poll, ready) {
+ Promise<int> p;
+ auto f = p.getFuture();
+ p.setValue(42);
+ EXPECT_EQ(42, f.poll().value().value());
+}
+
+TEST(Poll, notReady) {
+ Promise<int> p;
+ auto f = p.getFuture();
+ EXPECT_FALSE(f.poll().hasValue());
+}
+
+TEST(Poll, exception) {
+ Promise<void> p;
+ auto f = p.getFuture();
+ p.setWith([] { throw std::runtime_error("Runtime"); });
+ EXPECT_TRUE(f.poll().value().hasException());
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+using namespace folly;
+using std::unique_ptr;
+using std::string;
+
+typedef FutureException eggs_t;
+static eggs_t eggs("eggs");
+
+TEST(Promise, special) {
+ EXPECT_FALSE(std::is_copy_constructible<Promise<int>>::value);
+ EXPECT_FALSE(std::is_copy_assignable<Promise<int>>::value);
+ EXPECT_TRUE(std::is_move_constructible<Promise<int>>::value);
+ EXPECT_TRUE(std::is_move_assignable<Promise<int>>::value);
+}
+
+TEST(Promise, getFuture) {
+ Promise<int> p;
+ Future<int> f = p.getFuture();
+ EXPECT_FALSE(f.isReady());
+}
+
+TEST(Promise, setValue) {
+ Promise<int> fund;
+ auto ffund = fund.getFuture();
+ fund.setValue(42);
+ EXPECT_EQ(42, ffund.value());
+
+ struct Foo {
+ string name;
+ int value;
+ };
+
+ Promise<Foo> pod;
+ auto fpod = pod.getFuture();
+ Foo f = {"the answer", 42};
+ pod.setValue(f);
+ Foo f2 = fpod.value();
+ EXPECT_EQ(f.name, f2.name);
+ EXPECT_EQ(f.value, f2.value);
+
+ pod = Promise<Foo>();
+ fpod = pod.getFuture();
+ pod.setValue(std::move(f2));
+ Foo f3 = fpod.value();
+ EXPECT_EQ(f.name, f3.name);
+ EXPECT_EQ(f.value, f3.value);
+
+ Promise<unique_ptr<int>> mov;
+ auto fmov = mov.getFuture();
+ mov.setValue(unique_ptr<int>(new int(42)));
+ unique_ptr<int> ptr = std::move(fmov.value());
+ EXPECT_EQ(42, *ptr);
+
+ Promise<void> v;
+ auto fv = v.getFuture();
+ v.setValue();
+ EXPECT_TRUE(fv.isReady());
+}
+
+TEST(Promise, setException) {
+ {
+ Promise<void> p;
+ auto f = p.getFuture();
+ p.setException(eggs);
+ EXPECT_THROW(f.value(), eggs_t);
+ }
+ {
+ Promise<void> p;
+ auto f = p.getFuture();
+ try {
+ throw eggs;
+ } catch (...) {
+ p.setException(exception_wrapper(std::current_exception()));
+ }
+ EXPECT_THROW(f.value(), eggs_t);
+ }
+}
+
+TEST(Promise, setWith) {
+ {
+ Promise<int> p;
+ auto f = p.getFuture();
+ p.setWith([] { return 42; });
+ EXPECT_EQ(42, f.value());
+ }
+ {
+ Promise<int> p;
+ auto f = p.getFuture();
+ p.setWith([]() -> int { throw eggs; });
+ EXPECT_THROW(f.value(), eggs_t);
+ }
+}
+
+TEST(Promise, isFulfilled) {
+ Promise<int> p;
+
+ EXPECT_FALSE(p.isFulfilled());
+ p.setValue(42);
+ EXPECT_TRUE(p.isFulfilled());
+}
+
+TEST(Promise, isFulfilledWithFuture) {
+ Promise<int> p;
+ auto f = p.getFuture(); // so core_ will become null
+
+ EXPECT_FALSE(p.isFulfilled());
+ p.setValue(42); // after here
+ EXPECT_TRUE(p.isFulfilled());
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+using namespace folly;
+
+TEST(Reduce, basic) {
+ auto makeFutures = [](int count) {
+ std::vector<Future<int>> fs;
+ for (int i = 1; i <= count; ++i) {
+ fs.emplace_back(makeFuture(i));
+ }
+ return fs;
+ };
+
+ // Empty (Try)
+ {
+ auto fs = makeFutures(0);
+
+ Future<double> f1 = reduce(fs, 1.2,
+ [](double a, Try<int>&& b){
+ return a + *b + 0.1;
+ });
+ EXPECT_EQ(1.2, f1.get());
+ }
+
+ // One (Try)
+ {
+ auto fs = makeFutures(1);
+
+ Future<double> f1 = reduce(fs, 0.0,
+ [](double a, Try<int>&& b){
+ return a + *b + 0.1;
+ });
+ EXPECT_EQ(1.1, f1.get());
+ }
+
+ // Returning values (Try)
+ {
+ auto fs = makeFutures(3);
+
+ Future<double> f1 = reduce(fs, 0.0,
+ [](double a, Try<int>&& b){
+ return a + *b + 0.1;
+ });
+ EXPECT_EQ(6.3, f1.get());
+ }
+
+ // Returning values
+ {
+ auto fs = makeFutures(3);
+
+ Future<double> f1 = reduce(fs, 0.0,
+ [](double a, int&& b){
+ return a + b + 0.1;
+ });
+ EXPECT_EQ(6.3, f1.get());
+ }
+
+ // Returning futures (Try)
+ {
+ auto fs = makeFutures(3);
+
+ Future<double> f2 = reduce(fs, 0.0,
+ [](double a, Try<int>&& b){
+ return makeFuture<double>(a + *b + 0.1);
+ });
+ EXPECT_EQ(6.3, f2.get());
+ }
+
+ // Returning futures
+ {
+ auto fs = makeFutures(3);
+
+ Future<double> f2 = reduce(fs, 0.0,
+ [](double a, int&& b){
+ return makeFuture<double>(a + b + 0.1);
+ });
+ EXPECT_EQ(6.3, f2.get());
+ }
+}
+
+TEST(Reduce, chain) {
+ auto makeFutures = [](int count) {
+ std::vector<Future<int>> fs;
+ for (int i = 1; i <= count; ++i) {
+ fs.emplace_back(makeFuture(i));
+ }
+ return fs;
+ };
+
+ {
+ auto f = collectAll(makeFutures(3)).reduce(0, [](int a, Try<int>&& b){
+ return a + *b;
+ });
+ EXPECT_EQ(6, f.get());
+ }
+ {
+ auto f = collect(makeFutures(3)).reduce(0, [](int a, int&& b){
+ return a + b;
+ });
+ EXPECT_EQ(6, f.get());
+ }
+}
+
+TEST(Reduce, unorderedReduce) {
+ {
+ std::vector<Future<int>> fs;
+ fs.push_back(makeFuture(1));
+ fs.push_back(makeFuture(2));
+ fs.push_back(makeFuture(3));
+
+ Future<double> f = unorderedReduce(fs.begin(), fs.end(), 0.0,
+ [](double a, int&& b){
+ return double(b);
+ });
+ EXPECT_EQ(3.0, f.get());
+ }
+ {
+ Promise<int> p1;
+ Promise<int> p2;
+ Promise<int> p3;
+
+ std::vector<Future<int>> fs;
+ fs.push_back(p1.getFuture());
+ fs.push_back(p2.getFuture());
+ fs.push_back(p3.getFuture());
+
+ Future<double> f = unorderedReduce(fs.begin(), fs.end(), 0.0,
+ [](double a, int&& b){
+ return double(b);
+ });
+ p3.setValue(3);
+ p2.setValue(2);
+ p1.setValue(1);
+ EXPECT_EQ(1.0, f.get());
+ }
+}
+
+TEST(Reduce, unorderedReduceException) {
+ Promise<int> p1;
+ Promise<int> p2;
+ Promise<int> p3;
+
+ std::vector<Future<int>> fs;
+ fs.push_back(p1.getFuture());
+ fs.push_back(p2.getFuture());
+ fs.push_back(p3.getFuture());
+
+ Future<double> f = unorderedReduce(fs.begin(), fs.end(), 0.0,
+ [](double a, int&& b){
+ return b + 0.0;
+ });
+ p3.setValue(3);
+ p2.setException(exception_wrapper(std::runtime_error("blah")));
+ p1.setValue(1);
+ EXPECT_THROW(f.get(), std::runtime_error);
+}
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <folly/futures/SharedPromise.h>
+
#include <gtest/gtest.h>
+#include <folly/futures/SharedPromise.h>
+
using namespace folly;
-TEST(SharedPromise, SetGet) {
+TEST(SharedPromise, setGet) {
SharedPromise<int> p;
p.setValue(1);
auto f1 = p.getFuture();
EXPECT_EQ(1, f1.value());
EXPECT_EQ(1, f2.value());
}
-TEST(SharedPromise, GetSet) {
+TEST(SharedPromise, getSet) {
SharedPromise<int> p;
auto f1 = p.getFuture();
auto f2 = p.getFuture();
EXPECT_EQ(1, f2.value());
}
-TEST(SharedPromise, GetSetGet) {
+TEST(SharedPromise, getSetGet) {
SharedPromise<int> p;
auto f1 = p.getFuture();
p.setValue(1);
EXPECT_EQ(1, f2.value());
}
-TEST(SharedPromise, Reset) {
+TEST(SharedPromise, reset) {
SharedPromise<int> p;
auto f1 = p.getFuture();
EXPECT_EQ(2, f2.value());
}
-TEST(SharedPromise, GetMoveSet) {
+TEST(SharedPromise, getMoveSet) {
SharedPromise<int> p;
auto f = p.getFuture();
auto p2 = std::move(p);
EXPECT_EQ(1, f.value());
}
-TEST(SharedPromise, SetMoveGet) {
+TEST(SharedPromise, setMoveGet) {
SharedPromise<int> p;
p.setValue(1);
auto p2 = std::move(p);
EXPECT_EQ(1, f.value());
}
-TEST(SharedPromise, MoveSetGet) {
+TEST(SharedPromise, moveSetGet) {
SharedPromise<int> p;
auto p2 = std::move(p);
p2.setValue(1);
EXPECT_EQ(1, f.value());
}
-TEST(SharedPromise, MoveGetSet) {
+TEST(SharedPromise, moveGetSet) {
SharedPromise<int> p;
auto p2 = std::move(p);
auto f = p2.getFuture();
EXPECT_EQ(1, f.value());
}
-TEST(SharedPromise, MoveMove) {
+TEST(SharedPromise, moveMove) {
SharedPromise<std::shared_ptr<int>> p;
auto f1 = p.getFuture();
auto f2 = p.getFuture();
+++ /dev/null
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include <folly/futures/Future.h>
-
-using namespace folly;
-
-TEST(Sugar, pollReady) {
- Promise<int> p;
- auto f = p.getFuture();
- p.setValue(42);
- EXPECT_EQ(42, f.poll().value().value());
-}
-
-TEST(Sugar, pollNotReady) {
- Promise<int> p;
- auto f = p.getFuture();
- EXPECT_FALSE(f.poll().hasValue());
-}
-
-TEST(Sugar, pollException) {
- Promise<void> p;
- auto f = p.getFuture();
- p.setWith([] { throw std::runtime_error("Runtime"); });
- EXPECT_TRUE(f.poll().value().hasException());
-}
-
-TEST(Sugar, filterTrue) {
- EXPECT_EQ(42, makeFuture(42).filter([](int){ return true; }).get());
-}
-
-TEST(Sugar, filterFalse) {
- EXPECT_THROW(makeFuture(42).filter([](int){ return false; }).get(),
- folly::PredicateDoesNotObtain);
-}
-
-TEST(Sugar, filterMoveonly) {
- EXPECT_EQ(42,
- *makeFuture(folly::make_unique<int>(42))
- .filter([](std::unique_ptr<int> const&) { return true; })
- .get());
-}
--- /dev/null
+// This file is @generated by then_compile_test.rb. Do not edit directly.
+
+#include <folly/futures/test/ThenCompileTest.h>
+
+using namespace folly;
+
+TEST(Basic, thenVariants) {
+ SomeClass anObject;
+
+ {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>&&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&&>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A>&&){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A> const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A> const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A> const&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A> const&>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A> const&){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A>){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A>&){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A&&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&&>());}
+ {Future<B> f = someFuture<A>().then([&](A&&){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A const&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A const&>());}
+ {Future<B> f = someFuture<A>().then([&](A const&){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A>());}
+ {Future<B> f = someFuture<A>().then([&](A){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&>());}
+ {Future<B> f = someFuture<A>().then([&](A&){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then([&](){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>&&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&&>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A>&&){return B();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A> const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A> const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A> const&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A> const&>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A> const&){return B();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A>){return B();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A>&){return B();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<B, A&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A&&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<B, A&&>());}
+ {Future<B> f = someFuture<A>().then([&](A&&){return B();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<B, A const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A const&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<B, A const&>());}
+ {Future<B> f = someFuture<A>().then([&](A const&){return B();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<B, A>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<B, A>());}
+ {Future<B> f = someFuture<A>().then([&](A){return B();});}
+ {Future<B> f = someFuture<A>().then(&aFunction<B, A&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A&>, &anObject);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<B, A&>());}
+ {Future<B> f = someFuture<A>().then([&](A&){return B();});}
+ {Future<B> f = someFuture<A>().then([&](){return B();});}
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+#include <memory>
+
+namespace folly {
+
+typedef std::unique_ptr<int> A;
+struct B {};
+
+template <class T>
+using EnableIfFuture = typename std::enable_if<isFuture<T>::value>::type;
+
+template <class T>
+using EnableUnlessFuture = typename std::enable_if<!isFuture<T>::value>::type;
+
+template <class T>
+Future<T> someFuture() {
+ return makeFuture(T());
+}
+
+template <class Ret, class... Params>
+typename std::enable_if<isFuture<Ret>::value, Ret>::type
+aFunction(Params...) {
+ typedef typename Ret::value_type T;
+ return makeFuture(T());
+}
+
+template <class Ret, class... Params>
+typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+aFunction(Params...) {
+ return Ret();
+}
+
+template <class Ret, class... Params>
+std::function<Ret(Params...)>
+aStdFunction(
+ typename std::enable_if<!isFuture<Ret>::value, bool>::type = false) {
+ return [](Params...) -> Ret { return Ret(); };
+}
+
+template <class Ret, class... Params>
+std::function<Ret(Params...)>
+aStdFunction(typename std::enable_if<isFuture<Ret>::value, bool>::type = true) {
+ typedef typename Ret::value_type T;
+ return [](Params...) -> Future<T> { return makeFuture(T()); };
+}
+
+class SomeClass {
+public:
+ template <class Ret, class... Params>
+ static
+ typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+ aStaticMethod(Params...) {
+ return Ret();
+ }
+
+ template <class Ret, class... Params>
+ static
+ typename std::enable_if<isFuture<Ret>::value, Ret>::type
+ aStaticMethod(Params...) {
+ typedef typename Ret::value_type T;
+ return makeFuture(T());
+ }
+
+ template <class Ret, class... Params>
+ typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+ aMethod(Params...) {
+ return Ret();
+ }
+
+ template <class Ret, class... Params>
+ typename std::enable_if<isFuture<Ret>::value, Ret>::type
+ aMethod(Params...) {
+ typedef typename Ret::value_type T;
+ return makeFuture(T());
+ }
+};
+
+}
*/
#include <gtest/gtest.h>
-#include <thread>
#include <folly/futures/Future.h>
+#include <thread>
+
using namespace folly;
struct Widget {
EXPECT_EQ(future.value().moved_, 2);
}
-TEST(Then, TryConstRValueReference) {
+TEST(Then, tryConstRValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Try<Widget>&& t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, TryRValueReference) {
+TEST(Then, tryRValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Try<Widget>&& t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, TryLValueReference) {
+TEST(Then, tryLValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Try<Widget>& t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, TryConstLValueReference) {
+TEST(Then, tryConstLValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Try<Widget>& t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, TryValue) {
+TEST(Then, tryValue) {
auto future = makeFuture<Widget>(23).then(
[](Try<Widget> t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, TryConstValue) {
+TEST(Then, tryConstValue) {
auto future = makeFuture<Widget>(23).then(
[](const Try<Widget> t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, ConstRValueReference) {
+TEST(Then, constRValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Widget&& w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, RValueReference) {
+TEST(Then, rValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Widget&& w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, LValueReference) {
+TEST(Then, lValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Widget& w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, ConstLValueReference) {
+TEST(Then, constLValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Widget& w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, Value) {
+TEST(Then, value) {
auto future = makeFuture<Widget>(23).then(
[](Widget w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(future.value(), 23);
}
-TEST(Then, ConstValue) {
+TEST(Then, constValue) {
auto future = makeFuture<Widget>(23).then(
[](const Widget w) {
EXPECT_EQ(w.copied_, 0);
+++ /dev/null
-// This file is @generated by thens.rb. Do not edit directly.
-
-#include <folly/futures/test/Thens.h>
-
-TEST(Future, thenVariants) {
- SomeClass anObject;
- folly::Executor* anExecutor;
-
- {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>&&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&&>());}
- {Future<B> f = someFuture<A>().then([&](Try<A>&&){return someFuture<B>();});}
- {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A> const&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A> const&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A> const&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A> const&>());}
- {Future<B> f = someFuture<A>().then([&](Try<A> const&){return someFuture<B>();});}
- {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>>());}
- {Future<B> f = someFuture<A>().then([&](Try<A>){return someFuture<B>();});}
- {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&>());}
- {Future<B> f = someFuture<A>().then([&](Try<A>&){return someFuture<B>();});}
- {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A&&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&&>());}
- {Future<B> f = someFuture<A>().then([&](A&&){return someFuture<B>();});}
- {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A const&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A const&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A const&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A const&>());}
- {Future<B> f = someFuture<A>().then([&](A const&){return someFuture<B>();});}
- {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A>());}
- {Future<B> f = someFuture<A>().then([&](A){return someFuture<B>();});}
- {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&>());}
- {Future<B> f = someFuture<A>().then([&](A&){return someFuture<B>();});}
- {Future<B> f = someFuture<A>().then([&](){return someFuture<B>();});}
- {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>&&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&&>());}
- {Future<B> f = someFuture<A>().then([&](Try<A>&&){return B();});}
- {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A> const&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A> const&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A> const&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A> const&>());}
- {Future<B> f = someFuture<A>().then([&](Try<A> const&){return B();});}
- {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>>());}
- {Future<B> f = someFuture<A>().then([&](Try<A>){return B();});}
- {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&>());}
- {Future<B> f = someFuture<A>().then([&](Try<A>&){return B();});}
- {Future<B> f = someFuture<A>().then(&aFunction<B, A&&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A&&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<B, A&&>());}
- {Future<B> f = someFuture<A>().then([&](A&&){return B();});}
- {Future<B> f = someFuture<A>().then(&aFunction<B, A const&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A const&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A const&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<B, A const&>());}
- {Future<B> f = someFuture<A>().then([&](A const&){return B();});}
- {Future<B> f = someFuture<A>().then(&aFunction<B, A>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<B, A>());}
- {Future<B> f = someFuture<A>().then([&](A){return B();});}
- {Future<B> f = someFuture<A>().then(&aFunction<B, A&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&>);}
- {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A&>, &anObject);}
- {Future<B> f = someFuture<A>().then(aStdFunction<B, A&>());}
- {Future<B> f = someFuture<A>().then([&](A&){return B();});}
- {Future<B> f = someFuture<A>().then([&](){return B();});}
-}
-
+++ /dev/null
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-#include <gtest/gtest.h>
-#include <memory>
-#include <folly/futures/Future.h>
-#include <folly/Executor.h>
-
-using namespace folly;
-using namespace std;
-using namespace testing;
-
-typedef unique_ptr<int> A;
-struct B {};
-
-template <class T>
-using EnableIfFuture = typename std::enable_if<isFuture<T>::value>::type;
-
-template <class T>
-using EnableUnlessFuture = typename std::enable_if<!isFuture<T>::value>::type;
-
-template <class T>
-Future<T> someFuture() {
- return makeFuture(T());
-}
-
-template <class Ret, class... Params>
-typename std::enable_if<isFuture<Ret>::value, Ret>::type
-aFunction(Params...) {
- typedef typename Ret::value_type T;
- return makeFuture(T());
-}
-
-template <class Ret, class... Params>
-typename std::enable_if<!isFuture<Ret>::value, Ret>::type
-aFunction(Params...) {
- return Ret();
-}
-
-template <class Ret, class... Params>
-std::function<Ret(Params...)>
-aStdFunction(
- typename std::enable_if<!isFuture<Ret>::value, bool>::type = false) {
- return [](Params...) -> Ret { return Ret(); };
-}
-
-template <class Ret, class... Params>
-std::function<Ret(Params...)>
-aStdFunction(typename std::enable_if<isFuture<Ret>::value, bool>::type = true) {
- typedef typename Ret::value_type T;
- return [](Params...) -> Future<T> { return makeFuture(T()); };
-}
-
-class SomeClass {
-public:
- template <class Ret, class... Params>
- static
- typename std::enable_if<!isFuture<Ret>::value, Ret>::type
- aStaticMethod(Params...) {
- return Ret();
- }
-
- template <class Ret, class... Params>
- static
- typename std::enable_if<isFuture<Ret>::value, Ret>::type
- aStaticMethod(Params...) {
- typedef typename Ret::value_type T;
- return makeFuture(T());
- }
-
- template <class Ret, class... Params>
- typename std::enable_if<!isFuture<Ret>::value, Ret>::type
- aMethod(Params...) {
- return Ret();
- }
-
- template <class Ret, class... Params>
- typename std::enable_if<isFuture<Ret>::value, Ret>::type
- aMethod(Params...) {
- typedef typename Ret::value_type T;
- return makeFuture(T());
- }
-};
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
#include <gtest/gtest.h>
#include <folly/futures/Timekeeper.h>
+
#include <unistd.h>
using namespace folly;
-using namespace std::chrono;
-using folly::Timekeeper;
-using Duration = folly::Duration;
std::chrono::milliseconds const one_ms(1);
std::chrono::milliseconds const awhile(10);
// runs it by hand they're not sitting there forever wondering why it's
// blocked, and get a useful error message instead. If it does get flaky,
// empirically increase the timeout to the point where it's very improbable.
- EXPECT_EQ(42, p.getFuture().get(seconds(2)));
+ EXPECT_EQ(42, p.getFuture().get(std::chrono::seconds(2)));
t.join();
}
+++ /dev/null
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include <folly/Memory.h>
-#include <folly/futures/Try.h>
-
-using namespace folly;
-
-// Make sure we can copy Trys for copyable types
-TEST(Try, copy) {
- Try<int> t;
- auto t2 = t;
-}
-
-// But don't choke on move-only types
-TEST(Try, moveOnly) {
- Try<std::unique_ptr<int>> t;
- std::vector<Try<std::unique_ptr<int>>> v;
- v.reserve(10);
-}
-
-TEST(Try, makeTryWith) {
- auto func = []() {
- return folly::make_unique<int>(1);
- };
-
- auto result = makeTryWith(func);
- EXPECT_TRUE(result.hasValue());
- EXPECT_EQ(*result.value(), 1);
-}
-
-TEST(Try, makeTryWithThrow) {
- auto func = []() {
- throw std::runtime_error("Runtime");
- return folly::make_unique<int>(1);
- };
-
- auto result = makeTryWith(func);
- EXPECT_TRUE(result.hasException<std::runtime_error>());
-}
-
-TEST(Try, makeTryWithVoid) {
- auto func = []() {
- return;
- };
-
- auto result = makeTryWith(func);
- EXPECT_TRUE(result.hasValue());
-}
-
-TEST(Try, makeTryWithVoidThrow) {
- auto func = []() {
- throw std::runtime_error("Runtime");
- return;
- };
-
- auto result = makeTryWith(func);
- EXPECT_TRUE(result.hasException<std::runtime_error>());
-}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/Memory.h>
+#include <folly/futures/Try.h>
+
+using namespace folly;
+
+TEST(Try, basic) {
+ class A {
+ public:
+ A(int x) : x_(x) {}
+
+ int x() const {
+ return x_;
+ }
+ private:
+ int x_;
+ };
+
+ A a(5);
+ Try<A> t_a(std::move(a));
+
+ Try<void> t_void;
+
+ EXPECT_EQ(5, t_a.value().x());
+}
+
+// Make sure we can copy Trys for copyable types
+TEST(Try, copy) {
+ Try<int> t;
+ auto t2 = t;
+}
+
+// But don't choke on move-only types
+TEST(Try, moveOnly) {
+ Try<std::unique_ptr<int>> t;
+ std::vector<Try<std::unique_ptr<int>>> v;
+ v.reserve(10);
+}
+
+TEST(Try, makeTryWith) {
+ auto func = []() {
+ return folly::make_unique<int>(1);
+ };
+
+ auto result = makeTryWith(func);
+ EXPECT_TRUE(result.hasValue());
+ EXPECT_EQ(*result.value(), 1);
+}
+
+TEST(Try, makeTryWithThrow) {
+ auto func = []() {
+ throw std::runtime_error("Runtime");
+ return folly::make_unique<int>(1);
+ };
+
+ auto result = makeTryWith(func);
+ EXPECT_TRUE(result.hasException<std::runtime_error>());
+}
+
+TEST(Try, makeTryWithVoid) {
+ auto func = []() {
+ return;
+ };
+
+ auto result = makeTryWith(func);
+ EXPECT_TRUE(result.hasValue());
+}
+
+TEST(Try, makeTryWithVoidThrow) {
+ auto func = []() {
+ throw std::runtime_error("Runtime");
+ return;
+ };
+
+ auto result = makeTryWith(func);
+ EXPECT_TRUE(result.hasException<std::runtime_error>());
+}
* limitations under the License.
*/
-#include <folly/futures/Future.h>
#include <gtest/gtest.h>
+#include <folly/futures/Future.h>
+
using namespace folly;
-TEST(Unit, FutureDefaultCtor) {
+TEST(Unit, futureDefaultCtor) {
Future<Unit>();
}
EXPECT_FALSE(is_void_or_unit<int>::value);
}
-TEST(Unit, PromiseSetValue) {
+TEST(Unit, promiseSetValue) {
Promise<Unit> p;
p.setValue();
}
-TEST(Unit, LiftInt) {
+TEST(Unit, liftInt) {
using Lifted = Unit::Lift<int>;
EXPECT_FALSE(Lifted::value);
auto v = std::is_same<int, Lifted::type>::value;
EXPECT_TRUE(v);
}
-TEST(Unit, LiftVoid) {
+TEST(Unit, liftVoid) {
using Lifted = Unit::Lift<void>;
EXPECT_TRUE(Lifted::value);
auto v = std::is_same<Unit, Lifted::type>::value;
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+using namespace folly;
+
+// A simple scenario for the unwrap call, when the promise was fulfilled
+// before calling to unwrap.
+TEST(Unwrap, simpleScenario) {
+ Future<int> encapsulated_future = makeFuture(5484);
+ Future<Future<int>> future = makeFuture(std::move(encapsulated_future));
+ EXPECT_EQ(5484, future.unwrap().value());
+}
+
+// Makes sure that unwrap() works when chaning Future's commands.
+TEST(Unwrap, chainCommands) {
+ Future<Future<int>> future = makeFuture(makeFuture(5484));
+ auto unwrapped = future.unwrap().then([](int i){ return i; });
+ EXPECT_EQ(5484, unwrapped.value());
+}
+
+// Makes sure that the unwrap call also works when the promise was not yet
+// fulfilled, and that the returned Future<T> becomes ready once the promise
+// is fulfilled.
+TEST(Unwrap, futureNotReady) {
+ Promise<Future<int>> p;
+ Future<Future<int>> future = p.getFuture();
+ Future<int> unwrapped = future.unwrap();
+ // Sanity - should not be ready before the promise is fulfilled.
+ ASSERT_FALSE(unwrapped.isReady());
+ // Fulfill the promise and make sure the unwrapped future is now ready.
+ p.setValue(makeFuture(5484));
+ ASSERT_TRUE(unwrapped.isReady());
+ EXPECT_EQ(5484, unwrapped.value());
+}
*/
#include <gtest/gtest.h>
-#include <thread>
#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 <thread>
using namespace folly;
std::thread t;
};
-TEST(Via, exception_on_launch) {
+TEST(Via, exceptionOnLaunch) {
auto future = makeFuture<int>(std::runtime_error("E"));
EXPECT_THROW(future.value(), std::runtime_error);
}
-TEST(Via, then_value) {
+TEST(Via, thenValue) {
auto future = makeFuture(std::move(1))
.then([](Try<int>&& t) {
return t.value() == 1;
EXPECT_TRUE(future.value());
}
-TEST(Via, then_future) {
+TEST(Via, thenFuture) {
auto future = makeFuture(1)
.then([](Try<int>&& t) {
return makeFuture(t.value() == 1);
return makeFuture(t.value() + ";static");
}
-TEST(Via, then_function) {
+TEST(Via, thenFunction) {
struct Worker {
Future<std::string> doWork(Try<std::string>&& t) {
return makeFuture(t.value() + ";class");
EXPECT_EQ(f.value(), "start;static;class-static;class");
}
-TEST_F(ViaFixture, thread_hops) {
+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);
EXPECT_EQ(f.getVia(waiter.get()), 1);
}
-TEST_F(ViaFixture, chain_vias) {
+TEST_F(ViaFixture, chainVias) {
auto westThreadId = std::this_thread::get_id();
auto f = via(eastExecutor.get()).then([=]() {
EXPECT_NE(std::this_thread::get_id(), westThreadId);
x.run();
EXPECT_TRUE(f.a);
}
+
+/// Simple executor that does work in another thread
+class ThreadExecutor : public Executor {
+ folly::MPMCQueue<Func> funcs;
+ std::atomic<bool> done {false};
+ std::thread worker;
+ folly::Baton<> baton;
+
+ void work() {
+ baton.post();
+ Func fn;
+ while (!done) {
+ while (!funcs.isEmpty()) {
+ funcs.blockingRead(fn);
+ fn();
+ }
+ }
+ }
+
+ public:
+ explicit ThreadExecutor(size_t n = 1024)
+ : funcs(n) {
+ worker = std::thread(std::bind(&ThreadExecutor::work, this));
+ }
+
+ ~ThreadExecutor() {
+ done = true;
+ funcs.write([]{});
+ worker.join();
+ }
+
+ void add(Func fn) override {
+ funcs.blockingWrite(std::move(fn));
+ }
+
+ void waitForStartup() {
+ baton.wait();
+ }
+};
+
+TEST(Via, viaThenGetWasRacy) {
+ ThreadExecutor x;
+ std::unique_ptr<int> val = folly::via(&x)
+ .then([] { return folly::make_unique<int>(42); })
+ .get();
+ ASSERT_TRUE(!!val);
+ EXPECT_EQ(42, *val);
+}
+
+class DummyDrivableExecutor : public DrivableExecutor {
+ public:
+ void add(Func f) override {}
+ void drive() override { ran = true; }
+ bool ran{false};
+};
+
+TEST(Via, getVia) {
+ {
+ // non-void
+ ManualExecutor x;
+ auto f = via(&x).then([]{ return true; });
+ EXPECT_TRUE(f.getVia(&x));
+ }
+
+ {
+ // void
+ ManualExecutor x;
+ auto f = via(&x).then();
+ f.getVia(&x);
+ }
+
+ {
+ DummyDrivableExecutor x;
+ auto f = makeFuture(true);
+ EXPECT_TRUE(f.getVia(&x));
+ EXPECT_FALSE(x.ran);
+ }
+}
+
+TEST(Via, waitVia) {
+ {
+ ManualExecutor x;
+ auto f = via(&x).then();
+ EXPECT_FALSE(f.isReady());
+ f.waitVia(&x);
+ EXPECT_TRUE(f.isReady());
+ }
+
+ {
+ // try rvalue as well
+ ManualExecutor x;
+ auto f = via(&x).then().waitVia(&x);
+ EXPECT_TRUE(f.isReady());
+ }
+
+ {
+ DummyDrivableExecutor x;
+ makeFuture(true).waitVia(&x);
+ EXPECT_FALSE(x.ran);
+ }
+}
+
+TEST(Via, viaRaces) {
+ ManualExecutor x;
+ Promise<void> 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; });
+ });
+
+ std::thread t2([&] {
+ p.setValue();
+ });
+
+ while (!done) x.run();
+ t1.join();
+ t2.join();
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+#include <folly/io/async/EventBase.h>
+#include <folly/Baton.h>
+
+using namespace folly;
+using std::vector;
+using std::chrono::milliseconds;
+
+TEST(Wait, waitImmediate) {
+ makeFuture().wait();
+ auto done = makeFuture(42).wait().value();
+ EXPECT_EQ(42, done);
+
+ vector<int> v{1,2,3};
+ auto done_v = makeFuture(v).wait().value();
+ EXPECT_EQ(v.size(), done_v.size());
+ EXPECT_EQ(v, done_v);
+
+ vector<Future<void>> v_f;
+ v_f.push_back(makeFuture());
+ v_f.push_back(makeFuture());
+ auto done_v_f = collectAll(v_f).wait().value();
+ EXPECT_EQ(2, done_v_f.size());
+
+ vector<Future<bool>> v_fb;
+ v_fb.push_back(makeFuture(true));
+ v_fb.push_back(makeFuture(false));
+ auto fut = collectAll(v_fb);
+ auto done_v_fb = std::move(fut.wait().value());
+ EXPECT_EQ(2, done_v_fb.size());
+}
+
+TEST(Wait, wait) {
+ Promise<int> p;
+ Future<int> f = p.getFuture();
+ std::atomic<bool> flag{false};
+ std::atomic<int> result{1};
+ std::atomic<std::thread::id> id;
+
+ std::thread t([&](Future<int>&& tf){
+ auto n = tf.then([&](Try<int> && t) {
+ id = std::this_thread::get_id();
+ return t.value();
+ });
+ flag = true;
+ result.store(n.wait().value());
+ },
+ std::move(f)
+ );
+ while(!flag){}
+ EXPECT_EQ(result.load(), 1);
+ p.setValue(42);
+ t.join();
+ // validate that the callback ended up executing in this thread, which
+ // is more to ensure that this test actually tests what it should
+ EXPECT_EQ(id, std::this_thread::get_id());
+ EXPECT_EQ(result.load(), 42);
+}
+
+struct MoveFlag {
+ MoveFlag() = default;
+ MoveFlag& operator=(const MoveFlag&) = delete;
+ MoveFlag(const MoveFlag&) = delete;
+ MoveFlag(MoveFlag&& other) noexcept {
+ other.moved = true;
+ }
+ bool moved{false};
+};
+
+TEST(Wait, waitReplacesSelf) {
+ // wait
+ {
+ // lvalue
+ auto f1 = makeFuture(MoveFlag());
+ f1.wait();
+ EXPECT_FALSE(f1.value().moved);
+
+ // rvalue
+ auto f2 = makeFuture(MoveFlag()).wait();
+ EXPECT_FALSE(f2.value().moved);
+ }
+
+ // wait(Duration)
+ {
+ // lvalue
+ auto f1 = makeFuture(MoveFlag());
+ f1.wait(milliseconds(1));
+ EXPECT_FALSE(f1.value().moved);
+
+ // rvalue
+ auto f2 = makeFuture(MoveFlag()).wait(milliseconds(1));
+ EXPECT_FALSE(f2.value().moved);
+ }
+
+ // waitVia
+ {
+ folly::EventBase eb;
+ // lvalue
+ auto f1 = makeFuture(MoveFlag());
+ f1.waitVia(&eb);
+ EXPECT_FALSE(f1.value().moved);
+
+ // rvalue
+ auto f2 = makeFuture(MoveFlag()).waitVia(&eb);
+ EXPECT_FALSE(f2.value().moved);
+ }
+}
+
+TEST(Wait, waitWithDuration) {
+ {
+ Promise<int> p;
+ Future<int> f = p.getFuture();
+ f.wait(milliseconds(1));
+ EXPECT_FALSE(f.isReady());
+ p.setValue(1);
+ EXPECT_TRUE(f.isReady());
+ }
+ {
+ Promise<int> p;
+ Future<int> f = p.getFuture();
+ p.setValue(1);
+ f.wait(milliseconds(1));
+ EXPECT_TRUE(f.isReady());
+ }
+ {
+ vector<Future<bool>> v_fb;
+ v_fb.push_back(makeFuture(true));
+ v_fb.push_back(makeFuture(false));
+ auto f = collectAll(v_fb);
+ f.wait(milliseconds(1));
+ EXPECT_TRUE(f.isReady());
+ EXPECT_EQ(2, f.value().size());
+ }
+ {
+ vector<Future<bool>> v_fb;
+ Promise<bool> p1;
+ Promise<bool> p2;
+ v_fb.push_back(p1.getFuture());
+ v_fb.push_back(p2.getFuture());
+ auto f = collectAll(v_fb);
+ f.wait(milliseconds(1));
+ EXPECT_FALSE(f.isReady());
+ p1.setValue(true);
+ EXPECT_FALSE(f.isReady());
+ p2.setValue(true);
+ EXPECT_TRUE(f.isReady());
+ }
+ {
+ auto f = makeFuture().wait(milliseconds(1));
+ EXPECT_TRUE(f.isReady());
+ }
+
+ {
+ Promise<void> p;
+ auto start = std::chrono::steady_clock::now();
+ auto f = p.getFuture().wait(milliseconds(100));
+ auto elapsed = std::chrono::steady_clock::now() - start;
+ EXPECT_GE(elapsed, milliseconds(100));
+ EXPECT_FALSE(f.isReady());
+ p.setValue();
+ EXPECT_TRUE(f.isReady());
+ }
+
+ {
+ // Try to trigger the race where the resultant Future is not yet complete
+ // even if we didn't hit the timeout, and make sure we deal with it properly
+ Promise<void> p;
+ folly::Baton<> b;
+ auto t = std::thread([&]{
+ b.post();
+ /* sleep override */ std::this_thread::sleep_for(milliseconds(100));
+ p.setValue();
+ });
+ b.wait();
+ auto f = p.getFuture().wait(std::chrono::seconds(3600));
+ EXPECT_TRUE(f.isReady());
+ t.join();
+ }
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+using namespace folly;
+
+TEST(WillEqual, basic) {
+ // both p1 and p2 already fulfilled
+ {
+ Promise<int> p1;
+ Promise<int> p2;
+ p1.setValue(27);
+ p2.setValue(27);
+ auto f1 = p1.getFuture();
+ auto f2 = p2.getFuture();
+ EXPECT_TRUE(f1.willEqual(f2).get());
+ }
+ {
+ Promise<int> p1;
+ Promise<int> p2;
+ p1.setValue(27);
+ p2.setValue(36);
+ auto f1 = p1.getFuture();
+ auto f2 = p2.getFuture();
+ EXPECT_FALSE(f1.willEqual(f2).get());
+ }
+ // both p1 and p2 not yet fulfilled
+ {
+ Promise<int> p1;
+ Promise<int> p2;
+ auto f1 = p1.getFuture();
+ auto f2 = p2.getFuture();
+ auto f3 = f1.willEqual(f2);
+ p1.setValue(27);
+ p2.setValue(27);
+ EXPECT_TRUE(f3.get());
+ }
+ {
+ Promise<int> p1;
+ Promise<int> p2;
+ auto f1 = p1.getFuture();
+ auto f2 = p2.getFuture();
+ auto f3 = f1.willEqual(f2);
+ p1.setValue(27);
+ p2.setValue(36);
+ EXPECT_FALSE(f3.get());
+ }
+ // p1 already fulfilled, p2 not yet fulfilled
+ {
+ Promise<int> p1;
+ Promise<int> p2;
+ p1.setValue(27);
+ auto f1 = p1.getFuture();
+ auto f2 = p2.getFuture();
+ auto f3 = f1.willEqual(f2);
+ p2.setValue(27);
+ EXPECT_TRUE(f3.get());
+ }
+ {
+ Promise<int> p1;
+ Promise<int> p2;
+ p1.setValue(27);
+ auto f1 = p1.getFuture();
+ auto f2 = p2.getFuture();
+ auto f3 = f1.willEqual(f2);
+ p2.setValue(36);
+ EXPECT_FALSE(f3.get());
+ }
+ // p2 already fulfilled, p1 not yet fulfilled
+ {
+ Promise<int> p1;
+ Promise<int> p2;
+ p2.setValue(27);
+ auto f1 = p1.getFuture();
+ auto f2 = p2.getFuture();
+ auto f3 = f1.willEqual(f2);
+ p1.setValue(27);
+ EXPECT_TRUE(f3.get());
+ }
+ {
+ Promise<int> p1;
+ Promise<int> p2;
+ p2.setValue(36);
+ auto f1 = p1.getFuture();
+ auto f2 = p2.getFuture();
+ auto f3 = f1.willEqual(f2);
+ p1.setValue(27);
+ EXPECT_FALSE(f3.get());
+ }
+}
--- /dev/null
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+
+#include <vector>
+
+using namespace folly;
+
+TEST(Window, basic) {
+ // int -> Future<int>
+ auto fn = [](std::vector<int> input, size_t window_size, size_t expect) {
+ auto res = reduce(
+ window(
+ input,
+ [](int i) { return makeFuture(i); },
+ 2),
+ 0,
+ [](int sum, const Try<int>& b) {
+ return sum + *b;
+ }).get();
+ EXPECT_EQ(expect, res);
+ };
+ {
+ // 2 in-flight at a time
+ std::vector<int> input = {1, 2, 3};
+ fn(input, 2, 6);
+ }
+ {
+ // 4 in-flight at a time
+ std::vector<int> input = {1, 2, 3};
+ fn(input, 4, 6);
+ }
+ {
+ // empty inpt
+ std::vector<int> input;
+ fn(input, 1, 0);
+ }
+ {
+ // int -> Future<void>
+ auto res = reduce(
+ window(
+ std::vector<int>({1, 2, 3}),
+ [](int i) { return makeFuture(); },
+ 2),
+ 0,
+ [](int sum, const Try<void>& b) {
+ EXPECT_TRUE(b.hasValue());
+ return sum + 1;
+ }).get();
+ EXPECT_EQ(3, res);
+ }
+ {
+ // string -> return Future<int>
+ auto res = reduce(
+ window(
+ std::vector<std::string>{"1", "2", "3"},
+ [](std::string s) { return makeFuture<int>(folly::to<int>(s)); },
+ 2),
+ 0,
+ [](int sum, const Try<int>& b) {
+ return sum + *b;
+ }).get();
+ EXPECT_EQ(6, res);
+ }
+}
+++ /dev/null
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-#include <gflags/gflags.h>
-#include <folly/Portability.h>
-
-int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
- ::gflags::ParseCommandLineFlags(&argc, &argv, true);
- return RUN_ALL_TESTS();
-}
--- /dev/null
+#!/usr/bin/env ruby
+
+# cd folly/futures/test && ruby then_compile_test.rb > ThenCompileTest.cpp
+
+# An exercise in combinatorics.
+# (ordinary/static function, member function, std::function, lambda)
+# X
+# returns (Future<R>, R)
+# X
+# accepts (Try<T>&&, Try<T> const&, Try<T>, T&&, T const&, T, nothing)
+
+def test(*args)
+ args = args.join(", ")
+ [
+ "{Future<B> f = someFuture<A>().then(#{args});}",
+ #"{Future<B> f = makeFuture(A()).then(#{args}, anExecutor);}",
+ ]
+end
+
+def retval(ret)
+ {
+ "Future<B>" => "someFuture<B>()",
+ "Try<B>" => "Try<B>(B())",
+ "B" => "B()"
+ }[ret]
+end
+
+return_types = [
+ "Future<B>",
+ "B",
+ #"Try<B>",
+]
+param_types = [
+ "Try<A>&&",
+ "Try<A> const&",
+ "Try<A>",
+ "Try<A>&",
+ "A&&",
+ "A const&",
+ "A",
+ "A&",
+ "",
+ ]
+
+tests = (
+ return_types.map { |ret|
+ param_types.map { |param|
+ if param != "" then
+ both = "#{ret}, #{param}"
+ [
+ ["&aFunction<#{both}>"],
+ ["&SomeClass::aStaticMethod<#{both}>"],
+ ["&SomeClass::aMethod<#{both}>", "&anObject"],
+ ["aStdFunction<#{both}>()"],
+ ["[&](#{param}){return #{retval(ret)};}"],
+ ]
+ else
+ [["[&](){return #{retval(ret)};}"]]
+ end
+ }
+ }.flatten(2)
+).map {|a| test(a)}.flatten
+
+print <<EOF
+// This file is #{"@"}generated by then_compile_test.rb. Do not edit directly.
+
+#include <folly/futures/test/ThenCompileTest.h>
+
+using namespace folly;
+
+TEST(Basic, thenVariants) {
+ SomeClass anObject;
+
+ #{tests.join("\n ")}
+}
+EOF
+++ /dev/null
-#!/usr/bin/env ruby
-
-# ruby folly/futures/test/thens.rb > folly/futures/test/Thens.cpp
-
-# An exercise in combinatorics.
-# (ordinary/static function, member function, std::function, lambda)
-# X
-# returns (Future<R>, R)
-# X
-# accepts (Try<T>&&, Try<T> const&, Try<T>, T&&, T const&, T, nothing)
-
-def test(*args)
- args = args.join(", ")
- [
- "{Future<B> f = someFuture<A>().then(#{args});}",
- #"{Future<B> f = makeFuture(A()).then(#{args}, anExecutor);}",
- ]
-end
-
-def retval(ret)
- {
- "Future<B>" => "someFuture<B>()",
- "Try<B>" => "Try<B>(B())",
- "B" => "B()"
- }[ret]
-end
-
-return_types = [
- "Future<B>",
- "B",
- #"Try<B>",
-]
-param_types = [
- "Try<A>&&",
- "Try<A> const&",
- "Try<A>",
- "Try<A>&",
- "A&&",
- "A const&",
- "A",
- "A&",
- "",
- ]
-
-tests = (
- return_types.map { |ret|
- param_types.map { |param|
- if param != "" then
- both = "#{ret}, #{param}"
- [
- ["&aFunction<#{both}>"],
- ["&SomeClass::aStaticMethod<#{both}>"],
- ["&SomeClass::aMethod<#{both}>", "&anObject"],
- ["aStdFunction<#{both}>()"],
- ["[&](#{param}){return #{retval(ret)};}"],
- ]
- else
- [["[&](){return #{retval(ret)};}"]]
- end
- }
- }.flatten(2)
-).map {|a| test(a)}.flatten
-
-print <<EOF
-// This file is #{"@"}generated by thens.rb. Do not edit directly.
-
-#include <folly/futures/test/Thens.h>
-
-TEST(Future, thenVariants) {
- SomeClass anObject;
- folly::Executor* anExecutor;
-
- #{tests.join("\n ")}
-}
-
-EOF