• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
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 "perfetto/ext/base/string_splitter.h"
18 
19 #include <vector>
20 
21 #include "test/gtest_and_gmock.h"
22 
23 namespace perfetto {
24 namespace base {
25 namespace {
26 
27 using testing::ElementsAreArray;
28 
TEST(StringSplitterTest,StdString)29 TEST(StringSplitterTest, StdString) {
30   {
31     StringSplitter ss("", 'x');
32     EXPECT_EQ(nullptr, ss.cur_token());
33     EXPECT_EQ(0u, ss.cur_token_size());
34     EXPECT_FALSE(ss.Next());
35     EXPECT_EQ(nullptr, ss.cur_token());
36     EXPECT_EQ(0u, ss.cur_token_size());
37   }
38   {
39     StringSplitter ss(std::string(), 'x');
40     EXPECT_EQ(nullptr, ss.cur_token());
41     EXPECT_EQ(0u, ss.cur_token_size());
42     EXPECT_FALSE(ss.Next());
43     EXPECT_EQ(nullptr, ss.cur_token());
44     EXPECT_EQ(0u, ss.cur_token_size());
45   }
46   {
47     StringSplitter ss("a", 'x');
48     EXPECT_EQ(nullptr, ss.cur_token());
49     EXPECT_EQ(0u, ss.cur_token_size());
50     EXPECT_TRUE(ss.Next());
51     EXPECT_STREQ("a", ss.cur_token());
52     EXPECT_EQ(1u, ss.cur_token_size());
53     EXPECT_FALSE(ss.Next());
54     EXPECT_EQ(0u, ss.cur_token_size());
55   }
56   {
57     StringSplitter ss("abc", 'x');
58     EXPECT_TRUE(ss.Next());
59     EXPECT_STREQ("abc", ss.cur_token());
60     EXPECT_EQ(3u, ss.cur_token_size());
61     EXPECT_FALSE(ss.Next());
62   }
63   {
64     StringSplitter ss("ab,", ',');
65     EXPECT_TRUE(ss.Next());
66     EXPECT_STREQ("ab", ss.cur_token());
67     EXPECT_EQ(2u, ss.cur_token_size());
68     EXPECT_FALSE(ss.Next());
69   }
70   {
71     StringSplitter ss(",ab,", ',');
72     EXPECT_TRUE(ss.Next());
73     EXPECT_STREQ("ab", ss.cur_token());
74     EXPECT_EQ(2u, ss.cur_token_size());
75     EXPECT_FALSE(ss.Next());
76   }
77   {
78     StringSplitter ss("a,b,c", ',');
79     EXPECT_TRUE(ss.Next());
80     EXPECT_EQ(1u, ss.cur_token_size());
81     EXPECT_STREQ("a", ss.cur_token());
82 
83     EXPECT_TRUE(ss.Next());
84     EXPECT_STREQ("b", ss.cur_token());
85     EXPECT_EQ(1u, ss.cur_token_size());
86 
87     EXPECT_TRUE(ss.Next());
88     EXPECT_STREQ("c", ss.cur_token());
89     EXPECT_EQ(1u, ss.cur_token_size());
90 
91     EXPECT_FALSE(ss.Next());
92     EXPECT_EQ(nullptr, ss.cur_token());
93     EXPECT_EQ(0u, ss.cur_token_size());
94   }
95   {
96     StringSplitter ss("a,b,c,", ',');
97     EXPECT_TRUE(ss.Next());
98     EXPECT_STREQ("a", ss.cur_token());
99 
100     EXPECT_TRUE(ss.Next());
101     EXPECT_STREQ("b", ss.cur_token());
102 
103     EXPECT_TRUE(ss.Next());
104     EXPECT_STREQ("c", ss.cur_token());
105 
106     EXPECT_FALSE(ss.Next());
107     EXPECT_EQ(nullptr, ss.cur_token());
108   }
109   {
110     StringSplitter ss(",,a,,b,,,,c,,,", ',');
111     EXPECT_TRUE(ss.Next());
112     EXPECT_STREQ("a", ss.cur_token());
113     EXPECT_EQ(1u, ss.cur_token_size());
114 
115     EXPECT_TRUE(ss.Next());
116     EXPECT_STREQ("b", ss.cur_token());
117     EXPECT_EQ(1u, ss.cur_token_size());
118 
119     EXPECT_TRUE(ss.Next());
120     EXPECT_STREQ("c", ss.cur_token());
121     EXPECT_EQ(1u, ss.cur_token_size());
122 
123     for (int i = 0; i < 3; i++) {
124       EXPECT_FALSE(ss.Next());
125       EXPECT_EQ(0u, ss.cur_token_size());
126     }
127   }
128   {
129     StringSplitter ss(",,", ',');
130     for (int i = 0; i < 3; i++) {
131       EXPECT_FALSE(ss.Next());
132       EXPECT_EQ(nullptr, ss.cur_token());
133       EXPECT_EQ(0u, ss.cur_token_size());
134     }
135   }
136   {
137     StringSplitter ss(",,foo", ',');
138     EXPECT_TRUE(ss.Next());
139     EXPECT_STREQ("foo", ss.cur_token());
140     EXPECT_EQ(3u, ss.cur_token_size());
141     EXPECT_FALSE(ss.Next());
142   }
143 }
144 
TEST(StringSplitterTest,CString)145 TEST(StringSplitterTest, CString) {
146   {
147     char buf[] = "\0x\0";
148     StringSplitter ss(buf, sizeof(buf), ',');
149     EXPECT_FALSE(ss.Next());
150     EXPECT_EQ(nullptr, ss.cur_token());
151   }
152   {
153     char buf[] = "foo\nbar\n\nbaz\n";
154     StringSplitter ss(buf, sizeof(buf), '\n');
155     EXPECT_TRUE(ss.Next());
156     EXPECT_EQ(3u, ss.cur_token_size());
157     EXPECT_STREQ("foo", ss.cur_token());
158 
159     EXPECT_TRUE(ss.Next());
160     EXPECT_EQ(3u, ss.cur_token_size());
161     EXPECT_STREQ("bar", ss.cur_token());
162 
163     EXPECT_TRUE(ss.Next());
164     EXPECT_EQ(3u, ss.cur_token_size());
165     EXPECT_STREQ("baz", ss.cur_token());
166 
167     EXPECT_FALSE(ss.Next());
168     EXPECT_EQ(0u, ss.cur_token_size());
169   }
170   {
171     char buf[] = "";
172     StringSplitter ss(buf, 0, ',');
173     EXPECT_FALSE(ss.Next());
174     EXPECT_EQ(nullptr, ss.cur_token());
175     EXPECT_EQ(0u, ss.cur_token_size());
176   }
177   {
178     char buf[] = "\0";
179     StringSplitter ss(buf, 1, ',');
180     EXPECT_FALSE(ss.Next());
181     EXPECT_EQ(nullptr, ss.cur_token());
182     EXPECT_EQ(0u, ss.cur_token_size());
183   }
184   {
185     char buf[] = ",,foo,bar\0,baz";
186     StringSplitter ss(buf, sizeof(buf), ',');
187 
188     EXPECT_TRUE(ss.Next());
189     EXPECT_STREQ("foo", ss.cur_token());
190     EXPECT_EQ(3u, ss.cur_token_size());
191 
192     EXPECT_TRUE(ss.Next());
193     EXPECT_STREQ("bar", ss.cur_token());
194     EXPECT_EQ(3u, ss.cur_token_size());
195 
196     for (int i = 0; i < 3; i++) {
197       EXPECT_FALSE(ss.Next());
198       EXPECT_EQ(0u, ss.cur_token_size());
199     }
200   }
201   {
202     char buf[] = ",,a\0,b,";
203     StringSplitter ss(buf, sizeof(buf), ',');
204     EXPECT_TRUE(ss.Next());
205     EXPECT_STREQ("a", ss.cur_token());
206     EXPECT_EQ(1u, ss.cur_token_size());
207     for (int i = 0; i < 3; i++) {
208       EXPECT_FALSE(ss.Next());
209       EXPECT_EQ(nullptr, ss.cur_token());
210       EXPECT_EQ(0u, ss.cur_token_size());
211     }
212   }
213   {
214     char buf[] = ",a,\0b";
215     StringSplitter ss(buf, sizeof(buf), ',');
216     EXPECT_TRUE(ss.Next());
217     EXPECT_STREQ("a", ss.cur_token());
218     EXPECT_EQ(1u, ss.cur_token_size());
219     for (int i = 0; i < 3; i++) {
220       EXPECT_FALSE(ss.Next());
221       EXPECT_EQ(0u, ss.cur_token_size());
222       EXPECT_EQ(nullptr, ss.cur_token());
223     }
224   }
225   {
226     char buf[] = ",a\0\0,x\0\0b";
227     StringSplitter ss(buf, sizeof(buf), ',');
228     EXPECT_TRUE(ss.Next());
229     EXPECT_STREQ("a", ss.cur_token());
230     EXPECT_EQ(1u, ss.cur_token_size());
231     for (int i = 0; i < 3; i++) {
232       EXPECT_FALSE(ss.Next());
233       EXPECT_EQ(0u, ss.cur_token_size());
234       EXPECT_EQ(nullptr, ss.cur_token());
235     }
236   }
237 }
238 
TEST(StringSplitterTest,SplitOnNUL)239 TEST(StringSplitterTest, SplitOnNUL) {
240   {
241     StringSplitter ss(std::string(""), '\0');
242     EXPECT_FALSE(ss.Next());
243     EXPECT_EQ(nullptr, ss.cur_token());
244   }
245   {
246     std::string str;
247     str.resize(48);
248     memcpy(&str[0], "foo\0", 4);
249     memcpy(&str[4], "bar\0", 4);
250     memcpy(&str[20], "baz", 3);
251     StringSplitter ss(std::move(str), '\0');
252     EXPECT_TRUE(ss.Next());
253     EXPECT_STREQ("foo", ss.cur_token());
254     EXPECT_EQ(3u, ss.cur_token_size());
255 
256     EXPECT_TRUE(ss.Next());
257     EXPECT_STREQ("bar", ss.cur_token());
258     EXPECT_EQ(3u, ss.cur_token_size());
259 
260     EXPECT_TRUE(ss.Next());
261     EXPECT_STREQ("baz", ss.cur_token());
262     EXPECT_EQ(3u, ss.cur_token_size());
263 
264     for (int i = 0; i < 3; i++) {
265       EXPECT_FALSE(ss.Next());
266       EXPECT_EQ(0u, ss.cur_token_size());
267       EXPECT_EQ(nullptr, ss.cur_token());
268     }
269   }
270   {
271     char buf[] = "foo\0bar\0baz\0";
272     StringSplitter ss(buf, sizeof(buf), '\0');
273     EXPECT_TRUE(ss.Next());
274     EXPECT_EQ(3u, ss.cur_token_size());
275     EXPECT_STREQ("foo", ss.cur_token());
276 
277     EXPECT_TRUE(ss.Next());
278     EXPECT_EQ(3u, ss.cur_token_size());
279     EXPECT_STREQ("bar", ss.cur_token());
280 
281     EXPECT_TRUE(ss.Next());
282     EXPECT_EQ(3u, ss.cur_token_size());
283     EXPECT_STREQ("baz", ss.cur_token());
284 
285     for (int i = 0; i < 3; i++) {
286       EXPECT_FALSE(ss.Next());
287       EXPECT_EQ(0u, ss.cur_token_size());
288       EXPECT_EQ(nullptr, ss.cur_token());
289     }
290   }
291   {
292     char buf[] = "\0\0foo\0\0\0\0bar\0baz\0\0";
293     StringSplitter ss(buf, sizeof(buf), '\0');
294     EXPECT_TRUE(ss.Next());
295     EXPECT_EQ(3u, ss.cur_token_size());
296     EXPECT_STREQ("foo", ss.cur_token());
297 
298     EXPECT_TRUE(ss.Next());
299     EXPECT_EQ(3u, ss.cur_token_size());
300     EXPECT_STREQ("bar", ss.cur_token());
301 
302     EXPECT_TRUE(ss.Next());
303     EXPECT_EQ(3u, ss.cur_token_size());
304     EXPECT_STREQ("baz", ss.cur_token());
305 
306     for (int i = 0; i < 3; i++) {
307       EXPECT_FALSE(ss.Next());
308       EXPECT_EQ(0u, ss.cur_token_size());
309       EXPECT_EQ(nullptr, ss.cur_token());
310     }
311   }
312   {
313     char buf[] = "";
314     StringSplitter ss(buf, 0, '\0');
315     for (int i = 0; i < 3; i++) {
316       EXPECT_FALSE(ss.Next());
317       EXPECT_EQ(0u, ss.cur_token_size());
318       EXPECT_EQ(nullptr, ss.cur_token());
319     }
320   }
321   {
322     char buf[] = "\0";
323     StringSplitter ss(buf, 1, '\0');
324     for (int i = 0; i < 3; i++) {
325       EXPECT_FALSE(ss.Next());
326       EXPECT_EQ(0u, ss.cur_token_size());
327       EXPECT_EQ(nullptr, ss.cur_token());
328     }
329   }
330   {
331     char buf[] = "\0\0";
332     StringSplitter ss(buf, 2, '\0');
333     for (int i = 0; i < 3; i++) {
334       EXPECT_FALSE(ss.Next());
335       EXPECT_EQ(0u, ss.cur_token_size());
336       EXPECT_EQ(nullptr, ss.cur_token());
337     }
338   }
339 }
340 
TEST(StringSplitterTest,NestedUsage)341 TEST(StringSplitterTest, NestedUsage) {
342   char text[] = R"(
343 l1w1 l1w2 l1w3
344 
345 ,l,2,w,1   l,2,,w,,2,,
346 )";
347   std::vector<std::string> all_lines;
348   std::vector<std::string> all_words;
349   std::vector<std::string> all_tokens;
350   for (StringSplitter lines(text, sizeof(text), '\n'); lines.Next();) {
351     all_lines.push_back(lines.cur_token());
352     for (StringSplitter words(&lines, ' '); words.Next();) {
353       all_words.push_back(words.cur_token());
354       for (StringSplitter tokens(&words, ','); tokens.Next();) {
355         all_tokens.push_back(tokens.cur_token());
356       }
357     }
358   }
359   EXPECT_THAT(all_lines,
360               ElementsAreArray({"l1w1 l1w2 l1w3", ",l,2,w,1   l,2,,w,,2,,"}));
361   EXPECT_THAT(all_words, ElementsAreArray({"l1w1", "l1w2", "l1w3", ",l,2,w,1",
362                                            "l,2,,w,,2,,"}));
363   EXPECT_THAT(all_tokens, ElementsAreArray({"l1w1", "l1w2", "l1w3", "l", "2",
364                                             "w", "1", "l", "2", "w", "2"}));
365 }  // namespace
366 
TEST(StringSplitterTest,EmptyTokens)367 TEST(StringSplitterTest, EmptyTokens) {
368   char text[] = "a,,b";
369   std::vector<std::string> tokens;
370   for (StringSplitter lines(text, sizeof(text), ',',
371                             StringSplitter::EmptyTokenMode::ALLOW_EMPTY_TOKENS);
372        lines.Next();) {
373     tokens.push_back(lines.cur_token());
374   }
375   EXPECT_THAT(tokens, testing::ElementsAre("a", "", "b"));
376 }  // namespace
377 
378 }  // namespace
379 }  // namespace base
380 }  // namespace perfetto
381