(Wangle) Clean up tests
authorHannes Roth <hannesr@fb.com>
Fri, 5 Jun 2015 15:50:18 +0000 (08:50 -0700)
committerSara Golemon <sgolemon@fb.com>
Tue, 9 Jun 2015 20:19:18 +0000 (13:19 -0700)
Summary:
This always bothered me. Now:

1) Separate tests for each feature
2) `XTest.cpp` contains `TEST(X, lowerCaseCamelCase)`

Also cleaned up some header files and using statements.

Shamelessly trying to increase the number of lines that blame to me.

Test Plan:
Run all the tests.

`git grep 'TEST' -- 'folly/futures/test/*Test.cpp' | cut -d ',' -f 1 | cut -d '/' -f 4 | sort -u`

`diff <(git ls-files -- 'folly/futures/test/*Test.cpp' | cut -d '/' -f 4 | sort) <(git grep 'Test.cpp' -- folly/futures/TARGETS | cut -d '/' -f 4 | cut -d "'" -f 1 | sort)`

Reviewed By: jsedgwick@fb.com

Subscribers: trunkagent, folly-diffs@, jsedgwick, yfeldblum, chalfant

FB internal diff: D2127359

Tasks: 6019442

Signature: t1:2127359:1433459532:54a91ae83d7fb2d0b3f3769f673fefea20f35435

37 files changed:
folly/futures/test/Benchmark.cpp
folly/futures/test/ClientCompile.cpp [deleted file]
folly/futures/test/CollectTest.cpp [new file with mode: 0644]
folly/futures/test/ContextTest.cpp [new file with mode: 0644]
folly/futures/test/CoreTest.cpp [new file with mode: 0644]
folly/futures/test/EnsureTest.cpp [new file with mode: 0644]
folly/futures/test/ExecutorTest.cpp
folly/futures/test/FSM.cpp [deleted file]
folly/futures/test/FSMTest.cpp [new file with mode: 0644]
folly/futures/test/FilterTest.cpp [new file with mode: 0644]
folly/futures/test/FutureTest.cpp
folly/futures/test/HeaderCompileTest.cpp [new file with mode: 0644]
folly/futures/test/InterruptTest.cpp [new file with mode: 0644]
folly/futures/test/Interrupts.cpp [deleted file]
folly/futures/test/MapTest.cpp [new file with mode: 0644]
folly/futures/test/PollTest.cpp [new file with mode: 0644]
folly/futures/test/PromiseTest.cpp [new file with mode: 0644]
folly/futures/test/ReduceTest.cpp [new file with mode: 0644]
folly/futures/test/SharedPromiseTest.cpp
folly/futures/test/SugarTest.cpp [deleted file]
folly/futures/test/ThenCompileTest.cpp [new file with mode: 0644]
folly/futures/test/ThenCompileTest.h [new file with mode: 0644]
folly/futures/test/ThenTest.cpp
folly/futures/test/Thens.cpp [deleted file]
folly/futures/test/Thens.h [deleted file]
folly/futures/test/TimekeeperTest.cpp
folly/futures/test/Try.cpp [deleted file]
folly/futures/test/TryTest.cpp [new file with mode: 0644]
folly/futures/test/UnitTest.cpp
folly/futures/test/UnwrapTest.cpp [new file with mode: 0644]
folly/futures/test/ViaTest.cpp
folly/futures/test/WaitTest.cpp [new file with mode: 0644]
folly/futures/test/WillEqualTest.cpp [new file with mode: 0644]
folly/futures/test/WindowTest.cpp [new file with mode: 0644]
folly/futures/test/main.cpp [deleted file]
folly/futures/test/then_compile_test.rb [new file with mode: 0755]
folly/futures/test/thens.rb [deleted file]

index fbf2538fa7e0fcc54cebe2ca45d4493a058e4850..54771b1ed76584d2cae55d8aab8049d933ebf7b9 100644 (file)
  */
 
 #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 {
 
