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