8f8798887fceaeadb052b6372cd5d47d48cafa9b
[folly.git] / folly / gen / test / CombineTest.cpp
1 /*
2  * Copyright 2014 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 #include <gtest/gtest.h>
17 #include <string>
18 #include <vector>
19 #include <tuple>
20
21 #include "folly/Range.h"
22 #include "folly/FBVector.h"
23 #include "folly/experimental/TestUtil.h"
24 #include "folly/gen/Base.h"
25 #include "folly/gen/Combine.h"
26
27 using namespace folly::gen;
28 using namespace folly;
29 using std::string;
30 using std::vector;
31 using std::tuple;
32
33 auto even = [](int i) -> bool { return i % 2 == 0; };
34 auto odd = [](int i) -> bool { return i % 2 == 1; };
35
36 TEST(CombineGen, Interleave) {
37   { // large (infinite) base, small container
38     auto base = seq(1) | filter(odd);
39     auto toInterleave = seq(1, 6) | filter(even);
40     auto interleaved = base | interleave(toInterleave | as<vector>());
41     EXPECT_EQ(interleaved | as<vector>(), vector<int>({1, 2, 3, 4, 5, 6}));
42   }
43   { // small base, large container
44     auto base = seq(1) | filter(odd) | take(3);
45     auto toInterleave = seq(1) | filter(even) | take(50);
46     auto interleaved = base | interleave(toInterleave | as<vector>());
47     EXPECT_EQ(interleaved | as<vector>(),
48               vector<int>({1, 2, 3, 4, 5, 6}));
49   }
50 }
51
52 TEST(CombineGen, Zip) {
53   auto base0 = seq(1);
54   // We rely on std::move(fbvector) emptying the source vector
55   auto zippee = fbvector<string>{"one", "two", "three"};
56   {
57     auto combined = base0
58       | zip(zippee)
59       | as<vector>();
60     ASSERT_EQ(combined.size(), 3);
61     EXPECT_EQ(std::get<0>(combined[0]), 1);
62     EXPECT_EQ(std::get<1>(combined[0]), "one");
63     EXPECT_EQ(std::get<0>(combined[1]), 2);
64     EXPECT_EQ(std::get<1>(combined[1]), "two");
65     EXPECT_EQ(std::get<0>(combined[2]), 3);
66     EXPECT_EQ(std::get<1>(combined[2]), "three");
67     ASSERT_FALSE(zippee.empty());
68     EXPECT_FALSE(zippee.front().empty());  // shouldn't have been move'd
69   }
70
71   { // same as top, but using std::move.
72     auto combined = base0
73       | zip(std::move(zippee))
74       | as<vector>();
75     ASSERT_EQ(combined.size(), 3);
76     EXPECT_EQ(std::get<0>(combined[0]), 1);
77     EXPECT_TRUE(zippee.empty());
78   }
79
80   { // same as top, but base is truncated
81     auto baseFinite = seq(1) | take(1);
82     auto combined = baseFinite
83       | zip(vector<string>{"one", "two", "three"})
84       | as<vector>();
85     ASSERT_EQ(combined.size(), 1);
86     EXPECT_EQ(std::get<0>(combined[0]), 1);
87     EXPECT_EQ(std::get<1>(combined[0]), "one");
88   }
89 }
90
91 TEST(CombineGen, TupleFlatten) {
92   vector<tuple<int,string>> intStringTupleVec{
93     tuple<int,string>{1, "1"},
94     tuple<int,string>{2, "2"},
95     tuple<int,string>{3, "3"},
96   };
97
98   vector<tuple<char>> charTupleVec{
99     tuple<char>{'A'},
100     tuple<char>{'B'},
101     tuple<char>{'C'},
102     tuple<char>{'D'},
103   };
104
105   vector<double> doubleVec{
106     1.0,
107     4.0,
108     9.0,
109     16.0,
110     25.0,
111   };
112
113   auto zipped1 = from(intStringTupleVec)
114     | zip(charTupleVec)
115     | assert_type<tuple<tuple<int, string>, tuple<char>>>()
116     | as<vector>();
117   EXPECT_EQ(std::get<0>(zipped1[0]), std::make_tuple(1, "1"));
118   EXPECT_EQ(std::get<1>(zipped1[0]), std::make_tuple('A'));
119
120   auto zipped2 = from(zipped1)
121     | tuple_flatten
122     | assert_type<tuple<int, string, char>&&>()
123     | as<vector>();
124   ASSERT_EQ(zipped2.size(), 3);
125   EXPECT_EQ(zipped2[0], std::make_tuple(1, "1", 'A'));
126
127   auto zipped3 = from(charTupleVec)
128     | zip(intStringTupleVec)
129     | tuple_flatten
130     | assert_type<tuple<char, int, string>&&>()
131     | as<vector>();
132   ASSERT_EQ(zipped3.size(), 3);
133   EXPECT_EQ(zipped3[0], std::make_tuple('A', 1, "1"));
134
135   auto zipped4 = from(intStringTupleVec)
136     | zip(doubleVec)
137     | tuple_flatten
138     | assert_type<tuple<int, string, double>&&>()
139     | as<vector>();
140   ASSERT_EQ(zipped4.size(), 3);
141   EXPECT_EQ(zipped4[0], std::make_tuple(1, "1", 1.0));
142
143   auto zipped5 = from(doubleVec)
144     | zip(doubleVec)
145     | assert_type<tuple<double, double>>()
146     | tuple_flatten  // essentially a no-op
147     | assert_type<tuple<double, double>&&>()
148     | as<vector>();
149   ASSERT_EQ(zipped5.size(), 5);
150   EXPECT_EQ(zipped5[0], std::make_tuple(1.0, 1.0));
151
152   auto zipped6 = from(intStringTupleVec)
153     | zip(charTupleVec)
154     | tuple_flatten
155     | zip(doubleVec)
156     | tuple_flatten
157     | assert_type<tuple<int, string, char, double>&&>()
158     | as<vector>();
159   ASSERT_EQ(zipped6.size(), 3);
160   EXPECT_EQ(zipped6[0], std::make_tuple(1, "1", 'A', 1.0));
161 }
162
163 int main(int argc, char *argv[]) {
164   testing::InitGoogleTest(&argc, argv);
165   google::ParseCommandLineFlags(&argc, &argv, true);
166   return RUN_ALL_TESTS();
167 }