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>
23 #include "folly/experimental/Gen.h"
24 #include "folly/experimental/StringGen.h"
25 #include "folly/experimental/CombineGen.h"
26 #include "folly/experimental/FileGen.h"
27 #include "folly/experimental/TestUtil.h"
28 #include "folly/FBString.h"
29 #include "folly/FBVector.h"
30 #include "folly/Format.h"
31 #include "folly/dynamic.h"
33 using namespace folly::gen;
34 using namespace folly;
38 using std::unique_ptr;
42 using std::make_tuple;
44 #define EXPECT_SAME(A, B) \
45 static_assert(std::is_same<A, B>::value, "Mismatched: " #A ", " #B)
46 EXPECT_SAME(int&&, typename ArgumentReference<int>::type);
47 EXPECT_SAME(int&, typename ArgumentReference<int&>::type);
48 EXPECT_SAME(const int&, typename ArgumentReference<const int&>::type);
49 EXPECT_SAME(const int&, typename ArgumentReference<const int>::type);
52 ostream& operator<<(ostream& os, const set<T>& values) {
53 return os << from(values);
57 ostream& operator<<(ostream& os, const vector<T>& values) {
59 for (auto& value : values) {
60 if (&value != &values.front()) {
68 auto square = [](int x) { return x * x; };
69 auto add = [](int a, int b) { return a + b; };
70 auto multiply = [](int a, int b) { return a * b; };
72 auto product = foldl(1, multiply);
74 template<typename A, typename B>
75 ostream& operator<<(ostream& os, const pair<A, B>& pair) {
76 return os << "(" << pair.first << ", " << pair.second << ")";
80 auto gen = seq(1, 10);
81 EXPECT_EQ(10, gen | count);
82 EXPECT_EQ(5, gen | take(5) | count);
86 auto gen = seq(1, 10);
87 EXPECT_EQ((1 + 10) * 10 / 2, gen | sum);
88 EXPECT_EQ((1 + 5) * 5 / 2, gen | take(5) | sum);
94 gen | [&](int x) { accum += x; };
97 gen | take(3) | [&](int x) { accum2 += x; };
102 auto expected = vector<int>{4, 9, 16};
103 auto gen = from({2, 3, 4}) | map(square);
104 EXPECT_EQ((vector<int>{4, 9, 16}), gen | as<vector>());
105 EXPECT_EQ((vector<int>{4, 9}), gen | take(2) | as<vector>());
110 Counter(int start = 0)
114 int count() const { return c; }
115 int incr() { return ++c; }
117 int& ref() { return c; }
118 const int& ref() const { return c; }
122 auto counters = seq(1, 10) | eachAs<Counter>() | as<vector>();
123 EXPECT_EQ(10 * (1 + 10) / 2,
125 | member(&Counter::count)
127 EXPECT_EQ(10 * (2 + 11) / 2,
129 | member(&Counter::incr)
131 EXPECT_EQ(10 * (2 + 11) / 2,
133 | member(&Counter::count)
136 // type-verifications
137 auto m = empty<Counter&>();
138 auto c = empty<const Counter&>();
139 m | member(&Counter::incr) | assert_type<int&&>();
140 m | member(&Counter::count) | assert_type<int&&>();
141 m | member(&Counter::count) | assert_type<int&&>();
142 m | member<Const>(&Counter::ref) | assert_type<const int&>();
143 m | member<Mutable>(&Counter::ref) | assert_type<int&>();
144 c | member<Const>(&Counter::ref) | assert_type<const int&>();
149 X() : a(2), b(3), c(4), d(b) {}
154 int& d; // can't access this with a field pointer.
157 std::vector<X> xs(1);
158 EXPECT_EQ(2, from(xs)
161 EXPECT_EQ(3, from(xs)
164 EXPECT_EQ(4, from(xs)
168 empty<X&>() | field(&X::a) | assert_type<const int&>();
169 empty<X&>() | field(&X::b) | assert_type<int&>();
170 empty<X&>() | field(&X::c) | assert_type<int&>();
171 empty<X&&>() | field(&X::a) | assert_type<const int&&>();
172 empty<X&&>() | field(&X::b) | assert_type<int&&>();
173 empty<X&&>() | field(&X::c) | assert_type<int&&>();
174 // references don't imply ownership so they're not moved
175 empty<const X&>() | field(&X::a) | assert_type<const int&>();
176 empty<const X&>() | field(&X::b) | assert_type<const int&>();
177 // 'mutable' has no effect on field pointers, by C++ spec
178 empty<const X&>() | field(&X::c) | assert_type<const int&>();
180 // can't form pointer-to-reference field: empty<X&>() | field(&X::d)
184 // cover the fenceposts of the loop unrolling
185 for (int n = 1; n < 100; ++n) {
186 EXPECT_EQ(n, seq(1, n) | count);
187 EXPECT_EQ(n + 1, seq(1) | take(n + 1) | count);
192 // cover the fenceposts of the loop unrolling
193 for (int n = 1; n < 100; ++n) {
194 EXPECT_EQ(range(0, n) | count, n);
198 TEST(Gen, FromIterators) {
199 vector<int> source {2, 3, 5, 7, 11};
200 auto gen = from(makeRange(source.begin() + 1, source.end() - 1));
201 EXPECT_EQ(3 * 5 * 7, gen | product);
205 auto source = seq(0, 10)
206 | map([](int i) { return std::make_pair(i, i * i); })
207 | as<std::map<int, int>>();
208 auto gen = fromConst(source)
209 | map([&](const std::pair<const int, int>& p) {
210 return p.second - p.first;
212 EXPECT_EQ(330, gen | sum);
216 const auto expected = vector<int>{1, 2, 4, 5, 7, 8};
219 | filter([](int x) { return x % 3; })
221 EXPECT_EQ(expected, actual);
224 TEST(Gen, Contains) {
229 EXPECT_TRUE(gen | contains(49));
230 EXPECT_FALSE(gen | contains(50));
234 seq(1) // infinite, to prove laziness
236 | eachTo<std::string>();
238 // std::string gen, const char* needle
239 EXPECT_TRUE(gen | take(9999) | contains("49"));
244 auto expected = vector<int>{1, 4, 9, 16};
247 | mapped([](int x) { return x * x; })
250 EXPECT_EQ(expected, actual);
254 std::mt19937 rnd(42);
259 std::unordered_map<int,int> hits;
260 const int kNumIters = 80;
261 for (int i = 0; i < kNumIters; i++) {
262 auto vec = sampler | as<vector<int>>();
263 EXPECT_EQ(vec.size(), 50);
264 auto uniq = fromConst(vec) | as<set<int>>();
265 EXPECT_EQ(uniq.size(), vec.size()); // sampling without replacement
271 // In 80 separate samples of our range, we should have seen every value
272 // at least once and no value all 80 times. (The odds of either of those
273 // events is 1/2^80).
274 EXPECT_EQ(hits.size(), 100);
275 for (auto hit: hits) {
276 EXPECT_GT(hit.second, 0);
277 EXPECT_LT(hit.second, kNumIters);
283 EXPECT_EQ((small | sum), 15);
284 EXPECT_EQ((small | take(3) | count), 3);
290 | mapped([](int x) { return x * x; })
293 EXPECT_EQ((vector<int>{25, 36, 49, 64}), gen | as<vector>());
299 | mapped([](int x) { return x * x; })
300 | until([](int x) { return x >= 1000; });
301 EXPECT_EQ(31, gen | count);
304 auto even = [](int i) -> bool { return i % 2 == 0; };
305 auto odd = [](int i) -> bool { return i % 2 == 1; };
307 TEST(CombineGen, Interleave) {
308 { // large (infinite) base, small container
309 auto base = seq(1) | filter(odd);
310 auto toInterleave = seq(1, 6) | filter(even);
311 auto interleaved = base | interleave(toInterleave | as<vector>());
312 EXPECT_EQ(interleaved | as<vector>(), vector<int>({1, 2, 3, 4, 5, 6}));
314 { // small base, large container
315 auto base = seq(1) | filter(odd) | take(3);
316 auto toInterleave = seq(1) | filter(even) | take(50);
317 auto interleaved = base | interleave(toInterleave | as<vector>());
318 EXPECT_EQ(interleaved | as<vector>(),
319 vector<int>({1, 2, 3, 4, 5, 6}));
323 TEST(CombineGen, Zip) {
325 // We rely on std::move(fbvector) emptying the source vector
326 auto zippee = fbvector<string>{"one", "two", "three"};
328 auto combined = base0
331 ASSERT_EQ(combined.size(), 3);
332 EXPECT_EQ(std::get<0>(combined[0]), 1);
333 EXPECT_EQ(std::get<1>(combined[0]), "one");
334 EXPECT_EQ(std::get<0>(combined[1]), 2);
335 EXPECT_EQ(std::get<1>(combined[1]), "two");
336 EXPECT_EQ(std::get<0>(combined[2]), 3);
337 EXPECT_EQ(std::get<1>(combined[2]), "three");
338 ASSERT_FALSE(zippee.empty());
339 EXPECT_FALSE(zippee.front().empty()); // shouldn't have been move'd
342 { // same as top, but using std::move.
343 auto combined = base0
344 | zip(std::move(zippee))
346 ASSERT_EQ(combined.size(), 3);
347 EXPECT_EQ(std::get<0>(combined[0]), 1);
348 EXPECT_TRUE(zippee.empty());
351 { // same as top, but base is truncated
352 auto baseFinite = seq(1) | take(1);
353 auto combined = baseFinite
354 | zip(vector<string>{"one", "two", "three"})
356 ASSERT_EQ(combined.size(), 1);
357 EXPECT_EQ(std::get<0>(combined[0]), 1);
358 EXPECT_EQ(std::get<1>(combined[0]), "one");
362 TEST(CombineGen, TupleFlatten) {
363 vector<tuple<int,string>> intStringTupleVec{
364 tuple<int,string>{1, "1"},
365 tuple<int,string>{2, "2"},
366 tuple<int,string>{3, "3"},
369 vector<tuple<char>> charTupleVec{
376 vector<double> doubleVec{
384 auto zipped1 = from(intStringTupleVec)
386 | assert_type<tuple<tuple<int, string>, tuple<char>>>()
388 EXPECT_EQ(std::get<0>(zipped1[0]), std::make_tuple(1, "1"));
389 EXPECT_EQ(std::get<1>(zipped1[0]), std::make_tuple('A'));
391 auto zipped2 = from(zipped1)
393 | assert_type<tuple<int, string, char>&&>()
395 ASSERT_EQ(zipped2.size(), 3);
396 EXPECT_EQ(zipped2[0], std::make_tuple(1, "1", 'A'));
398 auto zipped3 = from(charTupleVec)
399 | zip(intStringTupleVec)
401 | assert_type<tuple<char, int, string>&&>()
403 ASSERT_EQ(zipped3.size(), 3);
404 EXPECT_EQ(zipped3[0], std::make_tuple('A', 1, "1"));
406 auto zipped4 = from(intStringTupleVec)
409 | assert_type<tuple<int, string, double>&&>()
411 ASSERT_EQ(zipped4.size(), 3);
412 EXPECT_EQ(zipped4[0], std::make_tuple(1, "1", 1.0));
414 auto zipped5 = from(doubleVec)
416 | assert_type<tuple<double, double>>()
417 | tuple_flatten // essentially a no-op
418 | assert_type<tuple<double, double>&&>()
420 ASSERT_EQ(zipped5.size(), 5);
421 EXPECT_EQ(zipped5[0], std::make_tuple(1.0, 1.0));
423 auto zipped6 = from(intStringTupleVec)
428 | assert_type<tuple<int, string, char, double>&&>()
430 ASSERT_EQ(zipped6.size(), 3);
431 EXPECT_EQ(zipped6[0], std::make_tuple(1, "1", 'A', 1.0));
434 TEST(Gen, Composed) {
435 // Operator, Operator
437 filter([](Optional<int>& o) { return o.hasValue(); })
438 | map([](Optional<int>& o) -> int& { return o.value(); });
439 std::vector<Optional<int>> opts {
440 none, 4, none, 6, none
442 EXPECT_EQ(4 * 4 + 6 * 6, from(opts) | valuesOf | map(square) | sum);
444 auto sumOpt = valuesOf | sum;
445 EXPECT_EQ(10, from(opts) | sumOpt);
449 std::vector<int> nums {2, 3, 5, 7};
450 std::map<int, int> mappings { { 3, 9}, {5, 25} };
451 auto gen = from(nums) + (from(mappings) | get<1>());
452 EXPECT_EQ(51, gen | sum);
453 EXPECT_EQ(5, gen | take(2) | sum);
454 EXPECT_EQ(26, gen | take(5) | sum);
458 std::vector<std::vector<int>> nums {{2, 3}, {5, 7}};
459 auto gen = from(nums) | rconcat;
460 EXPECT_EQ(17, gen | sum);
461 EXPECT_EQ(10, gen | take(3) | sum);
464 TEST(Gen, ConcatGen) {
465 auto gen = seq(1, 10)
466 | map([](int i) { return seq(1, i); })
468 EXPECT_EQ(220, gen | sum);
469 EXPECT_EQ(10, gen | take(6) | sum);
472 TEST(Gen, ConcatAlt) {
473 std::vector<std::vector<int>> nums {{2, 3}, {5, 7}};
474 auto actual = from(nums)
475 | map([](std::vector<int>& v) { return from(v); })
479 EXPECT_EQ(expected, actual);
483 auto expected = vector<int>{0, 3, 5, 6, 7, 8, 9};
485 from({8, 6, 7, 5, 3, 0, 9})
488 EXPECT_EQ(expected, actual);
491 TEST(Gen, OrderMoved) {
492 auto expected = vector<int>{0, 9, 25, 36, 49, 64, 81};
494 from({8, 6, 7, 5, 3, 0, 9})
499 EXPECT_EQ(expected, actual);
502 TEST(Gen, OrderTake) {
503 auto expected = vector<int>{9, 8, 7};
505 from({8, 6, 7, 5, 3, 0, 9})
506 | orderByDescending(square)
509 EXPECT_EQ(expected, actual);
512 TEST(Gen, Distinct) {
513 auto expected = vector<int>{3, 1, 2};
515 from({3, 1, 3, 2, 1, 2, 3})
518 EXPECT_EQ(expected, actual);
521 TEST(Gen, DistinctBy) { // 0 1 4 9 6 5 6 9 4 1 0
522 auto expected = vector<int>{0, 1, 2, 3, 4, 5};
525 | distinctBy([](int i) { return i * i % 10; })
527 EXPECT_EQ(expected, actual);
530 TEST(Gen, DistinctMove) { // 0 1 4 9 6 5 6 9 4 1 0
531 auto expected = vector<int>{0, 1, 2, 3, 4, 5};
534 | mapped([](int i) { return std::unique_ptr<int>(new int(i)); })
535 // see comment below about selector parameters for Distinct
536 | distinctBy([](const std::unique_ptr<int>& pi) { return *pi * *pi % 10; })
537 | mapped([](std::unique_ptr<int> pi) { return *pi; })
540 // NOTE(tjackson): the following line intentionally doesn't work:
541 // | distinctBy([](std::unique_ptr<int> pi) { return *pi * *pi % 10; })
542 // This is because distinctBy because the selector intentionally requires a
543 // const reference. If it required a move-reference, the value might get
544 // gutted by the selector before said value could be passed to downstream
546 EXPECT_EQ(expected, actual);
550 EXPECT_EQ(7, seq(1, 10)
551 | minBy([](int i) -> double {
558 auto gen = from({"three", "eleven", "four"});
560 EXPECT_EQ("eleven", gen | maxBy(&strlen));
564 fbstring expected = "facebook";
565 fbstring actual = "face";
566 from(StringPiece("book")) | appendTo(actual);
567 EXPECT_EQ(expected, actual);
570 TEST(Gen, FromRValue) {
572 // AFAICT The C++ Standard does not specify what happens to the rvalue
573 // reference of a std::vector when it is used as the 'other' for an rvalue
574 // constructor. Use fbvector because we're sure its size will be zero in
576 folly::fbvector<int> v({1,2,3,4});
578 EXPECT_EQ(v.size(), 4); // ensure that the lvalue version was called!
579 auto expected = 1 * 2 * 3 * 4;
580 EXPECT_EQ(expected, q1 | product);
582 auto q2 = from(std::move(v));
583 EXPECT_EQ(v.size(), 0); // ensure that rvalue version was called
584 EXPECT_EQ(expected, q2 | product);
588 auto q = from([] {return vector<int>({3,7,5}); }());
589 EXPECT_EQ(expected, q | max);
592 for (auto size: {5, 1024, 16384, 1<<20}) {
593 auto q1 = from(vector<int>(size, 2));
594 auto q2 = from(vector<int>(size, 3));
595 // If the rvalue specialization is broken/gone, then the compiler will
596 // (disgustingly!) just store a *reference* to the temporary object,
597 // which is bad. Try to catch this by allocating two temporary vectors
598 // of the same size, so that they'll probably use the same underlying
599 // buffer if q1's vector is destructed before q2's vector is constructed.
600 EXPECT_EQ(size * 2 + size * 3, (q1 | sum) + (q2 | sum));
604 auto q = from(set<int>{1,2,3,2,1});
605 EXPECT_EQ(q | sum, 6);
610 auto expected = vector<int>{5, 6, 4, 7, 3, 8, 2, 9, 1, 10};
613 | orderBy([](int x) { return (5.1 - x) * (5.1 - x); })
615 EXPECT_EQ(expected, actual);
619 int expected = 2 * 3 * 4 * 5;
622 | foldl(1, multiply);
623 EXPECT_EQ(expected, actual);
627 int expected = 2 + 3 + 4 + 5;
628 auto actual = seq(2, 5) | reduce(add);
629 EXPECT_EQ(expected, actual);
632 TEST(Gen, ReduceBad) {
633 auto gen = seq(1) | take(0);
643 std::vector<unique_ptr<int>> ptrs;
644 ptrs.emplace_back(new int(1));
645 EXPECT_NE(ptrs.front().get(), nullptr);
646 auto ptrs2 = from(ptrs) | move | as<vector>();
647 EXPECT_EQ(ptrs.front().get(), nullptr);
648 EXPECT_EQ(**ptrs2.data(), 1);
654 | filter([](int x) { return x > 3; });
655 EXPECT_EQ(4, gen | first);
658 TEST(Gen, FromCopy) {
659 vector<int> v {3, 5};
661 auto copy = fromCopy(v);
662 EXPECT_EQ(8, src | sum);
663 EXPECT_EQ(8, copy | sum);
665 EXPECT_EQ(10, src | sum);
666 EXPECT_EQ(8, copy | sum);
670 std::map<int, int> pairs {
676 auto pairSrc = from(pairs);
677 auto keys = pairSrc | get<0>();
678 auto values = pairSrc | get<1>();
679 EXPECT_EQ(10, keys | sum);
680 EXPECT_EQ(30, values | sum);
681 EXPECT_EQ(30, keys | map(square) | sum);
683 EXPECT_EQ(15, keys | sum);
684 EXPECT_EQ(55, values | sum);
686 vector<tuple<int, int, int>> tuples {
689 make_tuple(3, 9, 27),
691 EXPECT_EQ(36, from(tuples) | get<2>() | sum);
695 EXPECT_TRUE(seq(0) | any);
696 EXPECT_TRUE(seq(0, 1) | any);
697 EXPECT_TRUE(seq(0, 10) | any([](int i) { return i == 7; }));
698 EXPECT_FALSE(seq(0, 10) | any([](int i) { return i == 11; }));
700 EXPECT_TRUE(from({1}) | any);
701 EXPECT_FALSE(range(0, 0) | any);
702 EXPECT_FALSE(from({1}) | take(0) | any);
706 EXPECT_TRUE(seq(0, 10) | all([](int i) { return i < 11; }));
707 EXPECT_FALSE(seq(0, 10) | all([](int i) { return i < 5; }));
708 EXPECT_FALSE(seq(0) | take(9999) | all([](int i) { return i < 10; }));
710 // empty lists satisfies all
711 EXPECT_TRUE(seq(0) | take(0) | all([](int i) { return i < 50; }));
712 EXPECT_TRUE(seq(0) | take(0) | all([](int i) { return i > 50; }));
715 TEST(Gen, Yielders) {
716 auto gen = GENERATOR(int) {
717 for (int i = 1; i <= 5; ++i) {
721 for (int i = 3; ; ++i) {
725 vector<int> expected {
726 1, 2, 3, 4, 5, 7, 9, 16, 25
728 EXPECT_EQ(expected, gen | take(9) | as<vector>());
731 TEST(Gen, NestedYield) {
732 auto nums = GENERATOR(int) {
733 for (int i = 1; ; ++i) {
737 auto gen = GENERATOR(int) {
738 nums | take(10) | yield;
739 seq(1, 5) | [&](int i) {
743 EXPECT_EQ(70, gen | sum);
746 TEST(Gen, MapYielders) {
749 return GENERATOR(int) {
751 for (i = 1; i < n; ++i)
758 vector<int> expected {
763 1, 2, 3, 4, 5, 4, 3, 2, 1,
765 EXPECT_EQ(expected, gen | as<vector>());
768 TEST(Gen, VirtualGen) {
769 VirtualGen<int> v(seq(1, 10));
770 EXPECT_EQ(55, v | sum);
772 EXPECT_EQ(385, v | sum);
774 EXPECT_EQ(55, v | sum);
775 EXPECT_EQ(30, v | take(4) | sum);
779 TEST(Gen, CustomType) {
783 auto gen = from({Foo{2}, Foo{3}})
784 | map([](const Foo& f) { return f.y; });
785 EXPECT_EQ(5, gen | sum);
788 TEST(Gen, NoNeedlessCopies) {
790 | map([](int x) { return unique_ptr<int>(new int(x)); })
791 | map([](unique_ptr<int> p) { return p; })
792 | map([](unique_ptr<int>&& p) { return std::move(p); })
793 | map([](const unique_ptr<int>& p) { return *p; });
794 EXPECT_EQ(15, gen | sum);
795 EXPECT_EQ(6, gen | take(3) | sum);
800 class TestIntSeq : public GenImpl<int, TestIntSeq> {
804 template <class Body>
805 bool apply(Body&& body) const {
806 for (int i = 1; i < 6; ++i) {
814 TestIntSeq(TestIntSeq&&) = default;
815 TestIntSeq& operator=(TestIntSeq&&) = default;
816 TestIntSeq(const TestIntSeq&) = delete;
817 TestIntSeq& operator=(const TestIntSeq&) = delete;
822 TEST(Gen, NoGeneratorCopies) {
823 EXPECT_EQ(15, TestIntSeq() | sum);
824 auto x = TestIntSeq() | take(3);
825 EXPECT_EQ(6, std::move(x) | sum);
828 TEST(Gen, FromArray) {
829 int source[] = {2, 3, 5, 7};
830 auto gen = from(source);
831 EXPECT_EQ(2 * 3 * 5 * 7, gen | product);
834 TEST(Gen, FromStdArray) {
835 std::array<int,4> source {{2, 3, 5, 7}};
836 auto gen = from(source);
837 EXPECT_EQ(2 * 3 * 5 * 7, gen | product);
840 TEST(Gen, StringConcat) {
841 auto gen = seq(1, 10)
842 | map([](int n) { return folly::to<fbstring>(n); })
844 EXPECT_EQ("12345678910", gen | as<fbstring>());
852 CopyCounter() : copies(0), moves(0) {
856 CopyCounter(CopyCounter&& source) {
857 *this = std::move(source);
861 CopyCounter(const CopyCounter& source) {
870 CopyCounter& operator=(const CopyCounter& source) {
871 this->copies = source.copies + 1;
872 this->moves = source.moves;
876 CopyCounter& operator=(CopyCounter&& source) {
877 this->copies = source.copies;
878 this->moves = source.moves + 1;
883 int CopyCounter::alive = 0;
885 TEST(Gen, CopyCount) {
886 vector<CopyCounter> originals;
887 originals.emplace_back();
888 EXPECT_EQ(1, originals.size());
889 EXPECT_EQ(0, originals.back().copies);
891 vector<CopyCounter> copies = from(originals) | as<vector>();
892 EXPECT_EQ(1, copies.back().copies);
893 EXPECT_EQ(0, copies.back().moves);
895 vector<CopyCounter> moves = from(originals) | move | as<vector>();
896 EXPECT_EQ(0, moves.back().copies);
897 EXPECT_EQ(1, moves.back().moves);
900 // test dynamics with various layers of nested arrays.
902 dynamic array1 = {1, 2};
903 EXPECT_EQ(dynamic(3), from(array1) | sum);
904 dynamic array2 = {{1}, {1, 2}};
905 EXPECT_EQ(dynamic(4), from(array2) | rconcat | sum);
906 dynamic array3 = {{{1}}, {{1}, {1, 2}}};
907 EXPECT_EQ(dynamic(5), from(array3) | rconcat | rconcat | sum);
910 TEST(Gen, DynamicObject) {
911 const dynamic obj = dynamic::object(1, 2)(3, 4);
912 EXPECT_EQ(dynamic(4), from(obj.keys()) | sum);
913 EXPECT_EQ(dynamic(6), from(obj.values()) | sum);
914 EXPECT_EQ(dynamic(4), from(obj.items()) | get<0>() | sum);
915 EXPECT_EQ(dynamic(6), from(obj.items()) | get<1>() | sum);
919 auto s = from({7, 6, 5, 4, 3}) | as<set<int>>();
920 EXPECT_EQ(s.size(), 5);
923 TEST(StringGen, EmptySplit) {
924 auto collect = eachTo<std::string>() | as<vector>();
926 auto pieces = split("", ',') | collect;
927 EXPECT_EQ(0, pieces.size());
930 // The last delimiter is eaten, just like std::getline
932 auto pieces = split(",", ',') | collect;
933 EXPECT_EQ(1, pieces.size());
934 EXPECT_EQ("", pieces[0]);
938 auto pieces = split(",,", ',') | collect;
939 EXPECT_EQ(2, pieces.size());
940 EXPECT_EQ("", pieces[0]);
941 EXPECT_EQ("", pieces[1]);
945 auto pieces = split(",,", ',') | take(1) | collect;
946 EXPECT_EQ(1, pieces.size());
947 EXPECT_EQ("", pieces[0]);
951 TEST(StringGen, Split) {
952 auto collect = eachTo<std::string>() | as<vector>();
954 auto pieces = split("hello,, world, goodbye, meow", ',') | collect;
955 EXPECT_EQ(5, pieces.size());
956 EXPECT_EQ("hello", pieces[0]);
957 EXPECT_EQ("", pieces[1]);
958 EXPECT_EQ(" world", pieces[2]);
959 EXPECT_EQ(" goodbye", pieces[3]);
960 EXPECT_EQ(" meow", pieces[4]);
964 auto pieces = split("hello,, world, goodbye, meow", ',')
966 EXPECT_EQ(3, pieces.size());
967 EXPECT_EQ("hello", pieces[0]);
968 EXPECT_EQ("", pieces[1]);
969 EXPECT_EQ(" world", pieces[2]);
973 auto pieces = split("hello,, world, goodbye, meow", ',')
975 EXPECT_EQ(5, pieces.size());
976 EXPECT_EQ("hello", pieces[0]);
977 EXPECT_EQ("", pieces[1]);
978 EXPECT_EQ(" world", pieces[2]);
982 TEST(StringGen, EmptyResplit) {
983 auto collect = eachTo<std::string>() | as<vector>();
985 auto pieces = from({""}) | resplit(',') | collect;
986 EXPECT_EQ(0, pieces.size());
989 // The last delimiter is eaten, just like std::getline
991 auto pieces = from({","}) | resplit(',') | collect;
992 EXPECT_EQ(1, pieces.size());
993 EXPECT_EQ("", pieces[0]);
997 auto pieces = from({",,"}) | resplit(',') | collect;
998 EXPECT_EQ(2, pieces.size());
999 EXPECT_EQ("", pieces[0]);
1000 EXPECT_EQ("", pieces[1]);
1004 TEST(StringGen, EachToTuple) {
1006 auto lines = "2:1.414:yo 3:1.732:hi";
1009 | eachToTuple<int, double, std::string>(':')
1011 vector<tuple<int, double, std::string>> expected {
1012 make_tuple(2, 1.414, "yo"),
1013 make_tuple(3, 1.732, "hi"),
1015 EXPECT_EQ(expected, actual);
1021 | eachToTuple<int>(',')
1023 vector<tuple<int>> expected {
1027 EXPECT_EQ(expected, actual);
1030 // StringPiece target
1031 auto lines = "1:cat 2:dog";
1034 | eachToTuple<int, StringPiece>(':')
1036 vector<tuple<int, StringPiece>> expected {
1037 make_tuple(1, "cat"),
1038 make_tuple(2, "dog"),
1040 EXPECT_EQ(expected, actual);
1044 auto lines = "2:tjackson:4 3::5";
1047 | eachToTuple<int, fbstring, int>(':')
1049 vector<tuple<int, fbstring, int>> expected {
1050 make_tuple(2, "tjackson", 4),
1051 make_tuple(3, "", 5),
1053 EXPECT_EQ(expected, actual);
1057 auto lines = "1:2 3:4:5";
1058 EXPECT_THROW((split(lines, ' ')
1059 | eachToTuple<int, int>(':')
1061 std::runtime_error);
1065 auto lines = "1:2:3 4:5";
1066 EXPECT_THROW((split(lines, ' ')
1067 | eachToTuple<int, int, int>(':')
1069 std::runtime_error);
1073 TEST(StringGen, EachToPair) {
1076 auto lines = "2:1.414 3:1.732";
1079 | eachToPair<int, double>(':')
1080 | as<std::map<int, double>>();
1081 std::map<int, double> expected {
1085 EXPECT_EQ(expected, actual);
1088 // string delimiters
1089 auto lines = "ab=>cd ef=>gh";
1092 | eachToPair<string, string>("=>")
1093 | as<std::map<string, string>>();
1094 std::map<string, string> expected {
1098 EXPECT_EQ(expected, actual);
1103 TEST(StringGen, Resplit) {
1104 auto collect = eachTo<std::string>() | as<vector>();
1106 auto pieces = from({"hello,, world, goodbye, meow"}) |
1107 resplit(',') | collect;
1108 EXPECT_EQ(5, pieces.size());
1109 EXPECT_EQ("hello", pieces[0]);
1110 EXPECT_EQ("", pieces[1]);
1111 EXPECT_EQ(" world", pieces[2]);
1112 EXPECT_EQ(" goodbye", pieces[3]);
1113 EXPECT_EQ(" meow", pieces[4]);
1116 auto pieces = from({"hel", "lo,", ", world", ", goodbye, m", "eow"}) |
1117 resplit(',') | collect;
1118 EXPECT_EQ(5, pieces.size());
1119 EXPECT_EQ("hello", pieces[0]);
1120 EXPECT_EQ("", pieces[1]);
1121 EXPECT_EQ(" world", pieces[2]);
1122 EXPECT_EQ(" goodbye", pieces[3]);
1123 EXPECT_EQ(" meow", pieces[4]);
1127 template<typename F>
1128 void runUnsplitSuite(F fn) {
1130 fn("hello,world,goodbye");
1137 TEST(StringGen, Unsplit) {
1139 auto basicFn = [](const StringPiece& s) {
1140 EXPECT_EQ(split(s, ',') | unsplit(','), s);
1143 auto existingBuffer = [](const StringPiece& s) {
1144 folly::fbstring buffer("asdf");
1145 split(s, ',') | unsplit(',', &buffer);
1146 auto expected = folly::to<folly::fbstring>(
1147 "asdf", s.empty() ? "" : ",", s);
1148 EXPECT_EQ(expected, buffer);
1151 auto emptyBuffer = [](const StringPiece& s) {
1153 split(s, ',') | unsplit(',', &buffer);
1154 EXPECT_EQ(s, buffer);
1157 auto stringDelim = [](const StringPiece& s) {
1158 EXPECT_EQ(s, split(s, ',') | unsplit(","));
1160 split(s, ',') | unsplit(",", &buffer);
1161 EXPECT_EQ(buffer, s);
1164 runUnsplitSuite(basicFn);
1165 runUnsplitSuite(existingBuffer);
1166 runUnsplitSuite(emptyBuffer);
1167 runUnsplitSuite(stringDelim);
1168 EXPECT_EQ("1, 2, 3", seq(1, 3) | unsplit(", "));
1171 TEST(FileGen, ByLine) {
1172 auto collect = eachTo<std::string>() | as<vector>();
1173 test::TemporaryFile file("ByLine");
1174 static const std::string lines(
1176 "This is the second line\n"
1179 "a few empty lines above\n"
1180 "incomplete last line");
1181 EXPECT_EQ(lines.size(), write(file.fd(), lines.data(), lines.size()));
1183 auto expected = from({lines}) | resplit('\n') | collect;
1184 auto found = byLine(file.path().c_str()) | collect;
1186 EXPECT_TRUE(expected == found);
1189 class FileGenBufferedTest : public ::testing::TestWithParam<int> { };
1191 TEST_P(FileGenBufferedTest, FileWriter) {
1192 size_t bufferSize = GetParam();
1193 test::TemporaryFile file("FileWriter");
1195 static const std::string lines(
1197 "This is the second line\n"
1200 "a few empty lines above\n");
1202 auto src = from({lines, lines, lines, lines, lines, lines, lines, lines});
1203 auto collect = eachTo<std::string>() | as<vector>();
1204 auto expected = src | resplit('\n') | collect;
1206 src | eachAs<StringPiece>() | toFile(file.fd(), bufferSize);
1207 auto found = byLine(file.path().c_str()) | collect;
1209 EXPECT_TRUE(expected == found);
1212 INSTANTIATE_TEST_CASE_P(
1213 DifferentBufferSizes,
1214 FileGenBufferedTest,
1215 ::testing::Values(0, 1, 2, 4, 8, 64, 4096));
1217 int main(int argc, char *argv[]) {
1218 testing::InitGoogleTest(&argc, argv);
1219 google::ParseCommandLineFlags(&argc, &argv, true);
1220 return RUN_ALL_TESTS();