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