651dc3954194e7c288544f1031ef3d4f7f34f578
[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 <set>
21 #include <vector>
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"
29
30 using namespace folly::gen;
31 using namespace folly;
32 using std::ostream;
33 using std::pair;
34 using std::set;
35 using std::unique_ptr;
36 using std::vector;
37 using std::string;
38 using std::tuple;
39 using std::make_tuple;
40 //using std::unordered_map;
41
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);
48
49 template<typename T>
50 ostream& operator<<(ostream& os, const set<T>& values) {
51   return os << from(values);
52 }
53
54 template<typename T>
55 ostream& operator<<(ostream& os, const vector<T>& values) {
56   os << "[";
57   for (auto& value : values) {
58     if (&value != &values.front()) {
59       os << " ";
60     }
61     os << value;
62   }
63   return os << "]";
64 }
65
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; };
69
70 auto product = foldl(1, multiply);
71
72 template<typename A, typename B>
73 ostream& operator<<(ostream& os, const pair<A, B>& pair) {
74   return os << "(" << pair.first << ", " << pair.second << ")";
75 }
76
77 TEST(Gen, Count) {
78   auto gen = seq(1, 10);
79   EXPECT_EQ(10, gen | count);
80   EXPECT_EQ(5, gen | take(5) | count);
81 }
82
83 TEST(Gen, Sum) {
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);
87 }
88
89 TEST(Gen, Foreach) {
90   auto gen = seq(1, 4);
91   int accum = 0;
92   gen | [&](int x) { accum += x; };
93   EXPECT_EQ(10, accum);
94   int accum2 = 0;
95   gen | take(3) | [&](int x) { accum2 += x; };
96   EXPECT_EQ(6, accum2);
97 }
98
99 TEST(Gen, Map) {
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>());
104 }
105
106 TEST(Gen, Seq) {
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);
111   }
112 }
113
114 TEST(Gen, Range) {
115   // cover the fenceposts of the loop unrolling
116   for (int n = 1; n < 100; ++n) {
117     EXPECT_EQ(range(0, n) | count, n);
118   }
119 }
120
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);
125 }
126
127 TEST(Gen, FromMap) {
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;
134              });
135   EXPECT_EQ(330, gen | sum);
136 }
137
138 TEST(Gen, Filter) {
139   const auto expected = vector<int>{1, 2, 4, 5, 7, 8};
140   auto actual =
141       seq(1, 9)
142     | filter([](int x) { return x % 3; })
143     | as<vector<int>>();
144   EXPECT_EQ(expected, actual);
145 }
146
147 TEST(Gen, Contains) {
148   {
149     auto gen =
150         seq(1, 9)
151       | map(square);
152     EXPECT_TRUE(gen | contains(49));
153     EXPECT_FALSE(gen | contains(50));
154   }
155   {
156     auto gen =
157         seq(1) // infinite, to prove laziness
158       | map(square)
159       | eachTo<std::string>();
160
161     // std::string gen, const char* needle
162     EXPECT_TRUE(gen | contains("49"));
163   }
164 }
165
166 TEST(Gen, Take) {
167   auto expected = vector<int>{1, 4, 9, 16};
168   auto actual =
169       seq(1, 1000)
170     | mapped([](int x) { return x * x; })
171     | take(4)
172     | as<vector<int>>();
173   EXPECT_EQ(expected, actual);
174 }
175
176 TEST(Gen, Skip) {
177   auto gen =
178       seq(1, 1000)
179     | mapped([](int x) { return x * x; })
180     | skip(4)
181     | take(4);
182   EXPECT_EQ((vector<int>{25, 36, 49, 64}), gen | as<vector>());
183 }
184
185 TEST(Gen, Until) {
186   auto gen =
187       seq(1) //infinite
188     | mapped([](int x) { return x * x; })
189     | until([](int x) { return x >= 1000; });
190   EXPECT_EQ(31, gen | count);
191 }
192
193 TEST(Gen, Composed) {
194   // Operator, Operator
195   auto valuesOf =
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
200   };
201   EXPECT_EQ(4 * 4 + 6 * 6, from(opts) | valuesOf | map(square) | sum);
202   // Operator, Sink
203   auto sumOpt = valuesOf | sum;
204   EXPECT_EQ(10, from(opts) | sumOpt);
205 }
206
207 TEST(Gen, Chain) {
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);
214 }
215
216 TEST(Gen, Concat) {
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);
221 }
222
223 TEST(Gen, ConcatGen) {
224   auto gen = seq(1, 10)
225            | map([](int i) { return seq(1, i); })
226            | concat;
227   EXPECT_EQ(220, gen | sum);
228   EXPECT_EQ(10, gen | take(6) | sum);
229 }
230
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); })
235               | concat
236               | sum;
237   auto expected = 17;
238   EXPECT_EQ(expected, actual);
239 }
240
241 TEST(Gen, Order) {
242   auto expected = vector<int>{0, 3, 5, 6, 7, 8, 9};
243   auto actual =
244       from({8, 6, 7, 5, 3, 0, 9})
245     | order
246     | as<vector>();
247   EXPECT_EQ(expected, actual);
248 }
249
250 TEST(Gen, OrderMoved) {
251   auto expected = vector<int>{0, 9, 25, 36, 49, 64, 81};
252   auto actual =
253       from({8, 6, 7, 5, 3, 0, 9})
254     | move
255     | order
256     | map(square)
257     | as<vector>();
258   EXPECT_EQ(expected, actual);
259 }
260
261 TEST(Gen, OrderTake) {
262   auto expected = vector<int>{9, 8, 7};
263   auto actual =
264       from({8, 6, 7, 5, 3, 0, 9})
265     | orderByDescending(square)
266     | take(3)
267     | as<vector>();
268   EXPECT_EQ(expected, actual);
269 }
270
271 TEST(Gen, MinBy) {
272   EXPECT_EQ(7, seq(1, 10)
273              | minBy([](int i) -> double {
274                  double d = i - 6.8;
275                  return d * d;
276                }));
277 }
278
279 TEST(Gen, MaxBy) {
280   auto gen = from({"three", "eleven", "four"});
281
282   EXPECT_EQ("eleven", gen | maxBy(&strlen));
283 }
284
285 TEST(Gen, Append) {
286   fbstring expected = "facebook";
287   fbstring actual = "face";
288   from(StringPiece("book")) | appendTo(actual);
289   EXPECT_EQ(expected, actual);
290 }
291
292 TEST(Gen, FromRValue) {
293   {
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
297     // this case.
298     folly::fbvector<int> v({1,2,3,4});
299     auto q1 = from(v);
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);
303
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);
307   }
308   {
309     auto expected = 7;
310     auto q = from([] {return vector<int>({3,7,5}); }());
311     EXPECT_EQ(expected, q | max);
312   }
313   {
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));
323     }
324   }
325   {
326     auto q = from(set<int>{1,2,3,2,1});
327     EXPECT_EQ(q | sum, 6);
328   }
329 }
330
331 TEST(Gen, OrderBy) {
332   auto expected = vector<int>{5, 6, 4, 7, 3, 8, 2, 9, 1, 10};
333   auto actual =
334       seq(1, 10)
335     | orderBy([](int x) { return (5.1 - x) * (5.1 - x); })
336     | as<vector>();
337   EXPECT_EQ(expected, actual);
338 }
339
340 TEST(Gen, Foldl) {
341   int expected = 2 * 3 * 4 * 5;
342   auto actual =
343       seq(2, 5)
344     | foldl(1, multiply);
345   EXPECT_EQ(expected, actual);
346 }
347
348 TEST(Gen, Reduce) {
349   int expected = 2 + 3 + 4 + 5;
350   auto actual = seq(2, 5) | reduce(add);
351   EXPECT_EQ(expected, actual);
352 }
353
354 TEST(Gen, ReduceBad) {
355   auto gen = seq(1) | take(0);
356   try {
357     EXPECT_TRUE(true);
358     gen | reduce(add);
359     EXPECT_TRUE(false);
360   } catch (...) {
361   }
362 }
363
364 TEST(Gen, Moves) {
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);
371 }
372
373 TEST(Gen, First) {
374   auto gen =
375       seq(0)
376     | filter([](int x) { return x > 3; });
377   EXPECT_EQ(4, gen | first);
378 }
379
380 TEST(Gen, FromCopy) {
381   vector<int> v {3, 5};
382   auto src = from(v);
383   auto copy = fromCopy(v);
384   EXPECT_EQ(8, src | sum);
385   EXPECT_EQ(8, copy | sum);
386   v[1] = 7;
387   EXPECT_EQ(10, src | sum);
388   EXPECT_EQ(8, copy | sum);
389 }
390
391 TEST(Gen, Get) {
392   std::map<int, int> pairs {
393     {1, 1},
394     {2, 4},
395     {3, 9},
396     {4, 16},
397   };
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);
404   pairs[5] = 25;
405   EXPECT_EQ(15, keys | sum);
406   EXPECT_EQ(55, values | sum);
407
408   vector<tuple<int, int, int>> tuples {
409     make_tuple(1, 1, 1),
410     make_tuple(2, 4, 8),
411     make_tuple(3, 9, 27),
412   };
413   EXPECT_EQ(36, from(tuples) | get<2>() | sum);
414 }
415
416 TEST(Gen, Any) {
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; }));
421
422   EXPECT_TRUE(from({1}) | any);
423   EXPECT_FALSE(range(0, 0) | any);
424   EXPECT_FALSE(from({1}) | take(0) | any);
425 }
426
427 TEST(Gen, All) {
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; }));
431
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; }));
435 }
436
437 TEST(Gen, Yielders) {
438   auto gen = GENERATOR(int) {
439     for (int i = 1; i <= 5; ++i) {
440       yield(i);
441     }
442     yield(7);
443     for (int i = 3; ; ++i) {
444       yield(i * i);
445     }
446   };
447   vector<int> expected {
448     1, 2, 3, 4, 5, 7, 9, 16, 25
449   };
450   EXPECT_EQ(expected, gen | take(9) | as<vector>());
451 }
452
453 TEST(Gen, NestedYield) {
454   auto nums = GENERATOR(int) {
455     for (int i = 1; ; ++i) {
456       yield(i);
457     }
458   };
459   auto gen = GENERATOR(int) {
460     nums | take(10) | yield;
461     seq(1, 5) | [&](int i) {
462       yield(i);
463     };
464   };
465   EXPECT_EQ(70, gen | sum);
466 }
467
468 TEST(Gen, MapYielders) {
469   auto gen = seq(1, 5)
470            | map([](int n) {
471                return GENERATOR(int) {
472                  int i;
473                  for (i = 1; i < n; ++i)
474                    yield(i);
475                  for (; i >= 1; --i)
476                    yield(i);
477                };
478              })
479            | concat;
480   vector<int> expected {
481                 1,
482              1, 2, 1,
483           1, 2, 3, 2, 1,
484        1, 2, 3, 4, 3, 2, 1,
485     1, 2, 3, 4, 5, 4, 3, 2, 1,
486   };
487   EXPECT_EQ(expected, gen | as<vector>());
488 }
489
490 TEST(Gen, VirtualGen) {
491   VirtualGen<int> v(seq(1, 10));
492   EXPECT_EQ(55, v | sum);
493   v = v | map(square);
494   EXPECT_EQ(385, v | sum);
495   v = v | take(5);
496   EXPECT_EQ(55, v | sum);
497   EXPECT_EQ(30, v | take(4) | sum);
498 }
499
500
501 TEST(Gen, CustomType) {
502   struct Foo{
503     int y;
504   };
505   auto gen = from({Foo{2}, Foo{3}})
506            | map([](const Foo& f) { return f.y; });
507   EXPECT_EQ(5, gen | sum);
508 }
509
510 TEST(Gen, NoNeedlessCopies) {
511   auto gen = seq(1, 5)
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);
518 }
519
520 namespace {
521 class TestIntSeq : public GenImpl<int, TestIntSeq> {
522  public:
523   TestIntSeq() { }
524
525   template <class Body>
526   bool apply(Body&& body) const {
527     for (int i = 1; i < 6; ++i) {
528       if (!body(i)) {
529         return false;
530       }
531     }
532     return true;
533   }
534
535   TestIntSeq(TestIntSeq&&) = default;
536   TestIntSeq& operator=(TestIntSeq&&) = default;
537   TestIntSeq(const TestIntSeq&) = delete;
538   TestIntSeq& operator=(const TestIntSeq&) = delete;
539 };
540 }  // namespace
541
542 TEST(Gen, NoGeneratorCopies) {
543   EXPECT_EQ(15, TestIntSeq() | sum);
544   auto x = TestIntSeq() | take(3);
545   EXPECT_EQ(6, std::move(x) | sum);
546 }
547
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);
552 }
553
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);
558 }
559
560 TEST(Gen, StringConcat) {
561   auto gen = seq(1, 10)
562            | map([](int n) { return folly::to<fbstring>(n); })
563            | rconcat;
564   EXPECT_EQ("12345678910", gen | as<fbstring>());
565 }
566
567 struct CopyCounter {
568   static int alive;
569   int copies;
570   int moves;
571
572   CopyCounter() : copies(0), moves(0) {
573     ++alive;
574   }
575
576   CopyCounter(CopyCounter&& source) {
577     *this = std::move(source);
578     ++alive;
579   }
580
581   CopyCounter(const CopyCounter& source) {
582     *this = source;
583     ++alive;
584   }
585
586   ~CopyCounter() {
587     --alive;
588   }
589
590   CopyCounter& operator=(const CopyCounter& source) {
591     this->copies = source.copies + 1;
592     this->moves = source.moves;
593     return *this;
594   }
595
596   CopyCounter& operator=(CopyCounter&& source) {
597     this->copies = source.copies;
598     this->moves = source.moves + 1;
599     return *this;
600   }
601 };
602
603 int CopyCounter::alive = 0;
604
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);
610
611   vector<CopyCounter> copies = from(originals) | as<vector>();
612   EXPECT_EQ(1, copies.back().copies);
613   EXPECT_EQ(0, copies.back().moves);
614
615   vector<CopyCounter> moves = from(originals) | move | as<vector>();
616   EXPECT_EQ(0, moves.back().copies);
617   EXPECT_EQ(1, moves.back().moves);
618 }
619
620 // test dynamics with various layers of nested arrays.
621 TEST(Gen, Dynamic) {
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);
628 }
629
630 TEST(StringGen, EmptySplit) {
631   auto collect = eachTo<std::string>() | as<vector>();
632   {
633     auto pieces = split("", ',') | collect;
634     EXPECT_EQ(0, pieces.size());
635   }
636
637   // The last delimiter is eaten, just like std::getline
638   {
639     auto pieces = split(",", ',') | collect;
640     EXPECT_EQ(1, pieces.size());
641     EXPECT_EQ("", pieces[0]);
642   }
643
644   {
645     auto pieces = split(",,", ',') | collect;
646     EXPECT_EQ(2, pieces.size());
647     EXPECT_EQ("", pieces[0]);
648     EXPECT_EQ("", pieces[1]);
649   }
650
651   {
652     auto pieces = split(",,", ',') | take(1) | collect;
653     EXPECT_EQ(1, pieces.size());
654     EXPECT_EQ("", pieces[0]);
655   }
656 }
657
658 TEST(StringGen, Split) {
659   auto collect = eachTo<std::string>() | as<vector>();
660   {
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]);
668   }
669
670   {
671     auto pieces = split("hello,, world, goodbye, meow", ',')
672                 | take(3) | collect;
673     EXPECT_EQ(3, pieces.size());
674     EXPECT_EQ("hello", pieces[0]);
675     EXPECT_EQ("", pieces[1]);
676     EXPECT_EQ(" world", pieces[2]);
677   }
678
679   {
680     auto pieces = split("hello,, world, goodbye, meow", ',')
681                 | take(5) | collect;
682     EXPECT_EQ(5, pieces.size());
683     EXPECT_EQ("hello", pieces[0]);
684     EXPECT_EQ("", pieces[1]);
685     EXPECT_EQ(" world", pieces[2]);
686   }
687 }
688
689 TEST(StringGen, EmptyResplit) {
690   auto collect = eachTo<std::string>() | as<vector>();
691   {
692     auto pieces = from({""}) | resplit(',') | collect;
693     EXPECT_EQ(0, pieces.size());
694   }
695
696   // The last delimiter is eaten, just like std::getline
697   {
698     auto pieces = from({","}) | resplit(',') | collect;
699     EXPECT_EQ(1, pieces.size());
700     EXPECT_EQ("", pieces[0]);
701   }
702
703   {
704     auto pieces = from({",,"}) | resplit(',') | collect;
705     EXPECT_EQ(2, pieces.size());
706     EXPECT_EQ("", pieces[0]);
707     EXPECT_EQ("", pieces[1]);
708   }
709 }
710
711 TEST(StringGen, Resplit) {
712   auto collect = eachTo<std::string>() | as<vector>();
713   {
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]);
722   }
723   {
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]);
732   }
733 }
734
735 template<typename F>
736 void runUnsplitSuite(F fn) {
737   fn("hello, world");
738   fn("hello,world,goodbye");
739   fn(" ");
740   fn("");
741   fn(", ");
742   fn(", a, b,c");
743 }
744
745 TEST(StringGen, Unsplit) {
746
747   auto basicFn = [](const StringPiece& s) {
748     EXPECT_EQ(split(s, ',') | unsplit(','), s);
749   };
750
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);
757   };
758
759   auto emptyBuffer = [](const StringPiece& s) {
760     std::string buffer;
761     split(s, ',') | unsplit(',', &buffer);
762     EXPECT_EQ(s, buffer);
763   };
764
765   auto stringDelim = [](const StringPiece& s) {
766     EXPECT_EQ(s, split(s, ',') | unsplit(","));
767     std::string buffer;
768     split(s, ',') | unsplit(",", &buffer);
769     EXPECT_EQ(buffer, s);
770   };
771
772   runUnsplitSuite(basicFn);
773   runUnsplitSuite(existingBuffer);
774   runUnsplitSuite(emptyBuffer);
775   runUnsplitSuite(stringDelim);
776   EXPECT_EQ("1, 2, 3", seq(1, 3) | unsplit(", "));
777 }
778
779 TEST(FileGen, ByLine) {
780   auto collect = eachTo<std::string>() | as<vector>();
781   test::TemporaryFile file("ByLine");
782   static const std::string lines(
783       "Hello world\n"
784       "This is the second line\n"
785       "\n"
786       "\n"
787       "a few empty lines above\n"
788       "incomplete last line");
789   EXPECT_EQ(lines.size(), write(file.fd(), lines.data(), lines.size()));
790
791   auto expected = from({lines}) | resplit('\n') | collect;
792   auto found = byLine(file.path().c_str()) | collect;
793
794   EXPECT_TRUE(expected == found);
795 }
796
797 class FileGenBufferedTest : public ::testing::TestWithParam<int> { };
798
799 TEST_P(FileGenBufferedTest, FileWriter) {
800   size_t bufferSize = GetParam();
801   test::TemporaryFile file("FileWriter");
802
803   static const std::string lines(
804       "Hello world\n"
805       "This is the second line\n"
806       "\n"
807       "\n"
808       "a few empty lines above\n");
809
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;
813
814   src | eachAs<StringPiece>() | toFile(file.fd(), bufferSize);
815   auto found = byLine(file.path().c_str()) | collect;
816
817   EXPECT_TRUE(expected == found);
818 }
819
820 INSTANTIATE_TEST_CASE_P(
821     DifferentBufferSizes,
822     FileGenBufferedTest,
823     ::testing::Values(0, 1, 2, 4, 8, 64, 4096));
824
825 int main(int argc, char *argv[]) {
826   testing::InitGoogleTest(&argc, argv);
827   google::ParseCommandLineFlags(&argc, &argv, true);
828   return RUN_ALL_TESTS();
829 }