/*
- * 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;
using std::set;
using std::unique_ptr;
using std::vector;
+using std::string;
using std::tuple;
using std::make_tuple;
//using std::unordered_map;
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};
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;
}));
}
}
TEST(Gen, Yielders) {
- auto gen = GENERATOR(int, {
+ auto gen = GENERATOR(int) {
for (int i = 1; i <= 5; ++i) {
yield(i);
}
for (int i = 3; ; ++i) {
yield(i * i);
}
- });
+ };
vector<int> expected {
1, 2, 3, 4, 5, 7, 9, 16, 25
};
}
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 {
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);
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);