1 | //===- StringExtrasTest.cpp - Unit tests for String extras ----------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/ADT/StringExtras.h" |
10 | #include "llvm/Support/raw_ostream.h" |
11 | #include "gmock/gmock.h" |
12 | #include "gtest/gtest.h" |
13 | |
14 | using namespace llvm; |
15 | |
16 | TEST(StringExtrasTest, isPrint) { |
17 | EXPECT_FALSE(isPrint('\0')); |
18 | EXPECT_FALSE(isPrint('\t')); |
19 | EXPECT_TRUE(isPrint('0')); |
20 | EXPECT_TRUE(isPrint('a')); |
21 | EXPECT_TRUE(isPrint('A')); |
22 | EXPECT_TRUE(isPrint(' ')); |
23 | EXPECT_TRUE(isPrint('~')); |
24 | EXPECT_TRUE(isPrint('?')); |
25 | } |
26 | |
27 | TEST(StringExtrasTest, isSpace) { |
28 | EXPECT_TRUE(isSpace(' ')); |
29 | EXPECT_TRUE(isSpace('\t')); |
30 | EXPECT_TRUE(isSpace('\n')); |
31 | EXPECT_TRUE(isSpace('\v')); |
32 | EXPECT_TRUE(isSpace('\f')); |
33 | EXPECT_TRUE(isSpace('\v')); |
34 | EXPECT_FALSE(isSpace('\0')); |
35 | EXPECT_FALSE(isSpace('_')); |
36 | } |
37 | |
38 | TEST(StringExtrasTest, isLower) { |
39 | EXPECT_TRUE(isLower('a')); |
40 | EXPECT_TRUE(isLower('b')); |
41 | EXPECT_TRUE(isLower('z')); |
42 | EXPECT_FALSE(isLower('A')); |
43 | EXPECT_FALSE(isLower('B')); |
44 | EXPECT_FALSE(isLower('Z')); |
45 | EXPECT_FALSE(isLower('\0')); |
46 | EXPECT_FALSE(isLower('\t')); |
47 | EXPECT_FALSE(isLower('\?')); |
48 | } |
49 | |
50 | TEST(StringExtrasTest, isUpper) { |
51 | EXPECT_FALSE(isUpper('a')); |
52 | EXPECT_FALSE(isUpper('b')); |
53 | EXPECT_FALSE(isUpper('z')); |
54 | EXPECT_TRUE(isUpper('A')); |
55 | EXPECT_TRUE(isUpper('B')); |
56 | EXPECT_TRUE(isUpper('Z')); |
57 | EXPECT_FALSE(isUpper('\0')); |
58 | EXPECT_FALSE(isUpper('\t')); |
59 | EXPECT_FALSE(isUpper('\?')); |
60 | } |
61 | |
62 | template <class ContainerT> void testJoin() { |
63 | ContainerT Items; |
64 | EXPECT_EQ("" , join(Items.begin(), Items.end(), " <sep> " )); |
65 | |
66 | Items = {"foo" }; |
67 | EXPECT_EQ("foo" , join(Items.begin(), Items.end(), " <sep> " )); |
68 | |
69 | Items = {"foo" , "bar" }; |
70 | EXPECT_EQ("foo <sep> bar" , join(Items.begin(), Items.end(), " <sep> " )); |
71 | |
72 | Items = {"foo" , "bar" , "baz" }; |
73 | EXPECT_EQ("foo <sep> bar <sep> baz" , |
74 | join(Items.begin(), Items.end(), " <sep> " )); |
75 | } |
76 | |
77 | TEST(StringExtrasTest, Join) { |
78 | { |
79 | SCOPED_TRACE("std::vector<std::string>" ); |
80 | testJoin<std::vector<std::string>>(); |
81 | } |
82 | { |
83 | SCOPED_TRACE("std::vector<const char*>" ); |
84 | testJoin<std::vector<const char *>>(); |
85 | } |
86 | } |
87 | |
88 | TEST(StringExtrasTest, JoinItems) { |
89 | const char *Foo = "foo" ; |
90 | std::string Bar = "bar" ; |
91 | llvm::StringRef Baz = "baz" ; |
92 | char X = 'x'; |
93 | |
94 | EXPECT_EQ("" , join_items(" <sep> " )); |
95 | EXPECT_EQ("" , join_items('/')); |
96 | |
97 | EXPECT_EQ("foo" , join_items(" <sep> " , Foo)); |
98 | EXPECT_EQ("foo" , join_items('/', Foo)); |
99 | |
100 | EXPECT_EQ("foo <sep> bar" , join_items(" <sep> " , Foo, Bar)); |
101 | EXPECT_EQ("foo/bar" , join_items('/', Foo, Bar)); |
102 | |
103 | EXPECT_EQ("foo <sep> bar <sep> baz" , join_items(" <sep> " , Foo, Bar, Baz)); |
104 | EXPECT_EQ("foo/bar/baz" , join_items('/', Foo, Bar, Baz)); |
105 | |
106 | EXPECT_EQ("foo <sep> bar <sep> baz <sep> x" , |
107 | join_items(" <sep> " , Foo, Bar, Baz, X)); |
108 | |
109 | EXPECT_EQ("foo/bar/baz/x" , join_items('/', Foo, Bar, Baz, X)); |
110 | } |
111 | |
112 | TEST(StringExtrasTest, ToAndFromHex) { |
113 | std::vector<uint8_t> OddBytes = {0x5, 0xBD, 0x0D, 0x3E, 0xCD}; |
114 | std::string OddStr = "05BD0D3ECD" ; |
115 | StringRef OddData(reinterpret_cast<const char *>(OddBytes.data()), |
116 | OddBytes.size()); |
117 | EXPECT_EQ(OddStr, toHex(OddData)); |
118 | EXPECT_EQ(OddData, fromHex(StringRef(OddStr).drop_front())); |
119 | EXPECT_EQ(StringRef(OddStr).lower(), toHex(OddData, true)); |
120 | |
121 | std::vector<uint8_t> EvenBytes = {0xA5, 0xBD, 0x0D, 0x3E, 0xCD}; |
122 | std::string EvenStr = "A5BD0D3ECD" ; |
123 | StringRef EvenData(reinterpret_cast<const char *>(EvenBytes.data()), |
124 | EvenBytes.size()); |
125 | EXPECT_EQ(EvenStr, toHex(EvenData)); |
126 | EXPECT_EQ(EvenData, fromHex(EvenStr)); |
127 | EXPECT_EQ(StringRef(EvenStr).lower(), toHex(EvenData, true)); |
128 | |
129 | std::string InvalidStr = "A50\xFF" ; |
130 | std::string IgnoredOutput; |
131 | EXPECT_FALSE(tryGetFromHex(InvalidStr, IgnoredOutput)); |
132 | } |
133 | |
134 | TEST(StringExtrasTest, UINT64ToHex) { |
135 | EXPECT_EQ(utohexstr(0xA0u), "A0" ); |
136 | EXPECT_EQ(utohexstr(0xA0u, false, 4), "00A0" ); |
137 | EXPECT_EQ(utohexstr(0xA0u, false, 8), "000000A0" ); |
138 | } |
139 | |
140 | TEST(StringExtrasTest, to_float) { |
141 | float F; |
142 | EXPECT_TRUE(to_float("4.7" , F)); |
143 | EXPECT_FLOAT_EQ(4.7f, F); |
144 | |
145 | double D; |
146 | EXPECT_TRUE(to_float("4.7" , D)); |
147 | EXPECT_DOUBLE_EQ(4.7, D); |
148 | |
149 | long double LD; |
150 | EXPECT_TRUE(to_float("4.7" , LD)); |
151 | EXPECT_DOUBLE_EQ(4.7, LD); |
152 | |
153 | EXPECT_FALSE(to_float("foo" , F)); |
154 | EXPECT_FALSE(to_float("7.4 foo" , F)); |
155 | EXPECT_FLOAT_EQ(4.7f, F); // F should be unchanged |
156 | } |
157 | |
158 | TEST(StringExtrasTest, printLowerCase) { |
159 | std::string str; |
160 | raw_string_ostream OS(str); |
161 | printLowerCase(String: "ABCdefg01234.,&!~`'}\"" , Out&: OS); |
162 | EXPECT_EQ("abcdefg01234.,&!~`'}\"" , OS.str()); |
163 | } |
164 | |
165 | TEST(StringExtrasTest, printEscapedString) { |
166 | std::string str; |
167 | raw_string_ostream OS(str); |
168 | printEscapedString(Name: "ABCdef123&<>\\\"'\t" , Out&: OS); |
169 | EXPECT_EQ("ABCdef123&<>\\\\\\22'\\09" , OS.str()); |
170 | } |
171 | |
172 | TEST(StringExtrasTest, printHTMLEscaped) { |
173 | std::string str; |
174 | raw_string_ostream OS(str); |
175 | printHTMLEscaped(String: "ABCdef123&<>\"'" , Out&: OS); |
176 | EXPECT_EQ("ABCdef123&<>"'" , OS.str()); |
177 | } |
178 | |
179 | TEST(StringExtrasTest, ConvertToSnakeFromCamelCase) { |
180 | auto testConvertToSnakeCase = [](llvm::StringRef input, |
181 | llvm::StringRef expected) { |
182 | EXPECT_EQ(convertToSnakeFromCamelCase(input), expected.str()); |
183 | }; |
184 | |
185 | testConvertToSnakeCase("OpName" , "op_name" ); |
186 | testConvertToSnakeCase("opName" , "op_name" ); |
187 | testConvertToSnakeCase("OPName" , "op_name" ); |
188 | testConvertToSnakeCase("Intel_OCL_BI" , "intel_ocl_bi" ); |
189 | testConvertToSnakeCase("I32Attr" , "i32_attr" ); |
190 | testConvertToSnakeCase("opNAME" , "op_name" ); |
191 | testConvertToSnakeCase("opNAMe" , "op_na_me" ); |
192 | testConvertToSnakeCase("opnameE" , "opname_e" ); |
193 | testConvertToSnakeCase("OPNameOPName" , "op_name_op_name" ); |
194 | testConvertToSnakeCase("_OpName" , "_op_name" ); |
195 | testConvertToSnakeCase("Op_Name" , "op_name" ); |
196 | testConvertToSnakeCase("" , "" ); |
197 | testConvertToSnakeCase("A" , "a" ); |
198 | testConvertToSnakeCase("_" , "_" ); |
199 | testConvertToSnakeCase("a" , "a" ); |
200 | testConvertToSnakeCase("op_name" , "op_name" ); |
201 | testConvertToSnakeCase("_op_name" , "_op_name" ); |
202 | testConvertToSnakeCase("__op_name" , "__op_name" ); |
203 | testConvertToSnakeCase("op__name" , "op__name" ); |
204 | } |
205 | |
206 | TEST(StringExtrasTest, ConvertToCamelFromSnakeCase) { |
207 | auto testConvertToCamelCase = [](bool capitalizeFirst, llvm::StringRef input, |
208 | llvm::StringRef expected) { |
209 | EXPECT_EQ(convertToCamelFromSnakeCase(input, capitalizeFirst), |
210 | expected.str()); |
211 | }; |
212 | |
213 | testConvertToCamelCase(false, "op_name" , "opName" ); |
214 | testConvertToCamelCase(false, "_op_name" , "_opName" ); |
215 | testConvertToCamelCase(false, "__op_name" , "_OpName" ); |
216 | testConvertToCamelCase(false, "op__name" , "op_Name" ); |
217 | testConvertToCamelCase(false, "" , "" ); |
218 | testConvertToCamelCase(false, "A" , "A" ); |
219 | testConvertToCamelCase(false, "_" , "_" ); |
220 | testConvertToCamelCase(false, "a" , "a" ); |
221 | testConvertToCamelCase(false, "OpName" , "OpName" ); |
222 | testConvertToCamelCase(false, "opName" , "opName" ); |
223 | testConvertToCamelCase(false, "_OpName" , "_OpName" ); |
224 | testConvertToCamelCase(false, "Op_Name" , "Op_Name" ); |
225 | testConvertToCamelCase(true, "op_name" , "OpName" ); |
226 | testConvertToCamelCase(true, "_op_name" , "_opName" ); |
227 | testConvertToCamelCase(true, "__op_name" , "_OpName" ); |
228 | testConvertToCamelCase(true, "op__name" , "Op_Name" ); |
229 | testConvertToCamelCase(true, "" , "" ); |
230 | testConvertToCamelCase(true, "A" , "A" ); |
231 | testConvertToCamelCase(true, "_" , "_" ); |
232 | testConvertToCamelCase(true, "a" , "A" ); |
233 | testConvertToCamelCase(true, "OpName" , "OpName" ); |
234 | testConvertToCamelCase(true, "_OpName" , "_OpName" ); |
235 | testConvertToCamelCase(true, "Op_Name" , "Op_Name" ); |
236 | testConvertToCamelCase(true, "opName" , "OpName" ); |
237 | } |
238 | |
239 | constexpr uint64_t MaxUint64 = std::numeric_limits<uint64_t>::max(); |
240 | constexpr int64_t MaxInt64 = std::numeric_limits<int64_t>::max(); |
241 | constexpr int64_t MinInt64 = std::numeric_limits<int64_t>::min(); |
242 | |
243 | TEST(StringExtrasTest, UToStr) { |
244 | EXPECT_EQ("0" , utostr(0)); |
245 | EXPECT_EQ("0" , utostr(0, /*isNeg=*/false)); |
246 | EXPECT_EQ("1" , utostr(1)); |
247 | EXPECT_EQ("1" , utostr(1, /*isNeg=*/false)); |
248 | EXPECT_EQ(std::to_string(MaxUint64), utostr(MaxUint64)); |
249 | EXPECT_EQ(std::to_string(MaxUint64), utostr(MaxUint64, /*isNeg=*/false)); |
250 | |
251 | EXPECT_EQ("-0" , utostr(0, /*isNeg=*/true)); |
252 | EXPECT_EQ("-1" , utostr(1, /*isNeg=*/true)); |
253 | EXPECT_EQ("-" + std::to_string(MaxInt64), utostr(MaxInt64, /*isNeg=*/true)); |
254 | constexpr uint64_t MinusMinInt64 = -static_cast<uint64_t>(MinInt64); |
255 | EXPECT_EQ("-" + std::to_string(MinusMinInt64), |
256 | utostr(MinusMinInt64, /*isNeg=*/true)); |
257 | EXPECT_EQ("-" + std::to_string(MaxUint64), utostr(MaxUint64, /*isNeg=*/true)); |
258 | } |
259 | |
260 | TEST(StringExtrasTest, IToStr) { |
261 | EXPECT_EQ("0" , itostr(0)); |
262 | EXPECT_EQ("1" , itostr(1)); |
263 | EXPECT_EQ("-1" , itostr(-1)); |
264 | EXPECT_EQ(std::to_string(MinInt64), itostr(MinInt64)); |
265 | EXPECT_EQ(std::to_string(MaxInt64), itostr(MaxInt64)); |
266 | } |
267 | |
268 | TEST(StringExtrasTest, ListSeparator) { |
269 | ListSeparator LS; |
270 | StringRef S = LS; |
271 | EXPECT_EQ(S, "" ); |
272 | S = LS; |
273 | EXPECT_EQ(S, ", " ); |
274 | |
275 | ListSeparator LS2(" " ); |
276 | S = LS2; |
277 | EXPECT_EQ(S, "" ); |
278 | S = LS2; |
279 | EXPECT_EQ(S, " " ); |
280 | } |
281 | |
282 | TEST(StringExtrasTest, toStringAPInt) { |
283 | bool isSigned; |
284 | |
285 | EXPECT_EQ(toString(APInt(8, 0), 2, true, true), "0b0" ); |
286 | EXPECT_EQ(toString(APInt(8, 0), 8, true, true), "00" ); |
287 | EXPECT_EQ(toString(APInt(8, 0), 10, true, true), "0" ); |
288 | EXPECT_EQ(toString(APInt(8, 0), 16, true, true), "0x0" ); |
289 | EXPECT_EQ(toString(APInt(8, 0), 36, true, false), "0" ); |
290 | |
291 | isSigned = false; |
292 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 2, isSigned, true), "0b11111111" ); |
293 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 8, isSigned, true), "0377" ); |
294 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 10, isSigned, true), "255" ); |
295 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 16, isSigned, true), "0xFF" ); |
296 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 36, isSigned, false), "73" ); |
297 | |
298 | isSigned = true; |
299 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 2, isSigned, true), "-0b1" ); |
300 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 8, isSigned, true), "-01" ); |
301 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 10, isSigned, true), "-1" ); |
302 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 16, isSigned, true), "-0x1" ); |
303 | EXPECT_EQ(toString(APInt(8, 255, isSigned), 36, isSigned, false), "-1" ); |
304 | } |
305 | |
306 | TEST(StringExtrasTest, toStringAPSInt) { |
307 | bool isUnsigned; |
308 | |
309 | EXPECT_EQ(toString(APSInt(APInt(8, 0), false), 2), "0" ); |
310 | EXPECT_EQ(toString(APSInt(APInt(8, 0), false), 8), "0" ); |
311 | EXPECT_EQ(toString(APSInt(APInt(8, 0), false), 10), "0" ); |
312 | EXPECT_EQ(toString(APSInt(APInt(8, 0), false), 16), "0" ); |
313 | |
314 | isUnsigned = true; |
315 | EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 2), "11111111" ); |
316 | EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 8), "377" ); |
317 | EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 10), "255" ); |
318 | EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 16), "FF" ); |
319 | |
320 | isUnsigned = false; |
321 | EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 2), "-1" ); |
322 | EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 8), "-1" ); |
323 | EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 10), "-1" ); |
324 | EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 16), "-1" ); |
325 | } |
326 | |
327 | TEST(StringExtrasTest, splitStringRef) { |
328 | auto Spl = split(Str: "foo<=>bar<=><=>baz" , Separator: "<=>" ); |
329 | auto It = Spl.begin(); |
330 | auto End = Spl.end(); |
331 | |
332 | ASSERT_NE(It, End); |
333 | EXPECT_EQ(*It, StringRef("foo" )); |
334 | ASSERT_NE(++It, End); |
335 | EXPECT_EQ(*It, StringRef("bar" )); |
336 | ASSERT_NE(++It, End); |
337 | EXPECT_EQ(*It, StringRef("" )); |
338 | ASSERT_NE(++It, End); |
339 | EXPECT_EQ(*It, StringRef("baz" )); |
340 | ASSERT_EQ(++It, End); |
341 | } |
342 | |
343 | TEST(StringExtrasTest, splitStringRefForLoop) { |
344 | llvm::SmallVector<StringRef, 4> Result; |
345 | for (StringRef x : split(Str: "foo<=>bar<=><=>baz" , Separator: "<=>" )) |
346 | Result.push_back(Elt: x); |
347 | EXPECT_THAT(Result, testing::ElementsAre("foo" , "bar" , "" , "baz" )); |
348 | } |
349 | |
350 | TEST(StringExtrasTest, splitChar) { |
351 | auto Spl = split(Str: "foo,bar,,baz" , Separator: ','); |
352 | auto It = Spl.begin(); |
353 | auto End = Spl.end(); |
354 | |
355 | ASSERT_NE(It, End); |
356 | EXPECT_EQ(*It, StringRef("foo" )); |
357 | ASSERT_NE(++It, End); |
358 | EXPECT_EQ(*It, StringRef("bar" )); |
359 | ASSERT_NE(++It, End); |
360 | EXPECT_EQ(*It, StringRef("" )); |
361 | ASSERT_NE(++It, End); |
362 | EXPECT_EQ(*It, StringRef("baz" )); |
363 | ASSERT_EQ(++It, End); |
364 | } |
365 | |
366 | TEST(StringExtrasTest, splitCharForLoop) { |
367 | llvm::SmallVector<StringRef, 4> Result; |
368 | for (StringRef x : split(Str: "foo,bar,,baz" , Separator: ',')) |
369 | Result.push_back(Elt: x); |
370 | EXPECT_THAT(Result, testing::ElementsAre("foo" , "bar" , "" , "baz" )); |
371 | } |
372 | |
373 | TEST(StringExtrasTest, arrayToStringRef) { |
374 | auto roundTripTestString = [](llvm::StringRef Str) { |
375 | EXPECT_EQ(Str, toStringRef(arrayRefFromStringRef<uint8_t>(Str))); |
376 | EXPECT_EQ(Str, toStringRef(arrayRefFromStringRef<char>(Str))); |
377 | }; |
378 | roundTripTestString("" ); |
379 | roundTripTestString("foo" ); |
380 | roundTripTestString("\0\n" ); |
381 | roundTripTestString("\xFF\xFE" ); |
382 | } |
383 | |