@@ -89,8 +90,8 @@ BENCHMARK_RELATIVE(hundredThens) {
 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 {
@@ -118,8 +119,8 @@ BENCHMARK(no_contention) {
 }
 
 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);
diff --git a/folly/futures/test/ClientCompile.cpp b/folly/futures/test/ClientCompile.cpp
deleted file mode 100644 (file)
index caaac9e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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; }
diff --git a/folly/futures/test/CollectTest.cpp b/folly/futures/test/CollectTest.cpp
new file mode 100644 (file)
index 0000000..ea4b3bf
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * 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());
+}
diff --git a/folly/futures/test/ContextTest.cpp b/folly/futures/test/ContextTest.cpp
new file mode 100644 (file)
index 0000000..dd29b15
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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();
+}
diff --git a/folly/futures/test/CoreTest.cpp b/folly/futures/test/CoreTest.cpp
new file mode 100644 (file)
index 0000000..7e2ad64
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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>));
+}
diff --git a/folly/futures/test/EnsureTest.cpp b/folly/futures/test/EnsureTest.cpp
new file mode 100644 (file)
index 0000000..b3fa6b0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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);
+}
index e477f5cc70b1157adf0aaaf928cf74553ed75569..c7b06dd69a4017a66b5f7eb1df389fbdb92ccde9 100644 (file)
  */
 
 #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;
@@ -37,7 +36,7 @@ TEST(ManualExecutor, runIsStable) {
 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();
@@ -56,38 +55,38 @@ TEST(ManualExecutor, clockStartsAt0) {
 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);
 }
 
diff --git a/folly/futures/test/FSM.cpp b/folly/futures/test/FSM.cpp
deleted file mode 100644 (file)
index f5b871a..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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()); });
-}
diff --git a/folly/futures/test/FSMTest.cpp b/folly/futures/test/FSMTest.cpp
new file mode 100644 (file)
index 0000000..ee28b45
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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()); });
+}
diff --git a/folly/futures/test/FilterTest.cpp b/folly/futures/test/FilterTest.cpp
new file mode 100644 (file)
index 0000000..5b37080
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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());
+}
index 58619d6938e1e96bca762ab4ddf38d96eeba6aa9..5d171bb9732f50f9c0e12476072b3a79d2e9a253 100644 (file)
  * 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) {
@@ -323,26 +266,6 @@ 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);
@@ -351,20 +274,33 @@ TEST(Future, special) {
 }
 
 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");
 }
@@ -433,21 +369,21 @@ TEST(Future, thenValueFuture) {
   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);
@@ -455,21 +391,21 @@ TEST(Future, thenFunction) {
   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);
@@ -487,17 +423,17 @@ TEST(Future, thenBind) {
 }
 
 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);
 
@@ -546,93 +482,6 @@ TEST(Future, makeFuture) {
   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);
   {
@@ -690,489 +539,6 @@ TEST(Future, unwrap) {
   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(
@@ -1201,260 +567,13 @@ TEST(Future, throwIfFailed) {
     });
 }
 
-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);
@@ -1483,72 +602,6 @@ TEST(Future, detachRace) {
   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.
@@ -1601,333 +654,3 @@ TEST(Future, thenDynamic) {
   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());
-}
diff --git a/folly/futures/test/HeaderCompileTest.cpp b/folly/futures/test/HeaderCompileTest.cpp
new file mode 100644 (file)
index 0000000..2138bcc
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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);
+}
diff --git a/folly/futures/test/InterruptTest.cpp b/folly/futures/test/InterruptTest.cpp
new file mode 100644 (file)
index 0000000..1963c0a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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);
+}
diff --git a/folly/futures/test/Interrupts.cpp b/folly/futures/test/Interrupts.cpp
deleted file mode 100644 (file)
index 3b08bc6..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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);
-}
diff --git a/folly/futures/test/MapTest.cpp b/folly/futures/test/MapTest.cpp
new file mode 100644 (file)
index 0000000..ed0313d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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());
+}
diff --git a/folly/futures/test/PollTest.cpp b/folly/futures/test/PollTest.cpp
new file mode 100644 (file)
index 0000000..166dea6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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());
+}
diff --git a/folly/futures/test/PromiseTest.cpp b/folly/futures/test/PromiseTest.cpp
new file mode 100644 (file)
index 0000000..5e20706
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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());
+}
diff --git a/folly/futures/test/ReduceTest.cpp b/folly/futures/test/ReduceTest.cpp
new file mode 100644 (file)
index 0000000..20e2924
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * 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);
+}
index 280bb64cb2c183953340fd06ef1ad9f95ff66a14..495526d52ffbbb3f2f94964e0bb830f06b75f61f 100644 (file)
  * 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();
