2 * Copyright 2013 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <glog/logging.h>
18 #include <gtest/gtest.h>
22 #include "folly/experimental/Gen.h"
23 #include "folly/experimental/StringGen.h"
24 #include "folly/experimental/FileGen.h"
25 #include "folly/experimental/TestUtil.h"
26 #include "folly/FBVector.h"
27 #include "folly/Format.h"
28 #include "folly/dynamic.h"
30 using namespace folly::gen;
31 using namespace folly;
35 using std::unique_ptr;
39 using std::make_tuple;
40 //using std::unordered_map;
42 #define EXPECT_SAME(A, B) \
43 static_assert(std::is_same<A, B>::value, "Mismatched: " #A ", " #B)
44 EXPECT_SAME(int&&, typename ArgumentReference<int>::type);
45 EXPECT_SAME(int&, typename ArgumentReference<int&>::type);
46 EXPECT_SAME(const int&, typename ArgumentReference<const int&>::type);
47 EXPECT_SAME(const int&, typename ArgumentReference<const int>::type);
50 ostream& operator<<(ostream& os, const set<T>& values) {
51 return os << from(values);
55 ostream& operator<<(ostream& os, const vector<T>& values) {
57 for (auto& value : values) {
58 if (&value != &values.front()) {
66 auto square = [](int x) { return x * x; };
67 auto add = [](int a, int b) { return a + b; };
68 auto multiply = [](int a, int b) { return a * b; };
70 auto product = foldl(1, multiply);
72 template<typename A, typename B>
73 ostream& operator<<(ostream& os, const pair<A, B>& pair) {
74 return os << "(" << pair.first << ", " << pair.second << ")";
78 auto gen = seq(1, 10);
79 EXPECT_EQ(10, gen | count);
80 EXPECT_EQ(5, gen | take(5) | count);
84 auto gen = seq(1, 10);
85 EXPECT_EQ((1 + 10) * 10 / 2, gen | sum);
86 EXPECT_EQ((1 + 5) * 5 / 2, gen | take(5) | sum);
92 gen | [&](int x) { accum += x; };
95 gen | take(3) | [&](int x) { accum2 += x; };
100 auto expected = vector<int>{4, 9, 16};
101 auto gen = from({2, 3, 4}) | map(square);
102 EXPECT_EQ((vector<int>{4, 9, 16}), gen | as<vector>());
103 EXPECT_EQ((vector<int>{4, 9}), gen | take(2) | as<vector>());
107 // cover the fenceposts of the loop unrolling
108 for (int n = 1; n < 100; ++n) {
109 EXPECT_EQ(n, seq(1, n) | count);
110 EXPECT_EQ(n + 1, seq(1) | take(n + 1) | count);
115 // cover the fenceposts of the loop unrolling
116 for (int n = 1; n < 100; ++n) {
117 EXPECT_EQ(range(0, n) | count, n);
121 TEST(Gen, FromIterators) {
122 vector<int> source {2, 3, 5, 7, 11};
123 auto gen = from(makeRange(source.begin() + 1, source.end() - 1));
124 EXPECT_EQ(3 * 5 * 7, gen | product);
128 auto source = seq(0, 10)
129 | map([](int i) { return std::make_pair(i, i * i); })
130 | as<std::map<int, int>>();
131 auto gen = fromConst(source)
132 | map([&](const std::pair<const int, int>& p) {
133 return p.second - p.first;
135 EXPECT_EQ(330, gen | sum);
139 const auto expected = vector<int>{1, 2, 4, 5, 7, 8};
142 | filter([](int x) { return x % 3; })
144 EXPECT_EQ(expected, actual);
147 TEST(Gen, Contains) {
152 EXPECT_TRUE(gen | contains(49));
153 EXPECT_FALSE(gen | contains(50));
157 seq(1) // infinite, to prove laziness
159 | eachTo<std::string>();
161 // std::string gen, const char* needle
162 EXPECT_TRUE(gen | contains("49"));
167 auto expected = vector<int>{1, 4, 9, 16};
170 | mapped([](int x) { return x * x; })
173 EXPECT_EQ(expected, actual);
179 | mapped([](int x) { return x * x; })
182 EXPECT_EQ((vector<int>{25, 36, 49, 64}), gen | as<vector>());
188 | mapped([](int x) { return x * x; })
189 | until([](int x) { return x >= 1000; });
190 EXPECT_EQ(31, gen | count);
193 TEST(Gen, Composed) {
194 // Operator, Operator
196 filter([](Optional<int>& o) { return o.hasValue(); })
197 | map([](Optional<int>& o) -> int& { return o.value(); });
198 std::vector<Optional<int>> opts {
199 none, 4, none, 6, none
201 EXPECT_EQ(4 * 4 + 6 * 6, from(opts) | valuesOf | map(square) | sum);
203 auto sumOpt = valuesOf | sum;
204 EXPECT_EQ(10, from(opts) | sumOpt);
208 std::vector<int> nums {2, 3, 5, 7};
209 std::map<int, int> mappings { { 3, 9}, {5, 25} };
210 auto gen = from(nums) + (from(mappings) | get<1>());
211 EXPECT_EQ(51, gen | sum);
212 EXPECT_EQ(5, gen | take(2) | sum);
213 EXPECT_EQ(26, gen | take(5) | sum);
217 std::vector<std::vector<int>> nums {{2, 3}, {5, 7}};
218 auto gen = from(nums) | rconcat;
219 EXPECT_EQ(17, gen | sum);
220 EXPECT_EQ(10, gen | take(3) | sum);
223 TEST(Gen, ConcatGen) {
224 auto gen = seq(1, 10)
225 | map([](int i) { return seq(1, i); })
227 EXPECT_EQ(220, gen | sum);
228 EXPECT_EQ(10, gen | take(6) | sum);
231 TEST(Gen, ConcatAlt) {
232 std::vector<std::vector<int>> nums {{2, 3}, {5, 7}};
233 auto actual = from(nums)
234 | map([](std::vector<int>& v) { return from(v); })
238 EXPECT_EQ(expected, actual);
242 auto expected = vector<int>{0, 3, 5, 6, 7, 8, 9};
244 from({8, 6, 7, 5, 3, 0, 9})
247 EXPECT_EQ(expected, actual);
250 TEST(Gen, OrderMoved) {
251 auto expected = vector<int>{0, 9, 25, 36, 49, 64, 81};
253 from({8, 6, 7, 5, 3, 0, 9})
258 EXPECT_EQ(expected, actual);
261 TEST(Gen, OrderTake) {
262 auto expected = vector<int>{9, 8, 7};
264 from({8, 6, 7, 5, 3, 0, 9})
265 | orderByDescending(square)
268 EXPECT_EQ(expected, actual);
272 EXPECT_EQ(7, seq(1, 10)
273 | minBy([](int i) -> double {
280 auto gen = from({"three", "eleven", "four"});
282 EXPECT_EQ("eleven", gen | maxBy(&strlen));
286 fbstring expected = "facebook";
287 fbstring actual = "face";
288 from(StringPiece("book")) | appendTo(actual);
289 EXPECT_EQ(expected, actual);
292 TEST(Gen, FromRValue) {
294 // AFAICT The C++ Standard does not specify what happens to the rvalue
295 // reference of a std::vector when it is used as the 'other' for an rvalue
296 // constructor. Use fbvector because we're sure its size will be zero in
298 folly::fbvector<int> v({1,2,3,4});
300 EXPECT_EQ(v.size(), 4); // ensure that the lvalue version was called!
301 auto expected = 1 * 2 * 3 * 4;
302 EXPECT_EQ(expected, q1 | product);
304 auto q2 = from(std::move(v));
305 EXPECT_EQ(v.size(), 0); // ensure that rvalue version was called
306 EXPECT_EQ(expected, q2 | product);
310 auto q = from([] {return vector<int>({3,7,5}); }());
311 EXPECT_EQ(expected, q | max);
314 for (auto size: {5, 1024, 16384, 1<<20}) {
315 auto q1 = from(vector<int>(size, 2));
316 auto q2 = from(vector<int>(size, 3));
317 // If the rvalue specialization is broken/gone, then the compiler will
318 // (disgustingly!) just store a *reference* to the temporary object,
319 // which is bad. Try to catch this by allocating two temporary vectors
320 // of the same size, so that they'll probably use the same underlying
321 // buffer if q1's vector is destructed before q2's vector is constructed.
322 EXPECT_EQ(size * 2 + size * 3, (q1 | sum) + (q2 | sum));
326 auto q = from(set<int>{1,2,3,2,1});
327 EXPECT_EQ(q | sum, 6);
332 auto expected = vector<int>{5, 6, 4, 7, 3, 8, 2, 9, 1, 10};
335 | orderBy([](int x) { return (5.1 - x) * (5.1 - x); })
337 EXPECT_EQ(expected, actual);
341 int expected = 2 * 3 * 4 * 5;
344 | foldl(1, multiply);
345 EXPECT_EQ(expected, actual);
349 int expected = 2 + 3 + 4 + 5;
350 auto actual = seq(2, 5) | reduce(add);
351 EXPECT_EQ(expected, actual);
354 TEST(Gen, ReduceBad) {
355 auto gen = seq(1) | take(0);
365 std::vector<unique_ptr<int>> ptrs;
366 ptrs.emplace_back(new int(1));
367 EXPECT_NE(ptrs.front().get(), nullptr);
368 auto ptrs2 = from(ptrs) | move | as<vector>();
369 EXPECT_EQ(ptrs.front().get(), nullptr);
370 EXPECT_EQ(**ptrs2.data(), 1);
376 | filter([](int x) { return x > 3; });
377 EXPECT_EQ(4, gen | first);
380 TEST(Gen, FromCopy) {
381 vector<int> v {3, 5};
383 auto copy = fromCopy(v);
384 EXPECT_EQ(8, src | sum);
385 EXPECT_EQ(8, copy | sum);
387 EXPECT_EQ(10, src | sum);
388 EXPECT_EQ(8, copy | sum);
392 std::map<int, int> pairs {
398 auto pairSrc = from(pairs);
399 auto keys = pairSrc | get<0>();
400 auto values = pairSrc | get<1>();
401 EXPECT_EQ(10, keys | sum);
402 EXPECT_EQ(30, values | sum);
403 EXPECT_EQ(30, keys | map(square) | sum);
405 EXPECT_EQ(15, keys | sum);
406 EXPECT_EQ(55, values | sum);
408 vector<tuple<int, int, int>> tuples {
411 make_tuple(3, 9, 27),
413 EXPECT_EQ(36, from(tuples) | get<2>() | sum);
417 EXPECT_TRUE(seq(0) | any);
418 EXPECT_TRUE(seq(0, 1) | any);
419 EXPECT_TRUE(seq(0, 10) | any([](int i) { return i == 7; }));
420 EXPECT_FALSE(seq(0, 10) | any([](int i) { return i == 11; }));
422 EXPECT_TRUE(from({1}) | any);
423 EXPECT_FALSE(range(0, 0) | any);
424 EXPECT_FALSE(from({1}) | take(0) | any);
428 EXPECT_TRUE(seq(0, 10) | all([](int i) { return i < 11; }));
429 EXPECT_FALSE(seq(0, 10) | all([](int i) { return i < 5; }));
430 EXPECT_FALSE(seq(0) | all([](int i) { return i < 10; }));
432 // empty lists satisfies all
433 EXPECT_TRUE(seq(0) | take(0) | all([](int i) { return i < 50; }));
434 EXPECT_TRUE(seq(0) | take(0) | all([](int i) { return i > 50; }));
437 TEST(Gen, Yielders) {
438 auto gen = GENERATOR(int) {
439 for (int i = 1; i <= 5; ++i) {
443 for (int i = 3; ; ++i) {
447 vector<int> expected {
448 1, 2, 3, 4, 5, 7, 9, 16, 25
450 EXPECT_EQ(expected, gen | take(9) | as<vector>());
453 TEST(Gen, NestedYield) {
454 auto nums = GENERATOR(int) {
455 for (int i = 1; ; ++i) {
459 auto gen = GENERATOR(int) {
460 nums | take(10) | yield;
461 seq(1, 5) | [&](int i) {
465 EXPECT_EQ(70, gen | sum);
468 TEST(Gen, MapYielders) {
471 return GENERATOR(int) {
473 for (i = 1; i < n; ++i)
480 vector<int> expected {
485 1, 2, 3, 4, 5, 4, 3, 2, 1,
487 EXPECT_EQ(expected, gen | as<vector>());
490 TEST(Gen, VirtualGen) {
491 VirtualGen<int> v(seq(1, 10));
492 EXPECT_EQ(55, v | sum);
494 EXPECT_EQ(385, v | sum);
496 EXPECT_EQ(55, v | sum);
497 EXPECT_EQ(30, v | take(4) | sum);
501 TEST(Gen, CustomType) {
505 auto gen = from({Foo{2}, Foo{3}})
506 | map([](const Foo& f) { return f.y; });
507 EXPECT_EQ(5, gen | sum);
510 TEST(Gen, NoNeedlessCopies) {
512 | map([](int x) { return unique_ptr<int>(new int(x)); })
513 | map([](unique_ptr<int> p) { return p; })
514 | map([](unique_ptr<int>&& p) { return std::move(p); })
515 | map([](const unique_ptr<int>& p) { return *p; });
516 EXPECT_EQ(15, gen | sum);
517 EXPECT_EQ(6, gen | take(3) | sum);
521 class TestIntSeq : public GenImpl<int, TestIntSeq> {
525 template <class Body>
526 bool apply(Body&& body) const {
527 for (int i = 1; i < 6; ++i) {
535 TestIntSeq(TestIntSeq&&) = default;
536 TestIntSeq& operator=(TestIntSeq&&) = default;
537 TestIntSeq(const TestIntSeq&) = delete;
538 TestIntSeq& operator=(const TestIntSeq&) = delete;
542 TEST(Gen, NoGeneratorCopies) {
543 EXPECT_EQ(15, TestIntSeq() | sum);
544 auto x = TestIntSeq() | take(3);
545 EXPECT_EQ(6, std::move(x) | sum);
548 TEST(Gen, FromArray) {
549 int source[] = {2, 3, 5, 7};
550 auto gen = from(source);
551 EXPECT_EQ(2 * 3 * 5 * 7, gen | product);
554 TEST(Gen, FromStdArray) {
555 std::array<int,4> source {{2, 3, 5, 7}};
556 auto gen = from(source);
557 EXPECT_EQ(2 * 3 * 5 * 7, gen | product);
560 TEST(Gen, StringConcat) {
561 auto gen = seq(1, 10)
562 | map([](int n) { return folly::to<fbstring>(n); })
564 EXPECT_EQ("12345678910", gen | as<fbstring>());
572 CopyCounter() : copies(0), moves(0) {
576 CopyCounter(CopyCounter&& source) {
577 *this = std::move(source);
581 CopyCounter(const CopyCounter& source) {
590 CopyCounter& operator=(const CopyCounter& source) {
591 this->copies = source.copies + 1;
592 this->moves = source.moves;
596 CopyCounter& operator=(CopyCounter&& source) {
597 this->copies = source.copies;
598 this->moves = source.moves + 1;
603 int CopyCounter::alive = 0;
605 TEST(Gen, CopyCount) {
606 vector<CopyCounter> originals;
607 originals.emplace_back();
608 EXPECT_EQ(1, originals.size());
609 EXPECT_EQ(0, originals.back().copies);
611 vector<CopyCounter> copies = from(originals) | as<vector>();
612 EXPECT_EQ(1, copies.back().copies);
613 EXPECT_EQ(0, copies.back().moves);
615 vector<CopyCounter> moves = from(originals) | move | as<vector>();
616 EXPECT_EQ(0, moves.back().copies);
617 EXPECT_EQ(1, moves.back().moves);
620 // test dynamics with various layers of nested arrays.
622 dynamic array1 = {1, 2};
623 EXPECT_EQ(dynamic(3), from(array1) | sum);
624 dynamic array2 = {{1}, {1, 2}};
625 EXPECT_EQ(dynamic(4), from(array2) | rconcat | sum);
626 dynamic array3 = {{{1}}, {{1}, {1, 2}}};
627 EXPECT_EQ(dynamic(5), from(array3) | rconcat | rconcat | sum);
630 TEST(StringGen, EmptySplit) {
631 auto collect = eachTo<std::string>() | as<vector>();
633 auto pieces = split("", ',') | collect;
634 EXPECT_EQ(0, pieces.size());
637 // The last delimiter is eaten, just like std::getline
639 auto pieces = split(",", ',') | collect;
640 EXPECT_EQ(1, pieces.size());
641 EXPECT_EQ("", pieces[0]);
645 auto pieces = split(",,", ',') | collect;
646 EXPECT_EQ(2, pieces.size());
647 EXPECT_EQ("", pieces[0]);
648 EXPECT_EQ("", pieces[1]);
652 auto pieces = split(",,", ',') | take(1) | collect;
653 EXPECT_EQ(1, pieces.size());
654 EXPECT_EQ("", pieces[0]);
658 TEST(StringGen, Split) {
659 auto collect = eachTo<std::string>() | as<vector>();
661 auto pieces = split("hello,, world, goodbye, meow", ',') | collect;
662 EXPECT_EQ(5, pieces.size());
663 EXPECT_EQ("hello", pieces[0]);
664 EXPECT_EQ("", pieces[1]);
665 EXPECT_EQ(" world", pieces[2]);
666 EXPECT_EQ(" goodbye", pieces[3]);
667 EXPECT_EQ(" meow", pieces[4]);
671 auto pieces = split("hello,, world, goodbye, meow", ',')
673 EXPECT_EQ(3, pieces.size());
674 EXPECT_EQ("hello", pieces[0]);
675 EXPECT_EQ("", pieces[1]);
676 EXPECT_EQ(" world", pieces[2]);
680 auto pieces = split("hello,, world, goodbye, meow", ',')
682 EXPECT_EQ(5, pieces.size());
683 EXPECT_EQ("hello", pieces[0]);
684 EXPECT_EQ("", pieces[1]);
685 EXPECT_EQ(" world", pieces[2]);
689 TEST(StringGen, EmptyResplit) {
690 auto collect = eachTo<std::string>() | as<vector>();
692 auto pieces = from({""}) | resplit(',') | collect;
693 EXPECT_EQ(0, pieces.size());
696 // The last delimiter is eaten, just like std::getline
698 auto pieces = from({","}) | resplit(',') | collect;
699 EXPECT_EQ(1, pieces.size());
700 EXPECT_EQ("", pieces[0]);
704 auto pieces = from({",,"}) | resplit(',') | collect;
705 EXPECT_EQ(2, pieces.size());
706 EXPECT_EQ("", pieces[0]);
707 EXPECT_EQ("", pieces[1]);
711 TEST(StringGen, Resplit) {
712 auto collect = eachTo<std::string>() | as<vector>();
714 auto pieces = from({"hello,, world, goodbye, meow"}) |
715 resplit(',') | collect;
716 EXPECT_EQ(5, pieces.size());
717 EXPECT_EQ("hello", pieces[0]);
718 EXPECT_EQ("", pieces[1]);
719 EXPECT_EQ(" world", pieces[2]);
720 EXPECT_EQ(" goodbye", pieces[3]);
721 EXPECT_EQ(" meow", pieces[4]);
724 auto pieces = from({"hel", "lo,", ", world", ", goodbye, m", "eow"}) |
725 resplit(',') | collect;
726 EXPECT_EQ(5, pieces.size());
727 EXPECT_EQ("hello", pieces[0]);
728 EXPECT_EQ("", pieces[1]);
729 EXPECT_EQ(" world", pieces[2]);
730 EXPECT_EQ(" goodbye", pieces[3]);
731 EXPECT_EQ(" meow", pieces[4]);
736 void runUnsplitSuite(F fn) {
738 fn("hello,world,goodbye");
745 TEST(StringGen, Unsplit) {
747 auto basicFn = [](const StringPiece& s) {
748 EXPECT_EQ(split(s, ',') | unsplit(','), s);
751 auto existingBuffer = [](const StringPiece& s) {
752 folly::fbstring buffer("asdf");
753 split(s, ',') | unsplit(',', &buffer);
754 auto expected = folly::to<folly::fbstring>(
755 "asdf", s.empty() ? "" : ",", s);
756 EXPECT_EQ(expected, buffer);
759 auto emptyBuffer = [](const StringPiece& s) {
761 split(s, ',') | unsplit(',', &buffer);
762 EXPECT_EQ(s, buffer);
765 auto stringDelim = [](const StringPiece& s) {
766 EXPECT_EQ(s, split(s, ',') | unsplit(","));
768 split(s, ',') | unsplit(",", &buffer);
769 EXPECT_EQ(buffer, s);
772 runUnsplitSuite(basicFn);
773 runUnsplitSuite(existingBuffer);
774 runUnsplitSuite(emptyBuffer);
775 runUnsplitSuite(stringDelim);
776 EXPECT_EQ("1, 2, 3", seq(1, 3) | unsplit(", "));
779 TEST(FileGen, ByLine) {
780 auto collect = eachTo<std::string>() | as<vector>();
781 test::TemporaryFile file("ByLine");
782 static const std::string lines(
784 "This is the second line\n"
787 "a few empty lines above\n"
788 "incomplete last line");
789 EXPECT_EQ(lines.size(), write(file.fd(), lines.data(), lines.size()));
791 auto expected = from({lines}) | resplit('\n') | collect;
792 auto found = byLine(file.path().c_str()) | collect;
794 EXPECT_TRUE(expected == found);
797 class FileGenBufferedTest : public ::testing::TestWithParam<int> { };
799 TEST_P(FileGenBufferedTest, FileWriter) {
800 size_t bufferSize = GetParam();
801 test::TemporaryFile file("FileWriter");
803 static const std::string lines(
805 "This is the second line\n"
808 "a few empty lines above\n");
810 auto src = from({lines, lines, lines, lines, lines, lines, lines, lines});
811 auto collect = eachTo<std::string>() | as<vector>();
812 auto expected = src | resplit('\n') | collect;
814 src | eachAs<StringPiece>() | toFile(file.fd(), bufferSize);
815 auto found = byLine(file.path().c_str()) | collect;
817 EXPECT_TRUE(expected == found);
820 INSTANTIATE_TEST_CASE_P(
821 DifferentBufferSizes,
823 ::testing::Values(0, 1, 2, 4, 8, 64, 4096));
825 int main(int argc, char *argv[]) {
826 testing::InitGoogleTest(&argc, argv);
827 google::ParseCommandLineFlags(&argc, &argv, true);
828 return RUN_ALL_TESTS();