1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/strings/ascii.h"
16
17 #include <algorithm>
18 #include <cctype>
19 #include <clocale>
20 #include <cstring>
21 #include <string>
22
23 #include "gtest/gtest.h"
24 #include "absl/base/macros.h"
25 #include "absl/strings/string_view.h"
26
27 namespace {
28
TEST(AsciiIsFoo,All)29 TEST(AsciiIsFoo, All) {
30 for (int i = 0; i < 256; i++) {
31 const auto c = static_cast<unsigned char>(i);
32 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
33 EXPECT_TRUE(absl::ascii_isalpha(c)) << ": failed on " << c;
34 else
35 EXPECT_TRUE(!absl::ascii_isalpha(c)) << ": failed on " << c;
36 }
37 for (int i = 0; i < 256; i++) {
38 const auto c = static_cast<unsigned char>(i);
39 if ((c >= '0' && c <= '9'))
40 EXPECT_TRUE(absl::ascii_isdigit(c)) << ": failed on " << c;
41 else
42 EXPECT_TRUE(!absl::ascii_isdigit(c)) << ": failed on " << c;
43 }
44 for (int i = 0; i < 256; i++) {
45 const auto c = static_cast<unsigned char>(i);
46 if (absl::ascii_isalpha(c) || absl::ascii_isdigit(c))
47 EXPECT_TRUE(absl::ascii_isalnum(c)) << ": failed on " << c;
48 else
49 EXPECT_TRUE(!absl::ascii_isalnum(c)) << ": failed on " << c;
50 }
51 for (int i = 0; i < 256; i++) {
52 const auto c = static_cast<unsigned char>(i);
53 if (i != '\0' && strchr(" \r\n\t\v\f", i))
54 EXPECT_TRUE(absl::ascii_isspace(c)) << ": failed on " << c;
55 else
56 EXPECT_TRUE(!absl::ascii_isspace(c)) << ": failed on " << c;
57 }
58 for (int i = 0; i < 256; i++) {
59 const auto c = static_cast<unsigned char>(i);
60 if (i >= 32 && i < 127)
61 EXPECT_TRUE(absl::ascii_isprint(c)) << ": failed on " << c;
62 else
63 EXPECT_TRUE(!absl::ascii_isprint(c)) << ": failed on " << c;
64 }
65 for (int i = 0; i < 256; i++) {
66 const auto c = static_cast<unsigned char>(i);
67 if (absl::ascii_isprint(c) && !absl::ascii_isspace(c) &&
68 !absl::ascii_isalnum(c)) {
69 EXPECT_TRUE(absl::ascii_ispunct(c)) << ": failed on " << c;
70 } else {
71 EXPECT_TRUE(!absl::ascii_ispunct(c)) << ": failed on " << c;
72 }
73 }
74 for (int i = 0; i < 256; i++) {
75 const auto c = static_cast<unsigned char>(i);
76 if (i == ' ' || i == '\t')
77 EXPECT_TRUE(absl::ascii_isblank(c)) << ": failed on " << c;
78 else
79 EXPECT_TRUE(!absl::ascii_isblank(c)) << ": failed on " << c;
80 }
81 for (int i = 0; i < 256; i++) {
82 const auto c = static_cast<unsigned char>(i);
83 if (i < 32 || i == 127)
84 EXPECT_TRUE(absl::ascii_iscntrl(c)) << ": failed on " << c;
85 else
86 EXPECT_TRUE(!absl::ascii_iscntrl(c)) << ": failed on " << c;
87 }
88 for (int i = 0; i < 256; i++) {
89 const auto c = static_cast<unsigned char>(i);
90 if (absl::ascii_isdigit(c) || (i >= 'A' && i <= 'F') ||
91 (i >= 'a' && i <= 'f')) {
92 EXPECT_TRUE(absl::ascii_isxdigit(c)) << ": failed on " << c;
93 } else {
94 EXPECT_TRUE(!absl::ascii_isxdigit(c)) << ": failed on " << c;
95 }
96 }
97 for (int i = 0; i < 256; i++) {
98 const auto c = static_cast<unsigned char>(i);
99 if (i > 32 && i < 127)
100 EXPECT_TRUE(absl::ascii_isgraph(c)) << ": failed on " << c;
101 else
102 EXPECT_TRUE(!absl::ascii_isgraph(c)) << ": failed on " << c;
103 }
104 for (int i = 0; i < 256; i++) {
105 const auto c = static_cast<unsigned char>(i);
106 if (i >= 'A' && i <= 'Z')
107 EXPECT_TRUE(absl::ascii_isupper(c)) << ": failed on " << c;
108 else
109 EXPECT_TRUE(!absl::ascii_isupper(c)) << ": failed on " << c;
110 }
111 for (int i = 0; i < 256; i++) {
112 const auto c = static_cast<unsigned char>(i);
113 if (i >= 'a' && i <= 'z')
114 EXPECT_TRUE(absl::ascii_islower(c)) << ": failed on " << c;
115 else
116 EXPECT_TRUE(!absl::ascii_islower(c)) << ": failed on " << c;
117 }
118 for (unsigned char c = 0; c < 128; c++) {
119 EXPECT_TRUE(absl::ascii_isascii(c)) << ": failed on " << c;
120 }
121 for (int i = 128; i < 256; i++) {
122 const auto c = static_cast<unsigned char>(i);
123 EXPECT_TRUE(!absl::ascii_isascii(c)) << ": failed on " << c;
124 }
125 }
126
127 // Checks that absl::ascii_isfoo returns the same value as isfoo in the C
128 // locale.
TEST(AsciiIsFoo,SameAsIsFoo)129 TEST(AsciiIsFoo, SameAsIsFoo) {
130 #ifndef __ANDROID__
131 // temporarily change locale to C. It should already be C, but just for safety
132 const char* old_locale = setlocale(LC_CTYPE, "C");
133 ASSERT_TRUE(old_locale != nullptr);
134 #endif
135
136 for (int i = 0; i < 256; i++) {
137 const auto c = static_cast<unsigned char>(i);
138 EXPECT_EQ(isalpha(c) != 0, absl::ascii_isalpha(c)) << c;
139 EXPECT_EQ(isdigit(c) != 0, absl::ascii_isdigit(c)) << c;
140 EXPECT_EQ(isalnum(c) != 0, absl::ascii_isalnum(c)) << c;
141 EXPECT_EQ(isspace(c) != 0, absl::ascii_isspace(c)) << c;
142 EXPECT_EQ(ispunct(c) != 0, absl::ascii_ispunct(c)) << c;
143 EXPECT_EQ(isblank(c) != 0, absl::ascii_isblank(c)) << c;
144 EXPECT_EQ(iscntrl(c) != 0, absl::ascii_iscntrl(c)) << c;
145 EXPECT_EQ(isxdigit(c) != 0, absl::ascii_isxdigit(c)) << c;
146 EXPECT_EQ(isprint(c) != 0, absl::ascii_isprint(c)) << c;
147 EXPECT_EQ(isgraph(c) != 0, absl::ascii_isgraph(c)) << c;
148 EXPECT_EQ(isupper(c) != 0, absl::ascii_isupper(c)) << c;
149 EXPECT_EQ(islower(c) != 0, absl::ascii_islower(c)) << c;
150 EXPECT_EQ(isascii(c) != 0, absl::ascii_isascii(c)) << c;
151 }
152
153 #ifndef __ANDROID__
154 // restore the old locale.
155 ASSERT_TRUE(setlocale(LC_CTYPE, old_locale));
156 #endif
157 }
158
TEST(AsciiToFoo,All)159 TEST(AsciiToFoo, All) {
160 #ifndef __ANDROID__
161 // temporarily change locale to C. It should already be C, but just for safety
162 const char* old_locale = setlocale(LC_CTYPE, "C");
163 ASSERT_TRUE(old_locale != nullptr);
164 #endif
165
166 for (int i = 0; i < 256; i++) {
167 const auto c = static_cast<unsigned char>(i);
168 if (absl::ascii_islower(c))
169 EXPECT_EQ(absl::ascii_toupper(c), 'A' + (i - 'a')) << c;
170 else
171 EXPECT_EQ(absl::ascii_toupper(c), static_cast<char>(i)) << c;
172
173 if (absl::ascii_isupper(c))
174 EXPECT_EQ(absl::ascii_tolower(c), 'a' + (i - 'A')) << c;
175 else
176 EXPECT_EQ(absl::ascii_tolower(c), static_cast<char>(i)) << c;
177
178 // These CHECKs only hold in a C locale.
179 EXPECT_EQ(static_cast<char>(tolower(i)), absl::ascii_tolower(c)) << c;
180 EXPECT_EQ(static_cast<char>(toupper(i)), absl::ascii_toupper(c)) << c;
181 }
182 #ifndef __ANDROID__
183 // restore the old locale.
184 ASSERT_TRUE(setlocale(LC_CTYPE, old_locale));
185 #endif
186 }
187
TEST(AsciiStrTo,Lower)188 TEST(AsciiStrTo, Lower) {
189 const char buf[] = "ABCDEF";
190 const std::string str("GHIJKL");
191 const std::string str2("MNOPQR");
192 const absl::string_view sp(str2);
193 const std::string long_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ1!a");
194 std::string mutable_str("_`?@[{AMNOPQRSTUVWXYZ");
195 auto fun = []() -> std::string { return "PQRSTU"; };
196
197 EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf));
198 EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str));
199 EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp));
200 EXPECT_EQ("abcdefghijklmnopqrstuvwxyz1!a", absl::AsciiStrToLower(long_str));
201 EXPECT_EQ("pqrstu", absl::AsciiStrToLower(fun()));
202
203 // An empty `string_view` specifically exercises the case where a null data
204 // pointer is passed to internal functions.
205 EXPECT_EQ("", absl::AsciiStrToLower(absl::string_view()));
206
207 absl::AsciiStrToLower(&mutable_str);
208 EXPECT_EQ("_`?@[{amnopqrstuvwxyz", mutable_str);
209
210 char mutable_buf[] = "Mutable";
211 std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
212 mutable_buf, absl::ascii_tolower);
213 EXPECT_STREQ("mutable", mutable_buf);
214 }
215
TEST(AsciiStrTo,Upper)216 TEST(AsciiStrTo, Upper) {
217 const char buf[] = "abcdef";
218 const std::string str("ghijkl");
219 const std::string str2("_`?@[{amnopqrstuvwxyz");
220 const absl::string_view sp(str2);
221 const std::string long_str("abcdefghijklmnopqrstuvwxyz1!A");
222 auto fun = []() -> std::string { return "pqrstu"; };
223
224 EXPECT_EQ("ABCDEF", absl::AsciiStrToUpper(buf));
225 EXPECT_EQ("GHIJKL", absl::AsciiStrToUpper(str));
226 EXPECT_EQ("_`?@[{AMNOPQRSTUVWXYZ", absl::AsciiStrToUpper(sp));
227 EXPECT_EQ("ABCDEFGHIJKLMNOPQRSTUVWXYZ1!A", absl::AsciiStrToUpper(long_str));
228 EXPECT_EQ("PQRSTU", absl::AsciiStrToUpper(fun()));
229
230 // An empty `string_view` specifically exercises the case where a null data
231 // pointer is passed to internal functions.
232 EXPECT_EQ("", absl::AsciiStrToUpper(absl::string_view()));
233
234 char mutable_buf[] = "Mutable";
235 std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
236 mutable_buf, absl::ascii_toupper);
237 EXPECT_STREQ("MUTABLE", mutable_buf);
238 }
239
TEST(StripLeadingAsciiWhitespace,FromStringView)240 TEST(StripLeadingAsciiWhitespace, FromStringView) {
241 EXPECT_EQ(absl::string_view{},
242 absl::StripLeadingAsciiWhitespace(absl::string_view{}));
243 EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace({"foo"}));
244 EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace({"\t \n\f\r\n\vfoo"}));
245 EXPECT_EQ("foo foo\n ",
246 absl::StripLeadingAsciiWhitespace({"\t \n\f\r\n\vfoo foo\n "}));
247 EXPECT_EQ(absl::string_view{}, absl::StripLeadingAsciiWhitespace(
248 {"\t \n\f\r\v\n\t \n\f\r\v\n"}));
249 }
250
TEST(StripLeadingAsciiWhitespace,InPlace)251 TEST(StripLeadingAsciiWhitespace, InPlace) {
252 std::string str;
253
254 absl::StripLeadingAsciiWhitespace(&str);
255 EXPECT_EQ("", str);
256
257 str = "foo";
258 absl::StripLeadingAsciiWhitespace(&str);
259 EXPECT_EQ("foo", str);
260
261 str = "\t \n\f\r\n\vfoo";
262 absl::StripLeadingAsciiWhitespace(&str);
263 EXPECT_EQ("foo", str);
264
265 str = "\t \n\f\r\n\vfoo foo\n ";
266 absl::StripLeadingAsciiWhitespace(&str);
267 EXPECT_EQ("foo foo\n ", str);
268
269 str = "\t \n\f\r\v\n\t \n\f\r\v\n";
270 absl::StripLeadingAsciiWhitespace(&str);
271 EXPECT_EQ(absl::string_view{}, str);
272 }
273
TEST(StripTrailingAsciiWhitespace,FromStringView)274 TEST(StripTrailingAsciiWhitespace, FromStringView) {
275 EXPECT_EQ(absl::string_view{},
276 absl::StripTrailingAsciiWhitespace(absl::string_view{}));
277 EXPECT_EQ("foo", absl::StripTrailingAsciiWhitespace({"foo"}));
278 EXPECT_EQ("foo", absl::StripTrailingAsciiWhitespace({"foo\t \n\f\r\n\v"}));
279 EXPECT_EQ(" \nfoo foo",
280 absl::StripTrailingAsciiWhitespace({" \nfoo foo\t \n\f\r\n\v"}));
281 EXPECT_EQ(absl::string_view{}, absl::StripTrailingAsciiWhitespace(
282 {"\t \n\f\r\v\n\t \n\f\r\v\n"}));
283 }
284
TEST(StripTrailingAsciiWhitespace,InPlace)285 TEST(StripTrailingAsciiWhitespace, InPlace) {
286 std::string str;
287
288 absl::StripTrailingAsciiWhitespace(&str);
289 EXPECT_EQ("", str);
290
291 str = "foo";
292 absl::StripTrailingAsciiWhitespace(&str);
293 EXPECT_EQ("foo", str);
294
295 str = "foo\t \n\f\r\n\v";
296 absl::StripTrailingAsciiWhitespace(&str);
297 EXPECT_EQ("foo", str);
298
299 str = " \nfoo foo\t \n\f\r\n\v";
300 absl::StripTrailingAsciiWhitespace(&str);
301 EXPECT_EQ(" \nfoo foo", str);
302
303 str = "\t \n\f\r\v\n\t \n\f\r\v\n";
304 absl::StripTrailingAsciiWhitespace(&str);
305 EXPECT_EQ(absl::string_view{}, str);
306 }
307
TEST(StripAsciiWhitespace,FromStringView)308 TEST(StripAsciiWhitespace, FromStringView) {
309 EXPECT_EQ(absl::string_view{},
310 absl::StripAsciiWhitespace(absl::string_view{}));
311 EXPECT_EQ("foo", absl::StripAsciiWhitespace({"foo"}));
312 EXPECT_EQ("foo",
313 absl::StripAsciiWhitespace({"\t \n\f\r\n\vfoo\t \n\f\r\n\v"}));
314 EXPECT_EQ("foo foo", absl::StripAsciiWhitespace(
315 {"\t \n\f\r\n\vfoo foo\t \n\f\r\n\v"}));
316 EXPECT_EQ(absl::string_view{},
317 absl::StripAsciiWhitespace({"\t \n\f\r\v\n\t \n\f\r\v\n"}));
318 }
319
TEST(StripAsciiWhitespace,InPlace)320 TEST(StripAsciiWhitespace, InPlace) {
321 std::string str;
322
323 absl::StripAsciiWhitespace(&str);
324 EXPECT_EQ("", str);
325
326 str = "foo";
327 absl::StripAsciiWhitespace(&str);
328 EXPECT_EQ("foo", str);
329
330 str = "\t \n\f\r\n\vfoo\t \n\f\r\n\v";
331 absl::StripAsciiWhitespace(&str);
332 EXPECT_EQ("foo", str);
333
334 str = "\t \n\f\r\n\vfoo foo\t \n\f\r\n\v";
335 absl::StripAsciiWhitespace(&str);
336 EXPECT_EQ("foo foo", str);
337
338 str = "\t \n\f\r\v\n\t \n\f\r\v\n";
339 absl::StripAsciiWhitespace(&str);
340 EXPECT_EQ(absl::string_view{}, str);
341 }
342
TEST(RemoveExtraAsciiWhitespace,InPlace)343 TEST(RemoveExtraAsciiWhitespace, InPlace) {
344 const char* inputs[] = {"No extra space",
345 " Leading whitespace",
346 "Trailing whitespace ",
347 " Leading and trailing ",
348 " Whitespace \t in\v middle ",
349 "'Eeeeep! \n Newlines!\n",
350 "nospaces",
351 "",
352 "\n\t a\t\n\nb \t\n"};
353
354 const char* outputs[] = {
355 "No extra space",
356 "Leading whitespace",
357 "Trailing whitespace",
358 "Leading and trailing",
359 "Whitespace in middle",
360 "'Eeeeep! Newlines!",
361 "nospaces",
362 "",
363 "a\nb",
364 };
365 const int NUM_TESTS = ABSL_ARRAYSIZE(inputs);
366
367 for (int i = 0; i < NUM_TESTS; i++) {
368 std::string s(inputs[i]);
369 absl::RemoveExtraAsciiWhitespace(&s);
370 EXPECT_EQ(outputs[i], s);
371 }
372 }
373
374 } // namespace
375