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