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/FileGen.h"
26 #include "folly/experimental/TestUtil.h"
27 #include "folly/FBVector.h"
28 #include "folly/Format.h"
29 #include "folly/dynamic.h"
31 using namespace folly::gen;
32 using namespace folly;
36 using std::unique_ptr;
40 using std::make_tuple;
41 //using std::unordered_map;
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);
51 ostream& operator<<(ostream& os, const set<T>& values) {
52 return os << from(values);
56 ostream& operator<<(ostream& os, const vector<T>& values) {
58 for (auto& value : values) {
59 if (&value != &values.front()) {
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; };
71 auto product = foldl(1, multiply);
73 template<typename A, typename B>
74 ostream& operator<<(ostream& os, const pair<A, B>& pair) {
75 return os << "(" << pair.first << ", " << pair.second << ")";
79 auto gen = seq(1, 10);
80 EXPECT_EQ(10, gen | count);
81 EXPECT_EQ(5, gen | take(5) | count);
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);
93 gen | [&](int x) { accum += x; };
96 gen | take(3) | [&](int x) { accum2 += x; };
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>());
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);
116 // cover the fenceposts of the loop unrolling
117 for (int n = 1; n < 100; ++n) {
118 EXPECT_EQ(range(0, n) | count, n);
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);
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;
136 EXPECT_EQ(330, gen | sum);
140 const auto expected = vector<int>{1, 2, 4, 5, 7, 8};
143 | filter([](int x) { return x % 3; })
145 EXPECT_EQ(expected, actual);
148 TEST(Gen, Contains) {
153 EXPECT_TRUE(gen | contains(49));
154 EXPECT_FALSE(gen | contains(50));
158 seq(1) // infinite, to prove laziness
160 | eachTo<std::string>();
162 // std::string gen, const char* needle
163 EXPECT_TRUE(gen | take(9999) | contains("49"));
168 auto expected = vector<int>{1, 4, 9, 16};
171 | mapped([](int x) { return x * x; })
174 EXPECT_EQ(expected, actual);
178 std::mt19937 rnd(42);
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
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);
207 EXPECT_EQ((small | sum), 15);
208 EXPECT_EQ((small | take(3) | count), 3);
214 | mapped([](int x) { return x * x; })
217 EXPECT_EQ((vector<int>{25, 36, 49, 64}), gen | as<vector>());
223 | mapped([](int x) { return x * x; })
224 | until([](int x) { return x >= 1000; });
225 EXPECT_EQ(31, gen | count);
228 TEST(Gen, Composed) {
229 // Operator, Operator
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
236 EXPECT_EQ(4 * 4 + 6 * 6, from(opts) | valuesOf | map(square) | sum);
238 auto sumOpt = valuesOf | sum;
239 EXPECT_EQ(10, from(opts) | sumOpt);
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);
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);
258 TEST(Gen, ConcatGen) {
259 auto gen = seq(1, 10)
260 | map([](int i) { return seq(1, i); })
262 EXPECT_EQ(220, gen | sum);
263 EXPECT_EQ(10, gen | take(6) | sum);
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); })
273 EXPECT_EQ(expected, actual);
277 auto expected = vector<int>{0, 3, 5, 6, 7, 8, 9};
279 from({8, 6, 7, 5, 3, 0, 9})
282 EXPECT_EQ(expected, actual);
285 TEST(Gen, OrderMoved) {
286 auto expected = vector<int>{0, 9, 25, 36, 49, 64, 81};
288 from({8, 6, 7, 5, 3, 0, 9})
293 EXPECT_EQ(expected, actual);
296 TEST(Gen, OrderTake) {
297 auto expected = vector<int>{9, 8, 7};
299 from({8, 6, 7, 5, 3, 0, 9})
300 | orderByDescending(square)
303 EXPECT_EQ(expected, actual);
306 TEST(Gen, Distinct) {
307 auto expected = vector<int>{3, 1, 2};
309 from({3, 1, 3, 2, 1, 2, 3})
312 EXPECT_EQ(expected, actual);
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};
319 | distinctBy([](int i) { return i * i % 10; })
321 EXPECT_EQ(expected, actual);
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};
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; })
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
340 EXPECT_EQ(expected, actual);
344 EXPECT_EQ(7, seq(1, 10)
345 | minBy([](int i) -> double {
352 auto gen = from({"three", "eleven", "four"});
354 EXPECT_EQ("eleven", gen | maxBy(&strlen));
358 fbstring expected = "facebook";
359 fbstring actual = "face";
360 from(StringPiece("book")) | appendTo(actual);
361 EXPECT_EQ(expected, actual);
364 TEST(Gen, FromRValue) {
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
370 folly::fbvector<int> v({1,2,3,4});
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);
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);
382 auto q = from([] {return vector<int>({3,7,5}); }());
383 EXPECT_EQ(expected, q | max);
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));
398 auto q = from(set<int>{1,2,3,2,1});
399 EXPECT_EQ(q | sum, 6);
404 auto expected = vector<int>{5, 6, 4, 7, 3, 8, 2, 9, 1, 10};
407 | orderBy([](int x) { return (5.1 - x) * (5.1 - x); })
409 EXPECT_EQ(expected, actual);
413 int expected = 2 * 3 * 4 * 5;
416 | foldl(1, multiply);
417 EXPECT_EQ(expected, actual);
421 int expected = 2 + 3 + 4 + 5;
422 auto actual = seq(2, 5) | reduce(add);
423 EXPECT_EQ(expected, actual);
426 TEST(Gen, ReduceBad) {
427 auto gen = seq(1) | take(0);
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);
448 | filter([](int x) { return x > 3; });
449 EXPECT_EQ(4, gen | first);
452 TEST(Gen, FromCopy) {
453 vector<int> v {3, 5};
455 auto copy = fromCopy(v);
456 EXPECT_EQ(8, src | sum);
457 EXPECT_EQ(8, copy | sum);
459 EXPECT_EQ(10, src | sum);
460 EXPECT_EQ(8, copy | sum);
464 std::map<int, int> pairs {
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);
477 EXPECT_EQ(15, keys | sum);
478 EXPECT_EQ(55, values | sum);
480 vector<tuple<int, int, int>> tuples {
483 make_tuple(3, 9, 27),
485 EXPECT_EQ(36, from(tuples) | get<2>() | sum);
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; }));
494 EXPECT_TRUE(from({1}) | any);
495 EXPECT_FALSE(range(0, 0) | any);
496 EXPECT_FALSE(from({1}) | take(0) | any);
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; }));
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; }));
509 TEST(Gen, Yielders) {
510 auto gen = GENERATOR(int) {
511 for (int i = 1; i <= 5; ++i) {
515 for (int i = 3; ; ++i) {
519 vector<int> expected {
520 1, 2, 3, 4, 5, 7, 9, 16, 25
522 EXPECT_EQ(expected, gen | take(9) | as<vector>());
525 TEST(Gen, NestedYield) {
526 auto nums = GENERATOR(int) {
527 for (int i = 1; ; ++i) {
531 auto gen = GENERATOR(int) {
532 nums | take(10) | yield;
533 seq(1, 5) | [&](int i) {
537 EXPECT_EQ(70, gen | sum);
540 TEST(Gen, MapYielders) {
543 return GENERATOR(int) {
545 for (i = 1; i < n; ++i)
552 vector<int> expected {
557 1, 2, 3, 4, 5, 4, 3, 2, 1,
559 EXPECT_EQ(expected, gen | as<vector>());
562 TEST(Gen, VirtualGen) {
563 VirtualGen<int> v(seq(1, 10));
564 EXPECT_EQ(55, v | sum);
566 EXPECT_EQ(385, v | sum);
568 EXPECT_EQ(55, v | sum);
569 EXPECT_EQ(30, v | take(4) | sum);
573 TEST(Gen, CustomType) {
577 auto gen = from({Foo{2}, Foo{3}})
578 | map([](const Foo& f) { return f.y; });
579 EXPECT_EQ(5, gen | sum);
582 TEST(Gen, NoNeedlessCopies) {
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);
593 class TestIntSeq : public GenImpl<int, TestIntSeq> {
597 template <class Body>
598 bool apply(Body&& body) const {
599 for (int i = 1; i < 6; ++i) {
607 TestIntSeq(TestIntSeq&&) = default;
608 TestIntSeq& operator=(TestIntSeq&&) = default;
609 TestIntSeq(const TestIntSeq&) = delete;
610 TestIntSeq& operator=(const TestIntSeq&) = delete;
614 TEST(Gen, NoGeneratorCopies) {
615 EXPECT_EQ(15, TestIntSeq() | sum);
616 auto x = TestIntSeq() | take(3);
617 EXPECT_EQ(6, std::move(x) | sum);
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);
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);
632 TEST(Gen, StringConcat) {
633 auto gen = seq(1, 10)
634 | map([](int n) { return folly::to<fbstring>(n); })
636 EXPECT_EQ("12345678910", gen | as<fbstring>());
644 CopyCounter() : copies(0), moves(0) {
648 CopyCounter(CopyCounter&& source) {
649 *this = std::move(source);
653 CopyCounter(const CopyCounter& source) {
662 CopyCounter& operator=(const CopyCounter& source) {
663 this->copies = source.copies + 1;
664 this->moves = source.moves;
668 CopyCounter& operator=(CopyCounter&& source) {
669 this->copies = source.copies;
670 this->moves = source.moves + 1;
675 int CopyCounter::alive = 0;
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);
683 vector<CopyCounter> copies = from(originals) | as<vector>();
684 EXPECT_EQ(1, copies.back().copies);
685 EXPECT_EQ(0, copies.back().moves);
687 vector<CopyCounter> moves = from(originals) | move | as<vector>();
688 EXPECT_EQ(0, moves.back().copies);
689 EXPECT_EQ(1, moves.back().moves);
692 // test dynamics with various layers of nested arrays.
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);
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);
711 auto s = from({7, 6, 5, 4, 3}) | as<set<int>>();
712 EXPECT_EQ(s.size(), 5);
715 TEST(StringGen, EmptySplit) {
716 auto collect = eachTo<std::string>() | as<vector>();
718 auto pieces = split("", ',') | collect;
719 EXPECT_EQ(0, pieces.size());
722 // The last delimiter is eaten, just like std::getline
724 auto pieces = split(",", ',') | collect;
725 EXPECT_EQ(1, pieces.size());
726 EXPECT_EQ("", pieces[0]);
730 auto pieces = split(",,", ',') | collect;
731 EXPECT_EQ(2, pieces.size());
732 EXPECT_EQ("", pieces[0]);
733 EXPECT_EQ("", pieces[1]);
737 auto pieces = split(",,", ',') | take(1) | collect;
738 EXPECT_EQ(1, pieces.size());
739 EXPECT_EQ("", pieces[0]);
743 TEST(StringGen, Split) {
744 auto collect = eachTo<std::string>() | as<vector>();
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]);
756 auto pieces = split("hello,, world, goodbye, meow", ',')
758 EXPECT_EQ(3, pieces.size());
759 EXPECT_EQ("hello", pieces[0]);
760 EXPECT_EQ("", pieces[1]);
761 EXPECT_EQ(" world", pieces[2]);
765 auto pieces = split("hello,, world, goodbye, meow", ',')
767 EXPECT_EQ(5, pieces.size());
768 EXPECT_EQ("hello", pieces[0]);
769 EXPECT_EQ("", pieces[1]);
770 EXPECT_EQ(" world", pieces[2]);
774 TEST(StringGen, EmptyResplit) {
775 auto collect = eachTo<std::string>() | as<vector>();
777 auto pieces = from({""}) | resplit(',') | collect;
778 EXPECT_EQ(0, pieces.size());
781 // The last delimiter is eaten, just like std::getline
783 auto pieces = from({","}) | resplit(',') | collect;
784 EXPECT_EQ(1, pieces.size());
785 EXPECT_EQ("", pieces[0]);
789 auto pieces = from({",,"}) | resplit(',') | collect;
790 EXPECT_EQ(2, pieces.size());
791 EXPECT_EQ("", pieces[0]);
792 EXPECT_EQ("", pieces[1]);
796 TEST(StringGen, Resplit) {
797 auto collect = eachTo<std::string>() | as<vector>();
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]);
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]);
821 void runUnsplitSuite(F fn) {
823 fn("hello,world,goodbye");
830 TEST(StringGen, Unsplit) {
832 auto basicFn = [](const StringPiece& s) {
833 EXPECT_EQ(split(s, ',') | unsplit(','), s);
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);
844 auto emptyBuffer = [](const StringPiece& s) {
846 split(s, ',') | unsplit(',', &buffer);
847 EXPECT_EQ(s, buffer);
850 auto stringDelim = [](const StringPiece& s) {
851 EXPECT_EQ(s, split(s, ',') | unsplit(","));
853 split(s, ',') | unsplit(",", &buffer);
854 EXPECT_EQ(buffer, s);
857 runUnsplitSuite(basicFn);
858 runUnsplitSuite(existingBuffer);
859 runUnsplitSuite(emptyBuffer);
860 runUnsplitSuite(stringDelim);
861 EXPECT_EQ("1, 2, 3", seq(1, 3) | unsplit(", "));
864 TEST(FileGen, ByLine) {
865 auto collect = eachTo<std::string>() | as<vector>();
866 test::TemporaryFile file("ByLine");
867 static const std::string lines(
869 "This is the second line\n"
872 "a few empty lines above\n"
873 "incomplete last line");
874 EXPECT_EQ(lines.size(), write(file.fd(), lines.data(), lines.size()));
876 auto expected = from({lines}) | resplit('\n') | collect;
877 auto found = byLine(file.path().c_str()) | collect;
879 EXPECT_TRUE(expected == found);
882 class FileGenBufferedTest : public ::testing::TestWithParam<int> { };
884 TEST_P(FileGenBufferedTest, FileWriter) {
885 size_t bufferSize = GetParam();
886 test::TemporaryFile file("FileWriter");
888 static const std::string lines(
890 "This is the second line\n"
893 "a few empty lines above\n");
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;
899 src | eachAs<StringPiece>() | toFile(file.fd(), bufferSize);
900 auto found = byLine(file.path().c_str()) | collect;
902 EXPECT_TRUE(expected == found);
905 INSTANTIATE_TEST_CASE_P(
906 DifferentBufferSizes,
908 ::testing::Values(0, 1, 2, 4, 8, 64, 4096));
910 int main(int argc, char *argv[]) {
911 testing::InitGoogleTest(&argc, argv);
912 google::ParseCommandLineFlags(&argc, &argv, true);
913 return RUN_ALL_TESTS();