fix some of the warning/errors clang 3.1 reports - 2
[folly.git] / folly / experimental / test / GenTest.cpp
index bb85abab86c7b99fb2f43d1ea2e62cb212776f1c..de2e4afbebe63a099daa330afb99e65c64877f32 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Facebook, Inc.
+ * Copyright 2013 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <set>
 #include <vector>
 #include "folly/experimental/Gen.h"
+#include "folly/experimental/StringGen.h"
+#include "folly/experimental/FileGen.h"
+#include "folly/experimental/TestUtil.h"
 #include "folly/FBVector.h"
+#include "folly/Format.h"
 #include "folly/dynamic.h"
 
 using namespace folly::gen;
@@ -30,6 +34,7 @@ using std::pair;
 using std::set;
 using std::unique_ptr;
 using std::vector;
+using std::string;
 using std::tuple;
 using std::make_tuple;
 //using std::unordered_map;
@@ -166,6 +171,19 @@ TEST(Gen, Until) {
   EXPECT_EQ(31, gen | count);
 }
 
+TEST(Gen, Composed) {
+  // Operator, Operator
+  auto valuesOf =
+      filter([](Optional<int>& o) { return o.hasValue(); })
+    | map([](Optional<int>& o) -> int& { return o.value(); });
+  std::vector<Optional<int>> opts {
+    none, 4, none, 6, none
+  };
+  EXPECT_EQ(4 * 4 + 6 * 6, from(opts) | valuesOf | map(square) | sum);
+  // Operator, Sink
+  auto sumOpt = valuesOf | sum;
+  EXPECT_EQ(10, from(opts) | sumOpt);
+}
 
 TEST(Gen, Chain) {
   std::vector<int> nums {2, 3, 5, 7};
@@ -233,8 +251,8 @@ TEST(Gen, OrderTake) {
 
 TEST(Gen, MinBy) {
   EXPECT_EQ(7, seq(1, 10)
-             | minBy([](int i) {
-                 auto d = i - 6.8;
+             | minBy([](int i) -> double {
+                 double d = i - 6.8;
                  return d * d;
                }));
 }
@@ -385,7 +403,7 @@ TEST(Gen, Any) {
 }
 
 TEST(Gen, Yielders) {
-  auto gen = GENERATOR(int, {
+  auto gen = GENERATOR(int) {
     for (int i = 1; i <= 5; ++i) {
       yield(i);
     }
@@ -393,7 +411,7 @@ TEST(Gen, Yielders) {
     for (int i = 3; ; ++i) {
       yield(i * i);
     }
-  });
+  };
   vector<int> expected {
     1, 2, 3, 4, 5, 7, 9, 16, 25
   };
@@ -401,30 +419,30 @@ TEST(Gen, Yielders) {
 }
 
 TEST(Gen, NestedYield) {
-  auto nums = GENERATOR(int, {
+  auto nums = GENERATOR(int) {
     for (int i = 1; ; ++i) {
       yield(i);
     }
-  });
-  auto gen = GENERATOR(int, {
+  };
+  auto gen = GENERATOR(int) {
     nums | take(10) | yield;
     seq(1, 5) | [&](int i) {
       yield(i);
     };
-  });
+  };
   EXPECT_EQ(70, gen | sum);
 }
 
 TEST(Gen, MapYielders) {
   auto gen = seq(1, 5)
            | map([](int n) {
-               return GENERATOR(int, {
+               return GENERATOR(int) {
                  int i;
                  for (i = 1; i < n; ++i)
                    yield(i);
                  for (; i >= 1; --i)
                    yield(i);
-               });
+               };
              })
            | concat;
   vector<int> expected {
@@ -467,6 +485,34 @@ TEST(Gen, NoNeedlessCopies) {
   EXPECT_EQ(6, gen | take(3) | sum);
 }
 
+namespace {
+class TestIntSeq : public GenImpl<int, TestIntSeq> {
+ public:
+  TestIntSeq() { }
+
+  template <class Body>
+  bool apply(Body&& body) const {
+    for (int i = 1; i < 6; ++i) {
+      if (!body(i)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  TestIntSeq(TestIntSeq&&) = default;
+  TestIntSeq& operator=(TestIntSeq&&) = default;
+  TestIntSeq(const TestIntSeq&) = delete;
+  TestIntSeq& operator=(const TestIntSeq&) = delete;
+};
+}  // namespace
+
+TEST(Gen, NoGeneratorCopies) {
+  EXPECT_EQ(15, TestIntSeq() | sum);
+  auto x = TestIntSeq() | take(3);
+  EXPECT_EQ(6, std::move(x) | sum);
+}
+
 TEST(Gen, FromArray) {
   int source[] = {2, 3, 5, 7};
   auto gen = from(source);
@@ -549,6 +595,157 @@ TEST(Gen, Dynamic) {
   EXPECT_EQ(dynamic(5), from(array3) | rconcat | rconcat | sum);
 }
 
+TEST(StringGen, EmptySplit) {
+  auto collect = eachTo<std::string>() | as<vector>();
+  {
+    auto pieces = split("", ',') | collect;
+    EXPECT_EQ(0, pieces.size());
+  }
+
+  // The last delimiter is eaten, just like std::getline
+  {
+    auto pieces = split(",", ',') | collect;
+    EXPECT_EQ(1, pieces.size());
+    EXPECT_EQ("", pieces[0]);
+  }
+
+  {
+    auto pieces = split(",,", ',') | collect;
+    EXPECT_EQ(2, pieces.size());
+    EXPECT_EQ("", pieces[0]);
+    EXPECT_EQ("", pieces[1]);
+  }
+
+  {
+    auto pieces = split(",,", ',') | take(1) | collect;
+    EXPECT_EQ(1, pieces.size());
+    EXPECT_EQ("", pieces[0]);
+  }
+}
+
+TEST(StringGen, Split) {
+  auto collect = eachTo<std::string>() | as<vector>();
+  {
+    auto pieces = split("hello,, world, goodbye, meow", ',') | collect;
+    EXPECT_EQ(5, pieces.size());
+    EXPECT_EQ("hello", pieces[0]);
+    EXPECT_EQ("", pieces[1]);
+    EXPECT_EQ(" world", pieces[2]);
+    EXPECT_EQ(" goodbye", pieces[3]);
+    EXPECT_EQ(" meow", pieces[4]);
+  }
+
+  {
+    auto pieces = split("hello,, world, goodbye, meow", ',')
+                | take(3) | collect;
+    EXPECT_EQ(3, pieces.size());
+    EXPECT_EQ("hello", pieces[0]);
+    EXPECT_EQ("", pieces[1]);
+    EXPECT_EQ(" world", pieces[2]);
+  }
+
+  {
+    auto pieces = split("hello,, world, goodbye, meow", ',')
+                | take(5) | collect;
+    EXPECT_EQ(5, pieces.size());
+    EXPECT_EQ("hello", pieces[0]);
+    EXPECT_EQ("", pieces[1]);
+    EXPECT_EQ(" world", pieces[2]);
+  }
+}
+
+TEST(StringGen, EmptyResplit) {
+  auto collect = eachTo<std::string>() | as<vector>();
+  {
+    auto pieces = from({""}) | resplit(',') | collect;
+    EXPECT_EQ(0, pieces.size());
+  }
+
+  // The last delimiter is eaten, just like std::getline
+  {
+    auto pieces = from({","}) | resplit(',') | collect;
+    EXPECT_EQ(1, pieces.size());
+    EXPECT_EQ("", pieces[0]);
+  }
+
+  {
+    auto pieces = from({",,"}) | resplit(',') | collect;
+    EXPECT_EQ(2, pieces.size());
+    EXPECT_EQ("", pieces[0]);
+    EXPECT_EQ("", pieces[1]);
+  }
+}
+
+TEST(StringGen, Resplit) {
+  auto collect = eachTo<std::string>() | as<vector>();
+  {
+    auto pieces = from({"hello,, world, goodbye, meow"}) |
+      resplit(',') | collect;
+    EXPECT_EQ(5, pieces.size());
+    EXPECT_EQ("hello", pieces[0]);
+    EXPECT_EQ("", pieces[1]);
+    EXPECT_EQ(" world", pieces[2]);
+    EXPECT_EQ(" goodbye", pieces[3]);
+    EXPECT_EQ(" meow", pieces[4]);
+  }
+  {
+    auto pieces = from({"hel", "lo,", ", world", ", goodbye, m", "eow"}) |
+      resplit(',') | collect;
+    EXPECT_EQ(5, pieces.size());
+    EXPECT_EQ("hello", pieces[0]);
+    EXPECT_EQ("", pieces[1]);
+    EXPECT_EQ(" world", pieces[2]);
+    EXPECT_EQ(" goodbye", pieces[3]);
+    EXPECT_EQ(" meow", pieces[4]);
+  }
+}
+
+TEST(FileGen, ByLine) {
+  auto collect = eachTo<std::string>() | as<vector>();
+  test::TemporaryFile file("ByLine");
+  static const std::string lines(
+      "Hello world\n"
+      "This is the second line\n"
+      "\n"
+      "\n"
+      "a few empty lines above\n"
+      "incomplete last line");
+  EXPECT_EQ(lines.size(), write(file.fd(), lines.data(), lines.size()));
+
+  auto expected = from({lines}) | resplit('\n') | collect;
+  auto found = byLine(file.path().c_str()) | collect;
+
+  EXPECT_TRUE(expected == found);
+}
+
+class FileGenBufferedTest : public ::testing::TestWithParam<int> { };
+
+TEST_P(FileGenBufferedTest, FileWriter) {
+  size_t bufferSize = GetParam();
+  test::TemporaryFile file("FileWriter");
+
+  static const std::string lines(
+      "Hello world\n"
+      "This is the second line\n"
+      "\n"
+      "\n"
+      "a few empty lines above\n");
+
+  auto src = from({lines, lines, lines, lines, lines, lines, lines, lines});
+  auto collect = eachTo<std::string>() | as<vector>();
+  auto expected = src | resplit('\n') | collect;
+
+  src | eachAs<StringPiece>() | toFile(file.fd(), bufferSize);
+  auto found = byLine(file.path().c_str()) | collect;
+
+  EXPECT_TRUE(expected == found);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    DifferentBufferSizes,
+    FileGenBufferedTest,
+    ::testing::Values(0, 1, 2, 4, 8, 64, 4096));
+
 int main(int argc, char *argv[]) {
   testing::InitGoogleTest(&argc, argv);
   google::ParseCommandLineFlags(&argc, &argv, true);