@@ -26,7 +28,7 @@ TEST(SharedPromise, SetGet) {
   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();
@@ -35,7 +37,7 @@ TEST(SharedPromise, GetSet) {
   EXPECT_EQ(1, f2.value());
 }
 
-TEST(SharedPromise, GetSetGet) {
+TEST(SharedPromise, getSetGet) {
   SharedPromise<int> p;
   auto f1 = p.getFuture();
   p.setValue(1);
@@ -44,7 +46,7 @@ TEST(SharedPromise, GetSetGet) {
   EXPECT_EQ(1, f2.value());
 }
 
-TEST(SharedPromise, Reset) {
+TEST(SharedPromise, reset) {
   SharedPromise<int> p;
 
   auto f1 = p.getFuture();
@@ -58,7 +60,7 @@ TEST(SharedPromise, Reset) {
   EXPECT_EQ(2, f2.value());
 }
 
-TEST(SharedPromise, GetMoveSet) {
+TEST(SharedPromise, getMoveSet) {
   SharedPromise<int> p;
   auto f = p.getFuture();
   auto p2 = std::move(p);
@@ -66,7 +68,7 @@ TEST(SharedPromise, GetMoveSet) {
   EXPECT_EQ(1, f.value());
 }
 
-TEST(SharedPromise, SetMoveGet) {
+TEST(SharedPromise, setMoveGet) {
   SharedPromise<int> p;
   p.setValue(1);
   auto p2 = std::move(p);
@@ -74,7 +76,7 @@ TEST(SharedPromise, SetMoveGet) {
   EXPECT_EQ(1, f.value());
 }
 
-TEST(SharedPromise, MoveSetGet) {
+TEST(SharedPromise, moveSetGet) {
   SharedPromise<int> p;
   auto p2 = std::move(p);
   p2.setValue(1);
@@ -82,7 +84,7 @@ TEST(SharedPromise, MoveSetGet) {
   EXPECT_EQ(1, f.value());
 }
 
-TEST(SharedPromise, MoveGetSet) {
+TEST(SharedPromise, moveGetSet) {
   SharedPromise<int> p;
   auto p2 = std::move(p);
   auto f = p2.getFuture();
@@ -90,7 +92,7 @@ TEST(SharedPromise, MoveGetSet) {
   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();
diff --git a/folly/futures/test/SugarTest.cpp b/folly/futures/test/SugarTest.cpp
deleted file mode 100644 (file)
index 0563eef..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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());
-}
diff --git a/folly/futures/test/ThenCompileTest.cpp b/folly/futures/test/ThenCompileTest.cpp
new file mode 100644 (file)
index 0000000..0678d15
--- /dev/null
@@ -0,0 +1,92 @@
+// 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();});}
+}
diff --git a/folly/futures/test/ThenCompileTest.h b/folly/futures/test/ThenCompileTest.h
new file mode 100644 (file)
index 0000000..c8327e7
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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());
+  }
+};
+
+}
index fdc65a64e140d6da14f93dcad4f050453a124169..6d330f64b6635a1bea4f94aa371e350be07cbae1 100644 (file)
  */
 
 #include <gtest/gtest.h>
-#include <thread>
 
 #include <folly/futures/Future.h>
 
+#include <thread>
+
 using namespace folly;
 
 struct Widget {
@@ -48,7 +49,7 @@ TEST(Then, makeFuture) {
   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);
@@ -58,7 +59,7 @@ TEST(Then, TryConstRValueReference) {
   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);
@@ -68,7 +69,7 @@ TEST(Then, TryRValueReference) {
   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);
@@ -78,7 +79,7 @@ TEST(Then, TryLValueReference) {
   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);
@@ -88,7 +89,7 @@ TEST(Then, TryConstLValueReference) {
   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);
@@ -98,7 +99,7 @@ TEST(Then, TryValue) {
   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);
@@ -108,7 +109,7 @@ TEST(Then, TryConstValue) {
   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);
@@ -118,7 +119,7 @@ TEST(Then, ConstRValueReference) {
   EXPECT_EQ(future.value(), 23);
 }
 
-TEST(Then, RValueReference) {
+TEST(Then, rValueReference) {
   auto future = makeFuture<Widget>(23).then(
     [](Widget&& w) {
       EXPECT_EQ(w.copied_, 0);
@@ -128,7 +129,7 @@ TEST(Then, RValueReference) {
   EXPECT_EQ(future.value(), 23);
 }
 
-TEST(Then, LValueReference) {
+TEST(Then, lValueReference) {
   auto future = makeFuture<Widget>(23).then(
     [](Widget& w) {
       EXPECT_EQ(w.copied_, 0);
@@ -138,7 +139,7 @@ TEST(Then, LValueReference) {
   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);
@@ -148,7 +149,7 @@ TEST(Then, ConstLValueReference) {
   EXPECT_EQ(future.value(), 23);
 }
 
-TEST(Then, Value) {
+TEST(Then, value) {
   auto future = makeFuture<Widget>(23).then(
     [](Widget w) {
       EXPECT_EQ(w.copied_, 0);
@@ -158,7 +159,7 @@ TEST(Then, Value) {
   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);
diff --git a/folly/futures/test/Thens.cpp b/folly/futures/test/Thens.cpp
deleted file mode 100644 (file)
index 3d136b5..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-// 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();});}
-}
-
diff --git a/folly/futures/test/Thens.h b/folly/futures/test/Thens.h
deleted file mode 100644 (file)
index 5391e24..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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());
-  }
-};
index f9db640db52f04894194ebe1c7d45188f381678a..0ecdb2d73b53f78c50131f14dbf573ea671a77dc 100644 (file)
  * 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);
@@ -66,7 +65,7 @@ TEST(Timekeeper, futureGetBeforeTimeout) {
   // 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();
 }
 
diff --git a/folly/futures/test/Try.cpp b/folly/futures/test/Try.cpp
deleted file mode 100644 (file)
index f0bb5d6..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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>());
-}
diff --git a/folly/futures/test/TryTest.cpp b/folly/futures/test/TryTest.cpp
new file mode 100644 (file)
index 0000000..479fcb9
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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>());
+}
index 930b1231ae1edf5ce48cea9fbe0743d613978e7f..ae49065bd00807321bbbb5bb61f842ef42d1b898 100644 (file)
  * 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>();
 }
 
@@ -29,19 +30,19 @@ TEST(Unit, voidOrUnit) {
   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;
diff --git a/folly/futures/test/UnwrapTest.cpp b/folly/futures/test/UnwrapTest.cpp
new file mode 100644 (file)
index 0000000..686592c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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());
+}
index edaed77409720cb3ff119581243258f6c633f7b0..9acac1bc86edb62be1af06aa231f11ee01d08bd3 100644 (file)
  */
 
 #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;
 
@@ -73,12 +76,12 @@ struct ViaFixture : public testing::Test {
   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;
@@ -88,7 +91,7 @@ TEST(Via, then_value) {
   EXPECT_TRUE(future.value());
 }
 
-TEST(Via, then_future) {
+TEST(Via, thenFuture) {
   auto future = makeFuture(1)
     .then([](Try<int>&& t) {
       return makeFuture(t.value() == 1);
@@ -100,7 +103,7 @@ static Future<std::string> doWorkStatic(Try<std::string>&& t) {
   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");
@@ -119,7 +122,7 @@ TEST(Via, then_function) {
   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);
@@ -132,7 +135,7 @@ TEST_F(ViaFixture, thread_hops) {
   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);
@@ -287,3 +290,127 @@ TEST(Via, then2Variadic) {
   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();
+}
diff --git a/folly/futures/test/WaitTest.cpp b/folly/futures/test/WaitTest.cpp
new file mode 100644 (file)
index 0000000..d2b91f9
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * 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();
+ }
+}
diff --git a/folly/futures/test/WillEqualTest.cpp b/folly/futures/test/WillEqualTest.cpp
new file mode 100644 (file)
index 0000000..f517c7d
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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());
+  }
+}
diff --git a/folly/futures/test/WindowTest.cpp b/folly/futures/test/WindowTest.cpp
new file mode 100644 (file)
index 0000000..cc480fb
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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);
+  }
+}
diff --git a/folly/futures/test/main.cpp b/folly/futures/test/main.cpp
deleted file mode 100644 (file)
index a596ae6..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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();
-}
diff --git a/folly/futures/test/then_compile_test.rb b/folly/futures/test/then_compile_test.rb
new file mode 100755 (executable)
index 0000000..436e6ad
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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
diff --git a/folly/futures/test/thens.rb b/folly/futures/test/thens.rb
deleted file mode 100755 (executable)
index 4eeffd8..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/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