folly: build with -Wunused-parameter
[folly.git] / folly / futures / test / CollectTest.cpp
index ea4b3bf8f561edbcc42af5a033af287e73dcb487..c58b41ff2f285a92b7b7e00f8c123accca210a85 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <gtest/gtest.h>
 
+#include <boost/thread/barrier.hpp>
+
 #include <folly/futures/Future.h>
 #include <folly/Random.h>
 #include <folly/small_vector.h>
@@ -85,14 +87,14 @@ TEST(Collect, collectAll) {
 
   // check that futures are ready in then()
   {
-    std::vector<Promise<void>> promises(10);
-    std::vector<Future<void>> futures;
+    std::vector<Promise<Unit>> promises(10);
+    std::vector<Future<Unit>> futures;
 
     for (auto& p : promises)
       futures.push_back(p.getFuture());
 
     auto allf = collectAll(futures)
-      .then([](Try<std::vector<Try<void>>>&& ts) {
+      .then([](Try<std::vector<Try<Unit>>>&& ts) {
         for (auto& f : ts.value())
           f.value();
       });
@@ -164,8 +166,8 @@ TEST(Collect, collect) {
 
   // void futures success case
   {
-    std::vector<Promise<void>> promises(10);
-    std::vector<Future<void>> futures;
+    std::vector<Promise<Unit>> promises(10);
+    std::vector<Future<Unit>> futures;
 
     for (auto& p : promises)
       futures.push_back(p.getFuture());
@@ -183,8 +185,8 @@ TEST(Collect, collect) {
 
   // void futures failure case
   {
-    std::vector<Promise<void>> promises(10);
-    std::vector<Future<void>> futures;
+    std::vector<Promise<Unit>> promises(10);
+    std::vector<Future<Unit>> futures;
 
     for (auto& p : promises)
       futures.push_back(p.getFuture());
@@ -292,8 +294,8 @@ TEST(Collect, collectAny) {
 
   // error
   {
-    std::vector<Promise<void>> promises(10);
-    std::vector<Future<void>> futures;
+    std::vector<Promise<Unit>> promises(10);
+    std::vector<Future<Unit>> futures;
 
     for (auto& p : promises)
       futures.push_back(p.getFuture());
@@ -332,12 +334,12 @@ TEST(Collect, collectAny) {
 
 TEST(Collect, alreadyCompleted) {
   {
-    std::vector<Future<void>> fs;
+    std::vector<Future<Unit>> fs;
     for (int i = 0; i < 10; i++)
       fs.push_back(makeFuture());
 
     collectAll(fs)
-      .then([&](std::vector<Try<void>> ts) {
+      .then([&](std::vector<Try<Unit>> ts) {
         EXPECT_EQ(fs.size(), ts.size());
       });
   }
@@ -353,9 +355,137 @@ TEST(Collect, alreadyCompleted) {
   }
 }
 
+TEST(Collect, parallel) {
+  std::vector<Promise<int>> ps(10);
+  std::vector<Future<int>> fs;
+  for (size_t i = 0; i < ps.size(); i++) {
+    fs.emplace_back(ps[i].getFuture());
+  }
+  auto f = collect(fs);
+
+  std::vector<std::thread> ts;
+  boost::barrier barrier(ps.size() + 1);
+  for (size_t i = 0; i < ps.size(); i++) {
+    ts.emplace_back([&ps, &barrier, i]() {
+      barrier.wait();
+      ps[i].setValue(i);
+    });
+  }
+
+  barrier.wait();
+
+  for (size_t i = 0; i < ps.size(); i++) {
+    ts[i].join();
+  }
+
+  EXPECT_TRUE(f.isReady());
+  for (size_t i = 0; i < ps.size(); i++) {
+    EXPECT_EQ(i, f.value()[i]);
+  }
+}
+
+TEST(Collect, parallelWithError) {
+  std::vector<Promise<int>> ps(10);
+  std::vector<Future<int>> fs;
+  for (size_t i = 0; i < ps.size(); i++) {
+    fs.emplace_back(ps[i].getFuture());
+  }
+  auto f = collect(fs);
+
+  std::vector<std::thread> ts;
+  boost::barrier barrier(ps.size() + 1);
+  for (size_t i = 0; i < ps.size(); i++) {
+    ts.emplace_back([&ps, &barrier, i]() {
+      barrier.wait();
+      if (i == (ps.size()/2)) {
+        ps[i].setException(eggs);
+      } else {
+        ps[i].setValue(i);
+      }
+    });
+  }
+
+  barrier.wait();
+
+  for (size_t i = 0; i < ps.size(); i++) {
+    ts[i].join();
+  }
+
+  EXPECT_TRUE(f.isReady());
+  EXPECT_THROW(f.value(), eggs_t);
+}
+
+TEST(Collect, allParallel) {
+  std::vector<Promise<int>> ps(10);
+  std::vector<Future<int>> fs;
+  for (size_t i = 0; i < ps.size(); i++) {
+    fs.emplace_back(ps[i].getFuture());
+  }
+  auto f = collectAll(fs);
+
+  std::vector<std::thread> ts;
+  boost::barrier barrier(ps.size() + 1);
+  for (size_t i = 0; i < ps.size(); i++) {
+    ts.emplace_back([&ps, &barrier, i]() {
+      barrier.wait();
+      ps[i].setValue(i);
+    });
+  }
+
+  barrier.wait();
+
+  for (size_t i = 0; i < ps.size(); i++) {
+    ts[i].join();
+  }
+
+  EXPECT_TRUE(f.isReady());
+  for (size_t i = 0; i < ps.size(); i++) {
+    EXPECT_TRUE(f.value()[i].hasValue());
+    EXPECT_EQ(i, f.value()[i].value());
+  }
+}
+
+TEST(Collect, allParallelWithError) {
+  std::vector<Promise<int>> ps(10);
+  std::vector<Future<int>> fs;
+  for (size_t i = 0; i < ps.size(); i++) {
+    fs.emplace_back(ps[i].getFuture());
+  }
+  auto f = collectAll(fs);
+
+  std::vector<std::thread> ts;
+  boost::barrier barrier(ps.size() + 1);
+  for (size_t i = 0; i < ps.size(); i++) {
+    ts.emplace_back([&ps, &barrier, i]() {
+      barrier.wait();
+      if (i == (ps.size()/2)) {
+        ps[i].setException(eggs);
+      } else {
+        ps[i].setValue(i);
+      }
+    });
+  }
+
+  barrier.wait();
+
+  for (size_t i = 0; i < ps.size(); i++) {
+    ts[i].join();
+  }
+
+  EXPECT_TRUE(f.isReady());
+  for (size_t i = 0; i < ps.size(); i++) {
+    if (i == (ps.size()/2)) {
+      EXPECT_THROW(f.value()[i].value(), eggs_t);
+    } else {
+      EXPECT_TRUE(f.value()[i].hasValue());
+      EXPECT_EQ(i, f.value()[i].value());
+    }
+  }
+}
+
 TEST(Collect, collectN) {
-  std::vector<Promise<void>> promises(10);
-  std::vector<Future<void>> futures;
+  std::vector<Promise<Unit>> promises(10);
+  std::vector<Future<Unit>> futures;
 
   for (auto& p : promises)
     futures.push_back(p.getFuture());
@@ -363,7 +493,7 @@ TEST(Collect, collectN) {
   bool flag = false;
   size_t n = 3;
   collectN(futures, n)
-    .then([&](std::vector<std::pair<size_t, Try<void>>> v) {
+    .then([&](std::vector<std::pair<size_t, Try<Unit>>> v) {
       flag = true;
       EXPECT_EQ(n, v.size());
       for (auto& tt : v)
@@ -380,13 +510,13 @@ TEST(Collect, collectN) {
 
 /// Ensure that we can compile collectAll/Any with folly::small_vector
 TEST(Collect, smallVector) {
-  static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<void>),
+  static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<Unit>),
                 "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;
+    folly::small_vector<Future<Unit>> futures;
 
     for (int i = 0; i < 10; i++)
       futures.push_back(makeFuture());
@@ -394,7 +524,7 @@ TEST(Collect, smallVector) {
     auto anyf = collectAny(futures);
   }
   {
-    folly::small_vector<Future<void>> futures;
+    folly::small_vector<Future<Unit>> futures;
 
     for (int i = 0; i < 10; i++)
       futures.push_back(makeFuture());
@@ -443,8 +573,71 @@ TEST(Collect, collectAllVariadicReferences) {
   EXPECT_TRUE(flag);
 }
 
+TEST(Collect, collectAllVariadicWithException) {
+  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).hasException());
+      EXPECT_THROW(std::get<1>(tup).value(), eggs_t);
+    });
+  pb.setValue(true);
+  EXPECT_FALSE(flag);
+  pi.setException(eggs);
+  EXPECT_TRUE(flag);
+}
+
+TEST(Collect, collectVariadic) {
+  Promise<bool> pb;
+  Promise<int> pi;
+  Future<bool> fb = pb.getFuture();
+  Future<int> fi = pi.getFuture();
+  bool flag = false;
+  collect(std::move(fb), std::move(fi))
+    .then([&](std::tuple<bool, int> tup) {
+      flag = true;
+      EXPECT_EQ(std::get<0>(tup), true);
+      EXPECT_EQ(std::get<1>(tup), 42);
+    });
+  pb.setValue(true);
+  EXPECT_FALSE(flag);
+  pi.setValue(42);
+  EXPECT_TRUE(flag);
+}
+
+TEST(Collect, collectVariadicWithException) {
+  Promise<bool> pb;
+  Promise<int> pi;
+  Future<bool> fb = pb.getFuture();
+  Future<int> fi = pi.getFuture();
+  auto f = collect(std::move(fb), std::move(fi));
+  pb.setValue(true);
+  EXPECT_FALSE(f.isReady());
+  pi.setException(eggs);
+  EXPECT_TRUE(f.isReady());
+  EXPECT_TRUE(f.getTry().hasException());
+  EXPECT_THROW(f.get(), eggs_t);
+}
+
 TEST(Collect, collectAllNone) {
   std::vector<Future<int>> fs;
   auto f = collectAll(fs);
   EXPECT_TRUE(f.isReady());
 }
+
+TEST(Collect, noDefaultConstructor) {
+  struct A {
+    explicit A(size_t /* x */) {}
+  };
+
+  auto f1 = makeFuture(A(1));
+  auto f2 = makeFuture(A(2));
+
+  auto f = collect(std::move(f1), std::move(f2));
+}