gflags now likes namespace gflags, not google
[folly.git] / folly / gen / test / StringTest.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
17 #include <glog/logging.h>
18 #include <gtest/gtest.h>
19 #include <iosfwd>
20 #include <map>
21 #include <vector>
22
23 #include <folly/gen/String.h>
24
25 using namespace folly::gen;
26 using namespace folly;
27 using std::make_tuple;
28 using std::ostream;
29 using std::pair;
30 using std::string;
31 using std::tuple;
32 using std::unique_ptr;
33 using std::vector;
34
35 TEST(StringGen, EmptySplit) {
36   auto collect = eachTo<std::string>() | as<vector>();
37   {
38     auto pieces = split("", ',') | collect;
39     EXPECT_EQ(0, pieces.size());
40   }
41
42   // The last delimiter is eaten, just like std::getline
43   {
44     auto pieces = split(",", ',') | collect;
45     EXPECT_EQ(1, pieces.size());
46     EXPECT_EQ("", pieces[0]);
47   }
48
49   {
50     auto pieces = split(",,", ',') | collect;
51     EXPECT_EQ(2, pieces.size());
52     EXPECT_EQ("", pieces[0]);
53     EXPECT_EQ("", pieces[1]);
54   }
55
56   {
57     auto pieces = split(",,", ',') | take(1) | collect;
58     EXPECT_EQ(1, pieces.size());
59     EXPECT_EQ("", pieces[0]);
60   }
61 }
62
63 TEST(StringGen, Split) {
64   auto collect = eachTo<std::string>() | as<vector>();
65   {
66     auto pieces = split("hello,, world, goodbye, meow", ',') | collect;
67     EXPECT_EQ(5, pieces.size());
68     EXPECT_EQ("hello", pieces[0]);
69     EXPECT_EQ("", pieces[1]);
70     EXPECT_EQ(" world", pieces[2]);
71     EXPECT_EQ(" goodbye", pieces[3]);
72     EXPECT_EQ(" meow", pieces[4]);
73   }
74
75   {
76     auto pieces = split("hello,, world, goodbye, meow", ',')
77                 | take(3) | collect;
78     EXPECT_EQ(3, pieces.size());
79     EXPECT_EQ("hello", pieces[0]);
80     EXPECT_EQ("", pieces[1]);
81     EXPECT_EQ(" world", pieces[2]);
82   }
83
84   {
85     auto pieces = split("hello,, world, goodbye, meow", ",")
86                 | take(5) | collect;
87     EXPECT_EQ(5, pieces.size());
88     EXPECT_EQ("hello", pieces[0]);
89     EXPECT_EQ("", pieces[1]);
90     EXPECT_EQ(" world", pieces[2]);
91   }
92
93   {
94     auto pieces = split("hello,, world, goodbye, meow", ", ")
95                 | collect;
96     EXPECT_EQ(4, pieces.size());
97     EXPECT_EQ("hello,", pieces[0]);
98     EXPECT_EQ("world", pieces[1]);
99     EXPECT_EQ("goodbye", pieces[2]);
100     EXPECT_EQ("meow", pieces[3]);
101   }
102 }
103
104 TEST(StringGen, SplitByNewLine) {
105   auto collect = eachTo<std::string>() | as<vector>();
106   {
107     auto pieces = lines("hello\n\n world\r\n goodbye\r meow") | collect;
108     EXPECT_EQ(5, pieces.size());
109     EXPECT_EQ("hello", pieces[0]);
110     EXPECT_EQ("", pieces[1]);
111     EXPECT_EQ(" world", pieces[2]);
112     EXPECT_EQ(" goodbye", pieces[3]);
113     EXPECT_EQ(" meow", pieces[4]);
114   }
115 }
116
117 TEST(StringGen, EmptyResplit) {
118   auto collect = eachTo<std::string>() | as<vector>();
119   {
120     auto pieces = from({""}) | resplit(',') | collect;
121     EXPECT_EQ(0, pieces.size());
122   }
123
124   // The last delimiter is eaten, just like std::getline
125   {
126     auto pieces = from({","}) | resplit(',') | collect;
127     EXPECT_EQ(1, pieces.size());
128     EXPECT_EQ("", pieces[0]);
129   }
130
131   {
132     auto pieces = from({",,"}) | resplit(',') | collect;
133     EXPECT_EQ(2, pieces.size());
134     EXPECT_EQ("", pieces[0]);
135     EXPECT_EQ("", pieces[1]);
136   }
137 }
138
139 TEST(StringGen, EachToTuple) {
140   {
141     auto lines = "2:1.414:yo 3:1.732:hi";
142     auto actual
143       = split(lines, ' ')
144       | eachToTuple<int, double, std::string>(':')
145       | as<vector>();
146     vector<tuple<int, double, std::string>> expected {
147       make_tuple(2, 1.414, "yo"),
148       make_tuple(3, 1.732, "hi"),
149     };
150     EXPECT_EQ(expected, actual);
151   }
152   {
153     auto lines = "2 3";
154     auto actual
155       = split(lines, ' ')
156       | eachToTuple<int>(',')
157       | as<vector>();
158     vector<tuple<int>> expected {
159       make_tuple(2),
160       make_tuple(3),
161     };
162     EXPECT_EQ(expected, actual);
163   }
164   {
165     // StringPiece target
166     auto lines = "1:cat 2:dog";
167     auto actual
168       = split(lines, ' ')
169       | eachToTuple<int, StringPiece>(':')
170       | as<vector>();
171     vector<tuple<int, StringPiece>> expected {
172       make_tuple(1, "cat"),
173       make_tuple(2, "dog"),
174     };
175     EXPECT_EQ(expected, actual);
176   }
177   {
178     // Empty field
179     auto lines = "2:tjackson:4 3::5";
180     auto actual
181       = split(lines, ' ')
182       | eachToTuple<int, fbstring, int>(':')
183       | as<vector>();
184     vector<tuple<int, fbstring, int>> expected {
185       make_tuple(2, "tjackson", 4),
186       make_tuple(3, "", 5),
187     };
188     EXPECT_EQ(expected, actual);
189   }
190   {
191     // Excess fields
192     auto lines = "1:2 3:4:5";
193     EXPECT_THROW((split(lines, ' ')
194                     | eachToTuple<int, int>(':')
195                     | as<vector>()),
196                  std::runtime_error);
197   }
198   {
199     // Missing fields
200     auto lines = "1:2:3 4:5";
201     EXPECT_THROW((split(lines, ' ')
202                     | eachToTuple<int, int, int>(':')
203                     | as<vector>()),
204                  std::runtime_error);
205   }
206 }
207
208 TEST(StringGen, EachToPair) {
209   {
210     // char delimiters
211     auto lines = "2:1.414 3:1.732";
212     auto actual
213       = split(lines, ' ')
214       | eachToPair<int, double>(':')
215       | as<std::map<int, double>>();
216     std::map<int, double> expected {
217       { 3, 1.732 },
218       { 2, 1.414 },
219     };
220     EXPECT_EQ(expected, actual);
221   }
222   {
223     // string delimiters
224     auto lines = "ab=>cd ef=>gh";
225     auto actual
226       = split(lines, ' ')
227       | eachToPair<string, string>("=>")
228       | as<std::map<string, string>>();
229     std::map<string, string> expected {
230       { "ab", "cd" },
231       { "ef", "gh" },
232     };
233     EXPECT_EQ(expected, actual);
234   }
235 }
236
237 TEST(StringGen, Resplit) {
238   auto collect = eachTo<std::string>() | as<vector>();
239   {
240     auto pieces = from({"hello,, world, goodbye, meow"}) |
241       resplit(',') | collect;
242     EXPECT_EQ(5, pieces.size());
243     EXPECT_EQ("hello", pieces[0]);
244     EXPECT_EQ("", pieces[1]);
245     EXPECT_EQ(" world", pieces[2]);
246     EXPECT_EQ(" goodbye", pieces[3]);
247     EXPECT_EQ(" meow", pieces[4]);
248   }
249   {
250     auto pieces = from({"hel", "lo,", ", world", ", goodbye, m", "eow"}) |
251       resplit(',') | collect;
252     EXPECT_EQ(5, pieces.size());
253     EXPECT_EQ("hello", pieces[0]);
254     EXPECT_EQ("", pieces[1]);
255     EXPECT_EQ(" world", pieces[2]);
256     EXPECT_EQ(" goodbye", pieces[3]);
257     EXPECT_EQ(" meow", pieces[4]);
258   }
259 }
260
261 template<typename F>
262 void runUnsplitSuite(F fn) {
263   fn("hello, world");
264   fn("hello,world,goodbye");
265   fn(" ");
266   fn("");
267   fn(", ");
268   fn(", a, b,c");
269 }
270
271 TEST(StringGen, Unsplit) {
272
273   auto basicFn = [](StringPiece s) {
274     EXPECT_EQ(split(s, ',') | unsplit(','), s);
275   };
276
277   auto existingBuffer = [](StringPiece s) {
278     folly::fbstring buffer("asdf");
279     split(s, ',') | unsplit(',', &buffer);
280     auto expected = folly::to<folly::fbstring>(
281         "asdf", s.empty() ? "" : ",", s);
282     EXPECT_EQ(expected, buffer);
283   };
284
285   auto emptyBuffer = [](StringPiece s) {
286     std::string buffer;
287     split(s, ',') | unsplit(',', &buffer);
288     EXPECT_EQ(s, buffer);
289   };
290
291   auto stringDelim = [](StringPiece s) {
292     EXPECT_EQ(s, split(s, ',') | unsplit(","));
293     std::string buffer;
294     split(s, ',') | unsplit(",", &buffer);
295     EXPECT_EQ(buffer, s);
296   };
297
298   runUnsplitSuite(basicFn);
299   runUnsplitSuite(existingBuffer);
300   runUnsplitSuite(emptyBuffer);
301   runUnsplitSuite(stringDelim);
302   EXPECT_EQ("1, 2, 3", seq(1, 3) | unsplit(", "));
303 }
304
305 int main(int argc, char *argv[]) {
306   testing::InitGoogleTest(&argc, argv);
307   gflags::ParseCommandLineFlags(&argc, &argv, true);
308   return RUN_ALL_TESTS();
309 }