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