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