gen::sample
[folly.git] / folly / experimental / test / GenTest.cpp
1 /*
2  * Copyright 2013 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <glog/logging.h>
18 #include <gtest/gtest.h>
19 #include <iostream>
20 #include <random>
21 #include <set>
22 #include <vector>
23 #include "folly/experimental/Gen.h"
24 #include "folly/experimental/StringGen.h"
25 #include "folly/experimental/FileGen.h"
26 #include "folly/experimental/TestUtil.h"
27 #include "folly/FBVector.h"
28 #include "folly/Format.h"
29 #include "folly/dynamic.h"
30
31 using namespace folly::gen;
32 using namespace folly;
33 using std::ostream;
34 using std::pair;
35 using std::set;
36 using std::unique_ptr;
37 using std::vector;
38 using std::string;
39 using std::tuple;
40 using std::make_tuple;
41 //using std::unordered_map;
42
43 #define EXPECT_SAME(A, B) \
44   static_assert(std::is_same<A, B>::value, "Mismatched: " #A ", " #B)
45 EXPECT_SAME(int&&, typename ArgumentReference<int>::type);
46 EXPECT_SAME(int&, typename ArgumentReference<int&>::type);
47 EXPECT_SAME(const int&, typename ArgumentReference<const int&>::type);
48 EXPECT_SAME(const int&, typename ArgumentReference<const int>::type);
49
50 template<typename T>
51 ostream& operator<<(ostream& os, const set<T>& values) {
52   return os << from(values);
53 }
54
55 template<typename T>
56 ostream& operator<<(ostream& os, const vector<T>& values) {
57   os << "[";
58   for (auto& value : values) {
59     if (&value != &values.front()) {
60       os << " ";
61     }
62     os << value;
63   }
64   return os << "]";
65 }
66
67 auto square = [](int x) { return x * x; };
68 auto add = [](int a, int b) { return a + b; };
69 auto multiply = [](int a, int b) { return a * b; };
70
71 auto product = foldl(1, multiply);
72
73 template<typename A, typename B>
74 ostream& operator<<(ostream& os, const pair<A, B>& pair) {
75   return os << "(" << pair.first << ", " << pair.second << ")";
76 }
77
78 TEST(Gen, Count) {
79   auto gen = seq(1, 10);
80   EXPECT_EQ(10, gen | count);
81   EXPECT_EQ(5, gen | take(5) | count);
82 }
83
84 TEST(Gen, Sum) {
85   auto gen = seq(1, 10);
86   EXPECT_EQ((1 + 10) * 10 / 2, gen | sum);
87   EXPECT_EQ((1 + 5) * 5 / 2, gen | take(5) | sum);
88 }
89
90 TEST(Gen, Foreach) {
91   auto gen = seq(1, 4);
92   int accum = 0;
93   gen | [&](int x) { accum += x; };
94   EXPECT_EQ(10, accum);
95   int accum2 = 0;
96   gen | take(3) | [&](int x) { accum2 += x; };
97   EXPECT_EQ(6, accum2);
98 }
99
100 TEST(Gen, Map) {
101   auto expected = vector<int>{4, 9, 16};
102   auto gen = from({2, 3, 4}) | map(square);
103   EXPECT_EQ((vector<int>{4, 9, 16}), gen | as<vector>());
104   EXPECT_EQ((vector<int>{4, 9}), gen | take(2) | as<vector>());
105 }
106
107 TEST(Gen, Seq) {
108   // cover the fenceposts of the loop unrolling
109   for (int n = 1; n < 100; ++n) {
110     EXPECT_EQ(n, seq(1, n) | count);
111     EXPECT_EQ(n + 1, seq(1) | take(n + 1) | count);
112   }
113 }
114
115 TEST(Gen, Range) {
116   // cover the fenceposts of the loop unrolling
117   for (int n = 1; n < 100; ++n) {
118     EXPECT_EQ(range(0, n) | count, n);
119   }
120 }
121
122 TEST(Gen, FromIterators) {
123   vector<int> source {2, 3, 5, 7, 11};
124   auto gen = from(makeRange(source.begin() + 1, source.end() - 1));
125   EXPECT_EQ(3 * 5 * 7, gen | product);
126 }
127
128 TEST(Gen, FromMap) {
129   auto source = seq(0, 10)
130               | map([](int i) { return std::make_pair(i, i * i); })
131               | as<std::map<int, int>>();
132   auto gen = fromConst(source)
133            | map([&](const std::pair<const int, int>& p) {
134                return p.second - p.first;
135              });
136   EXPECT_EQ(330, gen | sum);
137 }
138
139 TEST(Gen, Filter) {
140   const auto expected = vector<int>{1, 2, 4, 5, 7, 8};
141   auto actual =
142       seq(1, 9)
143     | filter([](int x) { return x % 3; })
144     | as<vector<int>>();
145   EXPECT_EQ(expected, actual);
146 }
147
148 TEST(Gen, Contains) {
149   {
150     auto gen =
151         seq(1, 9)
152       | map(square);
153     EXPECT_TRUE(gen | contains(49));
154     EXPECT_FALSE(gen | contains(50));
155   }
156   {
157     auto gen =
158         seq(1) // infinite, to prove laziness
159       | map(square)
160       | eachTo<std::string>();
161
162     // std::string gen, const char* needle
163     EXPECT_TRUE(gen | take(9999) | contains("49"));
164   }
165 }
166
167 TEST(Gen, Take) {
168   auto expected = vector<int>{1, 4, 9, 16};
169   auto actual =
170       seq(1, 1000)
171     | mapped([](int x) { return x * x; })
172     | take(4)
173     | as<vector<int>>();
174   EXPECT_EQ(expected, actual);
175 }
176
177 TEST(Gen, Sample) {
178   std::mt19937 rnd(42);
179
180   auto sampler =
181       seq(1, 100)
182     | sample(50, rnd);
183   std::unordered_map<int,int> hits;
184   const int kNumIters = 80;
185   for (int i = 0; i < kNumIters; i++) {
186     auto vec = sampler | as<vector<int>>();
187     EXPECT_EQ(vec.size(), 50);
188     auto uniq = fromConst(vec) | as<set<int>>();
189     EXPECT_EQ(uniq.size(), vec.size());  // sampling without replacement
190     for (auto v: vec) {
191       ++hits[v];
192     }
193   }
194
195   // In 80 separate samples of our range, we should have seen every value
196   // at least once and no value all 80 times. (The odds of either of those
197   // events is 1/2^80).
198   EXPECT_EQ(hits.size(), 100);
199   for (auto hit: hits) {
200     EXPECT_GT(hit.second, 0);
201     EXPECT_LT(hit.second, kNumIters);
202   }
203
204   auto small =
205       seq(1, 5)
206     | sample(10);
207   EXPECT_EQ((small | sum), 15);
208   EXPECT_EQ((small | take(3) | count), 3);
209 }
210
211 TEST(Gen, Skip) {
212   auto gen =
213       seq(1, 1000)
214     | mapped([](int x) { return x * x; })
215     | skip(4)
216     | take(4);
217   EXPECT_EQ((vector<int>{25, 36, 49, 64}), gen | as<vector>());
218 }
219
220 TEST(Gen, Until) {
221   auto gen =
222       seq(1) //infinite
223     | mapped([](int x) { return x * x; })
224     | until([](int x) { return x >= 1000; });
225   EXPECT_EQ(31, gen | count);
226 }
227
228 TEST(Gen, Composed) {
229   // Operator, Operator
230   auto valuesOf =
231       filter([](Optional<int>& o) { return o.hasValue(); })
232     | map([](Optional<int>& o) -> int& { return o.value(); });
233   std::vector<Optional<int>> opts {
234     none, 4, none, 6, none
235   };
236   EXPECT_EQ(4 * 4 + 6 * 6, from(opts) | valuesOf | map(square) | sum);
237   // Operator, Sink
238   auto sumOpt = valuesOf | sum;
239   EXPECT_EQ(10, from(opts) | sumOpt);
240 }
241
242 TEST(Gen, Chain) {
243   std::vector<int> nums {2, 3, 5, 7};
244   std::map<int, int> mappings { { 3, 9}, {5, 25} };
245   auto gen = from(nums) + (from(mappings) | get<1>());
246   EXPECT_EQ(51, gen | sum);
247   EXPECT_EQ(5, gen | take(2) | sum);
248   EXPECT_EQ(26, gen | take(5) | sum);
249 }
250
251 TEST(Gen, Concat) {
252   std::vector<std::vector<int>> nums {{2, 3}, {5, 7}};
253   auto gen = from(nums) | rconcat;
254   EXPECT_EQ(17, gen | sum);
255   EXPECT_EQ(10, gen | take(3) | sum);
256 }
257
258 TEST(Gen, ConcatGen) {
259   auto gen = seq(1, 10)
260            | map([](int i) { return seq(1, i); })
261            | concat;
262   EXPECT_EQ(220, gen | sum);
263   EXPECT_EQ(10, gen | take(6) | sum);
264 }
265
266 TEST(Gen, ConcatAlt) {
267   std::vector<std::vector<int>> nums {{2, 3}, {5, 7}};
268   auto actual = from(nums)
269               | map([](std::vector<int>& v) { return from(v); })
270               | concat
271               | sum;
272   auto expected = 17;
273   EXPECT_EQ(expected, actual);
274 }
275
276 TEST(Gen, Order) {
277   auto expected = vector<int>{0, 3, 5, 6, 7, 8, 9};
278   auto actual =
279       from({8, 6, 7, 5, 3, 0, 9})
280     | order
281     | as<vector>();
282   EXPECT_EQ(expected, actual);
283 }
284
285 TEST(Gen, OrderMoved) {
286   auto expected = vector<int>{0, 9, 25, 36, 49, 64, 81};
287   auto actual =
288       from({8, 6, 7, 5, 3, 0, 9})
289     | move
290     | order
291     | map(square)
292     | as<vector>();
293   EXPECT_EQ(expected, actual);
294 }
295
296 TEST(Gen, OrderTake) {
297   auto expected = vector<int>{9, 8, 7};
298   auto actual =
299       from({8, 6, 7, 5, 3, 0, 9})
300     | orderByDescending(square)
301     | take(3)
302     | as<vector>();
303   EXPECT_EQ(expected, actual);
304 }
305
306 TEST(Gen, Distinct) {
307   auto expected = vector<int>{3, 1, 2};
308   auto actual =
309       from({3, 1, 3, 2, 1, 2, 3})
310     | distinct
311     | as<vector>();
312   EXPECT_EQ(expected, actual);
313 }
314
315 TEST(Gen, DistinctBy) {   //  0  1  4  9  6  5  6  9  4  1  0
316   auto expected = vector<int>{0, 1, 2, 3, 4, 5};
317   auto actual =
318       seq(0, 100)
319     | distinctBy([](int i) { return i * i % 10; })
320     | as<vector>();
321   EXPECT_EQ(expected, actual);
322 }
323
324 TEST(Gen, DistinctMove) {   //  0  1  4  9  6  5  6  9  4  1  0
325   auto expected = vector<int>{0, 1, 2, 3, 4, 5};
326   auto actual =
327       seq(0, 100)
328     | mapped([](int i) { return std::unique_ptr<int>(new int(i)); })
329       // see comment below about selector parameters for Distinct
330     | distinctBy([](const std::unique_ptr<int>& pi) { return *pi * *pi % 10; })
331     | mapped([](std::unique_ptr<int> pi) { return *pi; })
332     | as<vector>();
333
334   // NOTE(tjackson): the following line intentionally doesn't work:
335   //  | distinctBy([](std::unique_ptr<int> pi) { return *pi * *pi % 10; })
336   // This is because distinctBy because the selector intentionally requires a
337   // const reference.  If it required a move-reference, the value might get
338   // gutted by the selector before said value could be passed to downstream
339   // operators.
340   EXPECT_EQ(expected, actual);
341 }
342
343 TEST(Gen, MinBy) {
344   EXPECT_EQ(7, seq(1, 10)
345              | minBy([](int i) -> double {
346                  double d = i - 6.8;
347                  return d * d;
348                }));
349 }
350
351 TEST(Gen, MaxBy) {
352   auto gen = from({"three", "eleven", "four"});
353
354   EXPECT_EQ("eleven", gen | maxBy(&strlen));
355 }
356
357 TEST(Gen, Append) {
358   fbstring expected = "facebook";
359   fbstring actual = "face";
360   from(StringPiece("book")) | appendTo(actual);
361   EXPECT_EQ(expected, actual);
362 }
363
364 TEST(Gen, FromRValue) {
365   {
366     // AFAICT The C++ Standard does not specify what happens to the rvalue
367     // reference of a std::vector when it is used as the 'other' for an rvalue
368     // constructor.  Use fbvector because we're sure its size will be zero in
369     // this case.
370     folly::fbvector<int> v({1,2,3,4});
371     auto q1 = from(v);
372     EXPECT_EQ(v.size(), 4);  // ensure that the lvalue version was called!
373     auto expected = 1 * 2 * 3 * 4;
374     EXPECT_EQ(expected, q1 | product);
375
376     auto q2 = from(std::move(v));
377     EXPECT_EQ(v.size(), 0);  // ensure that rvalue version was called
378     EXPECT_EQ(expected, q2 | product);
379   }
380   {
381     auto expected = 7;
382     auto q = from([] {return vector<int>({3,7,5}); }());
383     EXPECT_EQ(expected, q | max);
384   }
385   {
386     for (auto size: {5, 1024, 16384, 1<<20}) {
387       auto q1 = from(vector<int>(size, 2));
388       auto q2 = from(vector<int>(size, 3));
389       // If the rvalue specialization is broken/gone, then the compiler will
390       // (disgustingly!) just store a *reference* to the temporary object,
391       // which is bad.  Try to catch this by allocating two temporary vectors
392       // of the same size, so that they'll probably use the same underlying
393       // buffer if q1's vector is destructed before q2's vector is constructed.
394       EXPECT_EQ(size * 2 + size * 3, (q1 | sum) + (q2 | sum));
395     }
396   }
397   {
398     auto q = from(set<int>{1,2,3,2,1});
399     EXPECT_EQ(q | sum, 6);
400   }
401 }
402
403 TEST(Gen, OrderBy) {
404   auto expected = vector<int>{5, 6, 4, 7, 3, 8, 2, 9, 1, 10};
405   auto actual =
406       seq(1, 10)
407     | orderBy([](int x) { return (5.1 - x) * (5.1 - x); })
408     | as<vector>();
409   EXPECT_EQ(expected, actual);
410 }
411
412 TEST(Gen, Foldl) {
413   int expected = 2 * 3 * 4 * 5;
414   auto actual =
415       seq(2, 5)
416     | foldl(1, multiply);
417   EXPECT_EQ(expected, actual);
418 }
419
420 TEST(Gen, Reduce) {
421   int expected = 2 + 3 + 4 + 5;
422   auto actual = seq(2, 5) | reduce(add);
423   EXPECT_EQ(expected, actual);
424 }
425
426 TEST(Gen, ReduceBad) {
427   auto gen = seq(1) | take(0);
428   try {
429     EXPECT_TRUE(true);
430     gen | reduce(add);
431     EXPECT_TRUE(false);
432   } catch (...) {
433   }
434 }
435
436 TEST(Gen, Moves) {
437   std::vector<unique_ptr<int>> ptrs;
438   ptrs.emplace_back(new int(1));
439   EXPECT_NE(ptrs.front().get(), nullptr);
440   auto ptrs2 = from(ptrs) | move | as<vector>();
441   EXPECT_EQ(ptrs.front().get(), nullptr);
442   EXPECT_EQ(**ptrs2.data(), 1);
443 }
444
445 TEST(Gen, First) {
446   auto gen =
447       seq(0)
448     | filter([](int x) { return x > 3; });
449   EXPECT_EQ(4, gen | first);
450 }
451
452 TEST(Gen, FromCopy) {
453   vector<int> v {3, 5};
454   auto src = from(v);
455   auto copy = fromCopy(v);
456   EXPECT_EQ(8, src | sum);
457   EXPECT_EQ(8, copy | sum);
458   v[1] = 7;
459   EXPECT_EQ(10, src | sum);
460   EXPECT_EQ(8, copy | sum);
461 }
462
463 TEST(Gen, Get) {
464   std::map<int, int> pairs {
465     {1, 1},
466     {2, 4},
467     {3, 9},
468     {4, 16},
469   };
470   auto pairSrc = from(pairs);
471   auto keys = pairSrc | get<0>();
472   auto values = pairSrc | get<1>();
473   EXPECT_EQ(10, keys | sum);
474   EXPECT_EQ(30, values | sum);
475   EXPECT_EQ(30, keys | map(square) | sum);
476   pairs[5] = 25;
477   EXPECT_EQ(15, keys | sum);
478   EXPECT_EQ(55, values | sum);
479
480   vector<tuple<int, int, int>> tuples {
481     make_tuple(1, 1, 1),
482     make_tuple(2, 4, 8),
483     make_tuple(3, 9, 27),
484   };
485   EXPECT_EQ(36, from(tuples) | get<2>() | sum);
486 }
487
488 TEST(Gen, Any) {
489   EXPECT_TRUE(seq(0) | any);
490   EXPECT_TRUE(seq(0, 1) | any);
491   EXPECT_TRUE(seq(0, 10) | any([](int i) { return i == 7; }));
492   EXPECT_FALSE(seq(0, 10) | any([](int i) { return i == 11; }));
493
494   EXPECT_TRUE(from({1}) | any);
495   EXPECT_FALSE(range(0, 0) | any);
496   EXPECT_FALSE(from({1}) | take(0) | any);
497 }
498
499 TEST(Gen, All) {
500   EXPECT_TRUE(seq(0, 10) | all([](int i) { return i < 11; }));
501   EXPECT_FALSE(seq(0, 10) | all([](int i) { return i < 5; }));
502   EXPECT_FALSE(seq(0) | take(9999) | all([](int i) { return i < 10; }));
503
504   // empty lists satisfies all
505   EXPECT_TRUE(seq(0) | take(0) | all([](int i) { return i < 50; }));
506   EXPECT_TRUE(seq(0) | take(0) | all([](int i) { return i > 50; }));
507 }
508
509 TEST(Gen, Yielders) {
510   auto gen = GENERATOR(int) {
511     for (int i = 1; i <= 5; ++i) {
512       yield(i);
513     }
514     yield(7);
515     for (int i = 3; ; ++i) {
516       yield(i * i);
517     }
518   };
519   vector<int> expected {
520     1, 2, 3, 4, 5, 7, 9, 16, 25
521   };
522   EXPECT_EQ(expected, gen | take(9) | as<vector>());
523 }
524
525 TEST(Gen, NestedYield) {
526   auto nums = GENERATOR(int) {
527     for (int i = 1; ; ++i) {
528       yield(i);
529     }
530   };
531   auto gen = GENERATOR(int) {
532     nums | take(10) | yield;
533     seq(1, 5) | [&](int i) {
534       yield(i);
535     };
536   };
537   EXPECT_EQ(70, gen | sum);
538 }
539
540 TEST(Gen, MapYielders) {
541   auto gen = seq(1, 5)
542            | map([](int n) {
543                return GENERATOR(int) {
544                  int i;
545                  for (i = 1; i < n; ++i)
546                    yield(i);
547                  for (; i >= 1; --i)
548                    yield(i);
549                };
550              })
551            | concat;
552   vector<int> expected {
553                 1,
554              1, 2, 1,
555           1, 2, 3, 2, 1,
556        1, 2, 3, 4, 3, 2, 1,
557     1, 2, 3, 4, 5, 4, 3, 2, 1,
558   };
559   EXPECT_EQ(expected, gen | as<vector>());
560 }
561
562 TEST(Gen, VirtualGen) {
563   VirtualGen<int> v(seq(1, 10));
564   EXPECT_EQ(55, v | sum);
565   v = v | map(square);
566   EXPECT_EQ(385, v | sum);
567   v = v | take(5);
568   EXPECT_EQ(55, v | sum);
569   EXPECT_EQ(30, v | take(4) | sum);
570 }
571
572
573 TEST(Gen, CustomType) {
574   struct Foo{
575     int y;
576   };
577   auto gen = from({Foo{2}, Foo{3}})
578            | map([](const Foo& f) { return f.y; });
579   EXPECT_EQ(5, gen | sum);
580 }
581
582 TEST(Gen, NoNeedlessCopies) {
583   auto gen = seq(1, 5)
584            | map([](int x) { return unique_ptr<int>(new int(x)); })
585            | map([](unique_ptr<int> p) { return p; })
586            | map([](unique_ptr<int>&& p) { return std::move(p); })
587            | map([](const unique_ptr<int>& p) { return *p; });
588   EXPECT_EQ(15, gen | sum);
589   EXPECT_EQ(6, gen | take(3) | sum);
590 }
591
592 namespace {
593 class TestIntSeq : public GenImpl<int, TestIntSeq> {
594  public:
595   TestIntSeq() { }
596
597   template <class Body>
598   bool apply(Body&& body) const {
599     for (int i = 1; i < 6; ++i) {
600       if (!body(i)) {
601         return false;
602       }
603     }
604     return true;
605   }
606
607   TestIntSeq(TestIntSeq&&) = default;
608   TestIntSeq& operator=(TestIntSeq&&) = default;
609   TestIntSeq(const TestIntSeq&) = delete;
610   TestIntSeq& operator=(const TestIntSeq&) = delete;
611 };
612 }  // namespace
613
614 TEST(Gen, NoGeneratorCopies) {
615   EXPECT_EQ(15, TestIntSeq() | sum);
616   auto x = TestIntSeq() | take(3);
617   EXPECT_EQ(6, std::move(x) | sum);
618 }
619
620 TEST(Gen, FromArray) {
621   int source[] = {2, 3, 5, 7};
622   auto gen = from(source);
623   EXPECT_EQ(2 * 3 * 5 * 7, gen | product);
624 }
625
626 TEST(Gen, FromStdArray) {
627   std::array<int,4> source {{2, 3, 5, 7}};
628   auto gen = from(source);
629   EXPECT_EQ(2 * 3 * 5 * 7, gen | product);
630 }
631
632 TEST(Gen, StringConcat) {
633   auto gen = seq(1, 10)
634            | map([](int n) { return folly::to<fbstring>(n); })
635            | rconcat;
636   EXPECT_EQ("12345678910", gen | as<fbstring>());
637 }
638
639 struct CopyCounter {
640   static int alive;
641   int copies;
642   int moves;
643
644   CopyCounter() : copies(0), moves(0) {
645     ++alive;
646   }
647
648   CopyCounter(CopyCounter&& source) {
649     *this = std::move(source);
650     ++alive;
651   }
652
653   CopyCounter(const CopyCounter& source) {
654     *this = source;
655     ++alive;
656   }
657
658   ~CopyCounter() {
659     --alive;
660   }
661
662   CopyCounter& operator=(const CopyCounter& source) {
663     this->copies = source.copies + 1;
664     this->moves = source.moves;
665     return *this;
666   }
667
668   CopyCounter& operator=(CopyCounter&& source) {
669     this->copies = source.copies;
670     this->moves = source.moves + 1;
671     return *this;
672   }
673 };
674
675 int CopyCounter::alive = 0;
676
677 TEST(Gen, CopyCount) {
678   vector<CopyCounter> originals;
679   originals.emplace_back();
680   EXPECT_EQ(1, originals.size());
681   EXPECT_EQ(0, originals.back().copies);
682
683   vector<CopyCounter> copies = from(originals) | as<vector>();
684   EXPECT_EQ(1, copies.back().copies);
685   EXPECT_EQ(0, copies.back().moves);
686
687   vector<CopyCounter> moves = from(originals) | move | as<vector>();
688   EXPECT_EQ(0, moves.back().copies);
689   EXPECT_EQ(1, moves.back().moves);
690 }
691
692 // test dynamics with various layers of nested arrays.
693 TEST(Gen, Dynamic) {
694   dynamic array1 = {1, 2};
695   EXPECT_EQ(dynamic(3), from(array1) | sum);
696   dynamic array2 = {{1}, {1, 2}};
697   EXPECT_EQ(dynamic(4), from(array2) | rconcat | sum);
698   dynamic array3 = {{{1}}, {{1}, {1, 2}}};
699   EXPECT_EQ(dynamic(5), from(array3) | rconcat | rconcat | sum);
700 }
701
702 TEST(Gen, DynamicObject) {
703   const dynamic obj = dynamic::object(1, 2)(3, 4);
704   EXPECT_EQ(dynamic(4), from(obj.keys()) | sum);
705   EXPECT_EQ(dynamic(6), from(obj.values()) | sum);
706   EXPECT_EQ(dynamic(4), from(obj.items()) | get<0>() | sum);
707   EXPECT_EQ(dynamic(6), from(obj.items()) | get<1>() | sum);
708 }
709
710 TEST(Gen, Collect) {
711   auto s = from({7, 6, 5, 4, 3}) | as<set<int>>();
712   EXPECT_EQ(s.size(), 5);
713 }
714
715 TEST(StringGen, EmptySplit) {
716   auto collect = eachTo<std::string>() | as<vector>();
717   {
718     auto pieces = split("", ',') | collect;
719     EXPECT_EQ(0, pieces.size());
720   }
721
722   // The last delimiter is eaten, just like std::getline
723   {
724     auto pieces = split(",", ',') | collect;
725     EXPECT_EQ(1, pieces.size());
726     EXPECT_EQ("", pieces[0]);
727   }
728
729   {
730     auto pieces = split(",,", ',') | collect;
731     EXPECT_EQ(2, pieces.size());
732     EXPECT_EQ("", pieces[0]);
733     EXPECT_EQ("", pieces[1]);
734   }
735
736   {
737     auto pieces = split(",,", ',') | take(1) | collect;
738     EXPECT_EQ(1, pieces.size());
739     EXPECT_EQ("", pieces[0]);
740   }
741 }
742
743 TEST(StringGen, Split) {
744   auto collect = eachTo<std::string>() | as<vector>();
745   {
746     auto pieces = split("hello,, world, goodbye, meow", ',') | collect;
747     EXPECT_EQ(5, pieces.size());
748     EXPECT_EQ("hello", pieces[0]);
749     EXPECT_EQ("", pieces[1]);
750     EXPECT_EQ(" world", pieces[2]);
751     EXPECT_EQ(" goodbye", pieces[3]);
752     EXPECT_EQ(" meow", pieces[4]);
753   }
754
755   {
756     auto pieces = split("hello,, world, goodbye, meow", ',')
757                 | take(3) | collect;
758     EXPECT_EQ(3, pieces.size());
759     EXPECT_EQ("hello", pieces[0]);
760     EXPECT_EQ("", pieces[1]);
761     EXPECT_EQ(" world", pieces[2]);
762   }
763
764   {
765     auto pieces = split("hello,, world, goodbye, meow", ',')
766                 | take(5) | collect;
767     EXPECT_EQ(5, pieces.size());
768     EXPECT_EQ("hello", pieces[0]);
769     EXPECT_EQ("", pieces[1]);
770     EXPECT_EQ(" world", pieces[2]);
771   }
772 }
773
774 TEST(StringGen, EmptyResplit) {
775   auto collect = eachTo<std::string>() | as<vector>();
776   {
777     auto pieces = from({""}) | resplit(',') | collect;
778     EXPECT_EQ(0, pieces.size());
779   }
780
781   // The last delimiter is eaten, just like std::getline
782   {
783     auto pieces = from({","}) | resplit(',') | collect;
784     EXPECT_EQ(1, pieces.size());
785     EXPECT_EQ("", pieces[0]);
786   }
787
788   {
789     auto pieces = from({",,"}) | resplit(',') | collect;
790     EXPECT_EQ(2, pieces.size());
791     EXPECT_EQ("", pieces[0]);
792     EXPECT_EQ("", pieces[1]);
793   }
794 }
795
796 TEST(StringGen, Resplit) {
797   auto collect = eachTo<std::string>() | as<vector>();
798   {
799     auto pieces = from({"hello,, world, goodbye, meow"}) |
800       resplit(',') | collect;
801     EXPECT_EQ(5, pieces.size());
802     EXPECT_EQ("hello", pieces[0]);
803     EXPECT_EQ("", pieces[1]);
804     EXPECT_EQ(" world", pieces[2]);
805     EXPECT_EQ(" goodbye", pieces[3]);
806     EXPECT_EQ(" meow", pieces[4]);
807   }
808   {
809     auto pieces = from({"hel", "lo,", ", world", ", goodbye, m", "eow"}) |
810       resplit(',') | collect;
811     EXPECT_EQ(5, pieces.size());
812     EXPECT_EQ("hello", pieces[0]);
813     EXPECT_EQ("", pieces[1]);
814     EXPECT_EQ(" world", pieces[2]);
815     EXPECT_EQ(" goodbye", pieces[3]);
816     EXPECT_EQ(" meow", pieces[4]);
817   }
818 }
819
820 template<typename F>
821 void runUnsplitSuite(F fn) {
822   fn("hello, world");
823   fn("hello,world,goodbye");
824   fn(" ");
825   fn("");
826   fn(", ");
827   fn(", a, b,c");
828 }
829
830 TEST(StringGen, Unsplit) {
831
832   auto basicFn = [](const StringPiece& s) {
833     EXPECT_EQ(split(s, ',') | unsplit(','), s);
834   };
835
836   auto existingBuffer = [](const StringPiece& s) {
837     folly::fbstring buffer("asdf");
838     split(s, ',') | unsplit(',', &buffer);
839     auto expected = folly::to<folly::fbstring>(
840         "asdf", s.empty() ? "" : ",", s);
841     EXPECT_EQ(expected, buffer);
842   };
843
844   auto emptyBuffer = [](const StringPiece& s) {
845     std::string buffer;
846     split(s, ',') | unsplit(',', &buffer);
847     EXPECT_EQ(s, buffer);
848   };
849
850   auto stringDelim = [](const StringPiece& s) {
851     EXPECT_EQ(s, split(s, ',') | unsplit(","));
852     std::string buffer;
853     split(s, ',') | unsplit(",", &buffer);
854     EXPECT_EQ(buffer, s);
855   };
856
857   runUnsplitSuite(basicFn);
858   runUnsplitSuite(existingBuffer);
859   runUnsplitSuite(emptyBuffer);
860   runUnsplitSuite(stringDelim);
861   EXPECT_EQ("1, 2, 3", seq(1, 3) | unsplit(", "));
862 }
863
864 TEST(FileGen, ByLine) {
865   auto collect = eachTo<std::string>() | as<vector>();
866   test::TemporaryFile file("ByLine");
867   static const std::string lines(
868       "Hello world\n"
869       "This is the second line\n"
870       "\n"
871       "\n"
872       "a few empty lines above\n"
873       "incomplete last line");
874   EXPECT_EQ(lines.size(), write(file.fd(), lines.data(), lines.size()));
875
876   auto expected = from({lines}) | resplit('\n') | collect;
877   auto found = byLine(file.path().c_str()) | collect;
878
879   EXPECT_TRUE(expected == found);
880 }
881
882 class FileGenBufferedTest : public ::testing::TestWithParam<int> { };
883
884 TEST_P(FileGenBufferedTest, FileWriter) {
885   size_t bufferSize = GetParam();
886   test::TemporaryFile file("FileWriter");
887
888   static const std::string lines(
889       "Hello world\n"
890       "This is the second line\n"
891       "\n"
892       "\n"
893       "a few empty lines above\n");
894
895   auto src = from({lines, lines, lines, lines, lines, lines, lines, lines});
896   auto collect = eachTo<std::string>() | as<vector>();
897   auto expected = src | resplit('\n') | collect;
898
899   src | eachAs<StringPiece>() | toFile(file.fd(), bufferSize);
900   auto found = byLine(file.path().c_str()) | collect;
901
902   EXPECT_TRUE(expected == found);
903 }
904
905 INSTANTIATE_TEST_CASE_P(
906     DifferentBufferSizes,
907     FileGenBufferedTest,
908     ::testing::Values(0, 1, 2, 4, 8, 64, 4096));
909
910 int main(int argc, char *argv[]) {
911   testing::InitGoogleTest(&argc, argv);
912   google::ParseCommandLineFlags(&argc, &argv, true);
913   return RUN_ALL_TESTS();
914 }