1/*
2 * Copyright 2012-present Facebook, Inc.
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#ifndef __STDC_FORMAT_MACROS
18#define __STDC_FORMAT_MACROS 1
19#endif
20
21#include <folly/String.h>
22#include <tuple>
23
24#include <cinttypes>
25#include <set>
26
27#include <boost/regex.hpp>
28
29#include <folly/FBVector.h>
30#include <folly/container/Array.h>
31#include <folly/portability/GTest.h>
32#include <folly/test/TestUtils.h>
33
34using namespace folly;
35using namespace std;
36
37TEST(StringPrintf, BasicTest) {
38 EXPECT_EQ("abc", stringPrintf("%s", "abc"));
39 EXPECT_EQ("abc", stringPrintf("%sbc", "a"));
40 EXPECT_EQ("abc", stringPrintf("a%sc", "b"));
41 EXPECT_EQ("abc", stringPrintf("ab%s", "c"));
42
43 EXPECT_EQ("abc", stringPrintf("abc"));
44}
45
46TEST(StringPrintf, NumericFormats) {
47 EXPECT_EQ("12", stringPrintf("%d", 12));
48 EXPECT_EQ("2000000000", stringPrintf("%ld", 2000000000UL));
49 EXPECT_EQ("2000000000", stringPrintf("%ld", 2000000000L));
50 EXPECT_EQ("-2000000000", stringPrintf("%ld", -2000000000L));
51 EXPECT_EQ("5000000000", stringPrintf("%lld", 5000000000ULL));
52 EXPECT_EQ("5000000000", stringPrintf("%lld", 5000000000LL));
53 EXPECT_EQ("-5000000000", stringPrintf("%lld", -5000000000LL));
54 EXPECT_EQ("-1", stringPrintf("%d", 0xffffffff));
55 EXPECT_EQ(
56 "-1",
57 stringPrintf("%" PRId64, static_cast<int64_t>(0xffffffffffffffffLL)));
58 EXPECT_EQ(
59 "-1",
60 stringPrintf("%" PRId64, static_cast<uint64_t>(0xffffffffffffffffULL)));
61
62 EXPECT_EQ("7.7", stringPrintf("%1.1f", 7.7));
63 EXPECT_EQ("7.7", stringPrintf("%1.1lf", 7.7));
64 EXPECT_EQ("7.70000000000000018", stringPrintf("%.17f", 7.7));
65 EXPECT_EQ("7.70000000000000018", stringPrintf("%.17lf", 7.7));
66}
67
68TEST(StringPrintf, Appending) {
69 string s;
70 stringAppendf(&s, "a%s", "b");
71 stringAppendf(&s, "%c", 'c');
72 EXPECT_EQ(s, "abc");
73 stringAppendf(&s, " %d", 123);
74 EXPECT_EQ(s, "abc 123");
75}
76
77void vprintfCheck(const char* expected, const char* fmt, ...) {
78 va_list apOrig;
79 va_start(apOrig, fmt);
80 SCOPE_EXIT {
81 va_end(apOrig);
82 };
83 va_list ap;
84 va_copy(ap, apOrig);
85 SCOPE_EXIT {
86 va_end(ap);
87 };
88
89 // Check both APIs for calling stringVPrintf()
90 EXPECT_EQ(expected, stringVPrintf(fmt, ap));
91 va_end(ap);
92 va_copy(ap, apOrig);
93
94 std::string out;
95 stringVPrintf(&out, fmt, ap);
96 va_end(ap);
97 va_copy(ap, apOrig);
98 EXPECT_EQ(expected, out);
99
100 // Check stringVAppendf() as well
101 std::string prefix = "foobar";
102 out = prefix;
103 EXPECT_EQ(prefix + expected, stringVAppendf(&out, fmt, ap));
104 va_end(ap);
105 va_copy(ap, apOrig);
106}
107
108void vprintfError(const char* fmt, ...) {
109 va_list ap;
110 va_start(ap, fmt);
111 SCOPE_EXIT {
112 va_end(ap);
113 };
114
115#ifdef HAVE_VSNPRINTF_ERRORS
116 // OSX's sprintf family does not return a negative number on a bad format
117 // string, but Linux does. It's unclear to me which behavior is more
118 // correct.
119 EXPECT_THROW({ stringVPrintf(fmt, ap); }, std::runtime_error);
120#endif
121}
122
123TEST(StringPrintf, VPrintf) {
124 vprintfCheck("foo", "%s", "foo");
125 vprintfCheck(
126 "long string requiring reallocation 1 2 3 0x12345678",
127 "%s %s %d %d %d %#x",
128 "long string",
129 "requiring reallocation",
130 1,
131 2,
132 3,
133 0x12345678);
134 vprintfError("bogus%", "foo");
135}
136
137TEST(StringPrintf, VariousSizes) {
138 // Test a wide variety of output sizes, making sure to cross the
139 // vsnprintf buffer boundary implementation detail.
140 for (int i = 0; i < 4096; ++i) {
141 string expected(i + 1, 'a');
142 expected = "X" + expected + "X";
143 string result = stringPrintf("%s", expected.c_str());
144 EXPECT_EQ(expected.size(), result.size());
145 EXPECT_EQ(expected, result);
146 }
147
148 // clang-format off
149 EXPECT_EQ("abc12345678910111213141516171819202122232425xyz",
150 stringPrintf("abc%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
151 "%d%d%d%d%d%d%d%d%d%d%dxyz",
152 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
153 17, 18, 19, 20, 21, 22, 23, 24, 25));
154 // clang-format on
155}
156
157TEST(StringPrintf, oldStringPrintfTests) {
158 EXPECT_EQ(string("a/b/c/d"), stringPrintf("%s/%s/%s/%s", "a", "b", "c", "d"));
159
160 EXPECT_EQ(string(" 5 10"), stringPrintf("%5d %5d", 5, 10));
161
162 // check printing w/ a big buffer
163 for (int size = (1 << 8); size <= (1 << 15); size <<= 1) {
164 string a(size, 'z');
165 string b = stringPrintf("%s", a.c_str());
166 EXPECT_EQ(a.size(), b.size());
167 }
168}
169
170TEST(StringPrintf, oldStringAppendf) {
171 string s = "hello";
172 stringAppendf(&s, "%s/%s/%s/%s", "a", "b", "c", "d");
173 EXPECT_EQ(string("helloa/b/c/d"), s);
174}
175
176TEST(Escape, cEscape) {
177 EXPECT_EQ("hello world", cEscape<std::string>("hello world"));
178 EXPECT_EQ(
179 "hello \\\\world\\\" goodbye",
180 cEscape<std::string>("hello \\world\" goodbye"));
181 EXPECT_EQ("hello\\nworld", cEscape<std::string>("hello\nworld"));
182 EXPECT_EQ("hello\\377\\376", cEscape<std::string>("hello\xff\xfe"));
183}
184
185TEST(Escape, cUnescape) {
186 EXPECT_EQ("hello world", cUnescape<std::string>("hello world"));
187 EXPECT_EQ(
188 "hello \\world\" goodbye",
189 cUnescape<std::string>("hello \\\\world\\\" goodbye"));
190 EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\nworld"));
191 EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\012world"));
192 EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\x0aworld"));
193 EXPECT_EQ("hello\xff\xfe", cUnescape<std::string>("hello\\377\\376"));
194 EXPECT_EQ("hello\xff\xfe", cUnescape<std::string>("hello\\xff\\xfe"));
195 EXPECT_EQ("hello\\", cUnescape<std::string>("hello\\", false));
196
197 EXPECT_THROW_RE(
198 cUnescape<std::string>("hello\\"),
199 std::invalid_argument,
200 "incomplete escape sequence");
201 EXPECT_THROW_RE(
202 cUnescape<std::string>("hello\\x"),
203 std::invalid_argument,
204 "incomplete hex escape sequence");
205 EXPECT_THROW_RE(
206 cUnescape<std::string>("hello\\q"),
207 std::invalid_argument,
208 "invalid escape sequence");
209}
210
211TEST(Escape, uriEscape) {
212 EXPECT_EQ("hello%2c%20%2fworld", uriEscape<std::string>("hello, /world"));
213 EXPECT_EQ(
214 "hello%2c%20/world",
215 uriEscape<std::string>("hello, /world", UriEscapeMode::PATH));
216 EXPECT_EQ(
217 "hello%2c+%2fworld",
218 uriEscape<std::string>("hello, /world", UriEscapeMode::QUERY));
219 EXPECT_EQ(
220 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~",
221 uriEscape<std::string>(
222 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~"));
223}
224
225TEST(Escape, uriUnescape) {
226 EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello, /world"));
227 EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello%2c%20%2fworld"));
228 EXPECT_EQ("hello,+/world", uriUnescape<std::string>("hello%2c+%2fworld"));
229 EXPECT_EQ(
230 "hello, /world",
231 uriUnescape<std::string>("hello%2c+%2fworld", UriEscapeMode::QUERY));
232 EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2f"));
233 EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2F"));
234 EXPECT_THROW({ uriUnescape<std::string>("hello%"); }, std::invalid_argument);
235 EXPECT_THROW({ uriUnescape<std::string>("hello%2"); }, std::invalid_argument);
236 EXPECT_THROW(
237 { uriUnescape<std::string>("hello%2g"); }, std::invalid_argument);
238}
239
240namespace {
241void expectPrintable(StringPiece s) {
242 for (char c : s) {
243 EXPECT_LE(32, c);
244 EXPECT_GE(127, c);
245 }
246}
247} // namespace
248
249TEST(Escape, uriEscapeAllCombinations) {
250 char c[3];
251 c[2] = '\0';
252 StringPiece in(c, 2);
253 fbstring tmp;
254 fbstring out;
255 for (int i = 0; i < 256; ++i) {
256 c[0] = i;
257 for (int j = 0; j < 256; ++j) {
258 c[1] = j;
259 tmp.clear();
260 out.clear();
261 uriEscape(in, tmp);
262 expectPrintable(tmp);
263 uriUnescape(tmp, out);
264 EXPECT_EQ(in, out);
265 }
266 }
267}
268
269namespace {
270bool isHex(int v) {
271 return (
272 (v >= '0' && v <= '9') || (v >= 'A' && v <= 'F') ||
273 (v >= 'a' && v <= 'f'));
274}
275} // namespace
276
277TEST(Escape, uriUnescapePercentDecoding) {
278 char c[4] = {'%', '\0', '\0', '\0'};
279 StringPiece in(c, 3);
280 fbstring out;
281 unsigned int expected = 0;
282 for (int i = 0; i < 256; ++i) {
283 c[1] = i;
284 for (int j = 0; j < 256; ++j) {
285 c[2] = j;
286 if (isHex(i) && isHex(j)) {
287 out.clear();
288 uriUnescape(in, out);
289 EXPECT_EQ(1, out.size());
290 EXPECT_EQ(1, sscanf(c + 1, "%x", &expected));
291 unsigned char v = out[0];
292 EXPECT_EQ(expected, v);
293 } else {
294 EXPECT_THROW({ uriUnescape(in, out); }, std::invalid_argument);
295 }
296 }
297 }
298}
299
300namespace {
301
302double pow2(int exponent) {
303 return double(int64_t(1) << exponent);
304}
305
306} // namespace
307
308struct PrettyTestCase {
309 std::string prettyString;
310 double realValue;
311 PrettyType prettyType;
312};
313
314PrettyTestCase prettyTestCases[] = {
315 {string("853 ms"), 85.3e-2, PRETTY_TIME_HMS},
316 {string("8.53 s "), 85.3e-1, PRETTY_TIME_HMS},
317 {string("1.422 m "), 85.3, PRETTY_TIME_HMS},
318 {string("14.22 m "), 85.3e1, PRETTY_TIME_HMS},
319 {string("2.369 h "), 85.3e2, PRETTY_TIME_HMS},
320 {string("2.369e+04 h "), 85.3e6, PRETTY_TIME_HMS},
321
322 {string("8.53e+07 s "), 85.3e6, PRETTY_TIME},
323 {string("8.53e+07 s "), 85.3e6, PRETTY_TIME},
324 {string("85.3 ms"), 85.3e-3, PRETTY_TIME},
325 {string("85.3 us"), 85.3e-6, PRETTY_TIME},
326 {string("85.3 ns"), 85.3e-9, PRETTY_TIME},
327 {string("85.3 ps"), 85.3e-12, PRETTY_TIME},
328 {string("8.53e-14 s "), 85.3e-15, PRETTY_TIME},
329
330 {string("0 s "), 0, PRETTY_TIME},
331 {string("1 s "), 1.0, PRETTY_TIME},
332 {string("1 ms"), 1.0e-3, PRETTY_TIME},
333 {string("1 us"), 1.0e-6, PRETTY_TIME},
334 {string("1 ns"), 1.0e-9, PRETTY_TIME},
335 {string("1 ps"), 1.0e-12, PRETTY_TIME},
336
337 // check bytes printing
338 {string("853 B "), 853., PRETTY_BYTES},
339 {string("833 kB"), 853.e3, PRETTY_BYTES},
340 {string("813.5 MB"), 853.e6, PRETTY_BYTES},
341 {string("7.944 GB"), 8.53e9, PRETTY_BYTES},
342 {string("794.4 GB"), 853.e9, PRETTY_BYTES},
343 {string("775.8 TB"), 853.e12, PRETTY_BYTES},
344
345 {string("0 B "), 0, PRETTY_BYTES},
346 {string("1 B "), pow2(0), PRETTY_BYTES},
347 {string("1 kB"), pow2(10), PRETTY_BYTES},
348 {string("1 MB"), pow2(20), PRETTY_BYTES},
349 {string("1 GB"), pow2(30), PRETTY_BYTES},
350 {string("1 TB"), pow2(40), PRETTY_BYTES},
351 {string("1 PB"), pow2(50), PRETTY_BYTES},
352 {string("1 EB"), pow2(60), PRETTY_BYTES},
353
354 {string("853 B "), 853., PRETTY_BYTES_IEC},
355 {string("833 KiB"), 853.e3, PRETTY_BYTES_IEC},
356 {string("813.5 MiB"), 853.e6, PRETTY_BYTES_IEC},
357 {string("7.944 GiB"), 8.53e9, PRETTY_BYTES_IEC},
358 {string("794.4 GiB"), 853.e9, PRETTY_BYTES_IEC},
359 {string("775.8 TiB"), 853.e12, PRETTY_BYTES_IEC},
360 {string("1.776 PiB"), 2e15, PRETTY_BYTES_IEC},
361 {string("1.735 EiB"), 2e18, PRETTY_BYTES_IEC},
362
363 {string("0 B "), 0, PRETTY_BYTES_IEC},
364 {string("1 B "), pow2(0), PRETTY_BYTES_IEC},
365 {string("1 KiB"), pow2(10), PRETTY_BYTES_IEC},
366 {string("1 MiB"), pow2(20), PRETTY_BYTES_IEC},
367 {string("1 GiB"), pow2(30), PRETTY_BYTES_IEC},
368 {string("1 TiB"), pow2(40), PRETTY_BYTES_IEC},
369 {string("1 PiB"), pow2(50), PRETTY_BYTES_IEC},
370 {string("1 EiB"), pow2(60), PRETTY_BYTES_IEC},
371
372 // check bytes metric printing
373 {string("853 B "), 853., PRETTY_BYTES_METRIC},
374 {string("853 kB"), 853.e3, PRETTY_BYTES_METRIC},
375 {string("853 MB"), 853.e6, PRETTY_BYTES_METRIC},
376 {string("8.53 GB"), 8.53e9, PRETTY_BYTES_METRIC},
377 {string("853 GB"), 853.e9, PRETTY_BYTES_METRIC},
378 {string("853 TB"), 853.e12, PRETTY_BYTES_METRIC},
379
380 {string("0 B "), 0, PRETTY_BYTES_METRIC},
381 {string("1 B "), 1.0, PRETTY_BYTES_METRIC},
382 {string("1 kB"), 1.0e+3, PRETTY_BYTES_METRIC},
383 {string("1 MB"), 1.0e+6, PRETTY_BYTES_METRIC},
384 {string("1 GB"), 1.0e+9, PRETTY_BYTES_METRIC},
385 {string("1 TB"), 1.0e+12, PRETTY_BYTES_METRIC},
386 {string("1 PB"), 1.0e+15, PRETTY_BYTES_METRIC},
387 {string("1 EB"), 1.0e+18, PRETTY_BYTES_METRIC},
388
389 // check metric-units (powers of 1000) printing
390 {string("853 "), 853., PRETTY_UNITS_METRIC},
391 {string("853 k"), 853.e3, PRETTY_UNITS_METRIC},
392 {string("853 M"), 853.e6, PRETTY_UNITS_METRIC},
393 {string("8.53 bil"), 8.53e9, PRETTY_UNITS_METRIC},
394 {string("853 bil"), 853.e9, PRETTY_UNITS_METRIC},
395 {string("853 tril"), 853.e12, PRETTY_UNITS_METRIC},
396
397 // check binary-units (powers of 1024) printing
398 {string("0 "), 0, PRETTY_UNITS_BINARY},
399 {string("1 "), pow2(0), PRETTY_UNITS_BINARY},
400 {string("1 k"), pow2(10), PRETTY_UNITS_BINARY},
401 {string("1 M"), pow2(20), PRETTY_UNITS_BINARY},
402 {string("1 G"), pow2(30), PRETTY_UNITS_BINARY},
403 {string("1 T"), pow2(40), PRETTY_UNITS_BINARY},
404
405 {string("1023 "), pow2(10) - 1, PRETTY_UNITS_BINARY},
406 {string("1024 k"), pow2(20) - 1, PRETTY_UNITS_BINARY},
407 {string("1024 M"), pow2(30) - 1, PRETTY_UNITS_BINARY},
408 {string("1024 G"), pow2(40) - 1, PRETTY_UNITS_BINARY},
409
410 {string("0 "), 0, PRETTY_UNITS_BINARY_IEC},
411 {string("1 "), pow2(0), PRETTY_UNITS_BINARY_IEC},
412 {string("1 Ki"), pow2(10), PRETTY_UNITS_BINARY_IEC},
413 {string("1 Mi"), pow2(20), PRETTY_UNITS_BINARY_IEC},
414 {string("1 Gi"), pow2(30), PRETTY_UNITS_BINARY_IEC},
415 {string("1 Ti"), pow2(40), PRETTY_UNITS_BINARY_IEC},
416
417 {string("1023 "), pow2(10) - 1, PRETTY_UNITS_BINARY_IEC},
418 {string("1024 Ki"), pow2(20) - 1, PRETTY_UNITS_BINARY_IEC},
419 {string("1024 Mi"), pow2(30) - 1, PRETTY_UNITS_BINARY_IEC},
420 {string("1024 Gi"), pow2(40) - 1, PRETTY_UNITS_BINARY_IEC},
421
422 // check border SI cases
423
424 {string("1 Y"), 1e24, PRETTY_SI},
425 {string("10 Y"), 1e25, PRETTY_SI},
426 {string("1 y"), 1e-24, PRETTY_SI},
427 {string("10 y"), 1e-23, PRETTY_SI},
428
429 // check that negative values work
430 {string("-85.3 s "), -85.3, PRETTY_TIME},
431 {string("-85.3 ms"), -85.3e-3, PRETTY_TIME},
432 {string("-85.3 us"), -85.3e-6, PRETTY_TIME},
433 {string("-85.3 ns"), -85.3e-9, PRETTY_TIME},
434
435 // end of test
436 {string("endoftest"), 0, PRETTY_NUM_TYPES},
437};
438
439TEST(PrettyPrint, Basic) {
440 for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i) {
441 const PrettyTestCase& prettyTest = prettyTestCases[i];
442 EXPECT_EQ(
443 prettyTest.prettyString,
444 prettyPrint(prettyTest.realValue, prettyTest.prettyType));
445 }
446}
447
448TEST(PrettyToDouble, Basic) {
449 // check manually created tests
450 for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i) {
451 PrettyTestCase testCase = prettyTestCases[i];
452 PrettyType formatType = testCase.prettyType;
453 double x = testCase.realValue;
454 std::string testString = testCase.prettyString;
455 double recoveredX = 0;
456 try {
457 recoveredX = prettyToDouble(testString, formatType);
458 } catch (const std::exception& ex) {
459 ADD_FAILURE() << testCase.prettyString << " -> " << ex.what();
460 }
461 double relativeError =
462 fabs(x) < 1e-5 ? (x - recoveredX) : (x - recoveredX) / x;
463 EXPECT_NEAR(0, relativeError, 1e-3);
464 }
465
466 // checks for compatibility with prettyPrint over the whole parameter space
467 for (int i = 0; i < PRETTY_NUM_TYPES; ++i) {
468 PrettyType formatType = static_cast<PrettyType>(i);
469 for (double x = 1e-18; x < 1e40; x *= 1.9) {
470 bool addSpace = static_cast<PrettyType>(i) == PRETTY_SI;
471 for (int it = 0; it < 2; ++it, addSpace = true) {
472 double recoveredX = 0;
473 try {
474 recoveredX =
475 prettyToDouble(prettyPrint(x, formatType, addSpace), formatType);
476 } catch (const std::exception& ex) {
477 ADD_FAILURE() << folly::exceptionStr(ex);
478 }
479 double relativeError = (x - recoveredX) / x;
480 EXPECT_NEAR(0, relativeError, 1e-3);
481 }
482 }
483 }
484
485 // check for incorrect values
486 EXPECT_THROW(prettyToDouble("10Mx", PRETTY_SI), std::range_error);
487 EXPECT_THROW(prettyToDouble("10 Mx", PRETTY_SI), std::range_error);
488 EXPECT_THROW(prettyToDouble("10 M x", PRETTY_SI), std::range_error);
489
490 StringPiece testString = "10Mx";
491 EXPECT_DOUBLE_EQ(prettyToDouble(&testString, PRETTY_UNITS_METRIC), 10e6);
492 EXPECT_EQ(testString, "x");
493}
494
495TEST(PrettyPrint, HexDump) {
496 std::string a("abc\x00\x02\xa0", 6); // embedded NUL
497 EXPECT_EQ(
498 "00000000 61 62 63 00 02 a0 "
499 "|abc... |\n",
500 hexDump(a.data(), a.size()));
501
502 a = "abcdefghijklmnopqrstuvwxyz";
503 EXPECT_EQ(
504 "00000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 "
505 "|abcdefghijklmnop|\n"
506 "00000010 71 72 73 74 75 76 77 78 79 7a "
507 "|qrstuvwxyz |\n",
508 hexDump(a.data(), a.size()));
509}
510
511TEST(System, errnoStr) {
512 errno = EACCES;
513 EXPECT_EQ(EACCES, errno);
514 EXPECT_EQ(EACCES, errno); // twice to make sure EXPECT_EQ doesn't change it
515
516 fbstring expected = strerror(ENOENT);
517
518 errno = EACCES;
519 EXPECT_EQ(expected, errnoStr(ENOENT));
520 // Ensure that errno isn't changed
521 EXPECT_EQ(EACCES, errno);
522
523 // Per POSIX, all errno values are positive, so -1 is invalid
524 errnoStr(-1);
525
526 // Ensure that errno isn't changed
527 EXPECT_EQ(EACCES, errno);
528}
529
530namespace {
531
532template <template <class, class> class VectorType>
533void splitTest() {
534 VectorType<string, std::allocator<string>> parts;
535
536 folly::split(',', "a,b,c", parts);
537 EXPECT_EQ(parts.size(), 3);
538 EXPECT_EQ(parts[0], "a");
539 EXPECT_EQ(parts[1], "b");
540 EXPECT_EQ(parts[2], "c");
541 parts.clear();
542
543 folly::split(',', StringPiece("a,b,c"), parts);
544 EXPECT_EQ(parts.size(), 3);
545 EXPECT_EQ(parts[0], "a");
546 EXPECT_EQ(parts[1], "b");
547 EXPECT_EQ(parts[2], "c");
548 parts.clear();
549
550 folly::split(',', string("a,b,c"), parts);
551 EXPECT_EQ(parts.size(), 3);
552 EXPECT_EQ(parts[0], "a");
553 EXPECT_EQ(parts[1], "b");
554 EXPECT_EQ(parts[2], "c");
555 parts.clear();
556
557 folly::split(',', "a,,c", parts);
558 EXPECT_EQ(parts.size(), 3);
559 EXPECT_EQ(parts[0], "a");
560 EXPECT_EQ(parts[1], "");
561 EXPECT_EQ(parts[2], "c");
562 parts.clear();
563
564 folly::split(',', string("a,,c"), parts);
565 EXPECT_EQ(parts.size(), 3);
566 EXPECT_EQ(parts[0], "a");
567 EXPECT_EQ(parts[1], "");
568 EXPECT_EQ(parts[2], "c");
569 parts.clear();
570
571 folly::split(',', "a,,c", parts, true);
572 EXPECT_EQ(parts.size(), 2);
573 EXPECT_EQ(parts[0], "a");
574 EXPECT_EQ(parts[1], "c");
575 parts.clear();
576
577 folly::split(',', string("a,,c"), parts, true);
578 EXPECT_EQ(parts.size(), 2);
579 EXPECT_EQ(parts[0], "a");
580 EXPECT_EQ(parts[1], "c");
581 parts.clear();
582
583 folly::split(',', string(",,a,,c,,,"), parts, true);
584 EXPECT_EQ(parts.size(), 2);
585 EXPECT_EQ(parts[0], "a");
586 EXPECT_EQ(parts[1], "c");
587 parts.clear();
588
589 // test multiple split w/o clear
590 folly::split(',', ",,a,,c,,,", parts, true);
591 EXPECT_EQ(parts.size(), 2);
592 EXPECT_EQ(parts[0], "a");
593 EXPECT_EQ(parts[1], "c");
594 folly::split(',', ",,a,,c,,,", parts, true);
595 EXPECT_EQ(parts.size(), 4);
596 EXPECT_EQ(parts[2], "a");
597 EXPECT_EQ(parts[3], "c");
598 parts.clear();
599
600 // test splits that with multi-line delimiter
601 folly::split("ab", "dabcabkdbkab", parts, true);
602 EXPECT_EQ(parts.size(), 3);
603 EXPECT_EQ(parts[0], "d");
604 EXPECT_EQ(parts[1], "c");
605 EXPECT_EQ(parts[2], "kdbk");
606 parts.clear();
607
608 // test last part is shorter than the delimiter
609 folly::split("bc", "abcd", parts, true);
610 EXPECT_EQ(parts.size(), 2);
611 EXPECT_EQ(parts[0], "a");
612 EXPECT_EQ(parts[1], "d");
613 parts.clear();
614
615 string orig = "ab2342asdfv~~!";
616 folly::split("", orig, parts, true);
617 EXPECT_EQ(parts.size(), 1);
618 EXPECT_EQ(parts[0], orig);
619 parts.clear();
620
621 folly::split("452x;o38asfsajsdlfdf.j", "asfds", parts, true);
622 EXPECT_EQ(parts.size(), 1);
623 EXPECT_EQ(parts[0], "asfds");
624 parts.clear();
625
626 folly::split("a", "", parts, true);
627 EXPECT_EQ(parts.size(), 0);
628 parts.clear();
629
630 folly::split("a", "", parts);
631 EXPECT_EQ(parts.size(), 1);
632 EXPECT_EQ(parts[0], "");
633 parts.clear();
634
635 folly::split("a", StringPiece(), parts, true);
636 EXPECT_EQ(parts.size(), 0);
637 parts.clear();
638
639 folly::split("a", StringPiece(), parts);
640 EXPECT_EQ(parts.size(), 1);
641 EXPECT_EQ(parts[0], "");
642 parts.clear();
643
644 folly::split("a", "abcdefg", parts, true);
645 EXPECT_EQ(parts.size(), 1);
646 EXPECT_EQ(parts[0], "bcdefg");
647 parts.clear();
648
649 orig = "All, , your base, are , , belong to us";
650 folly::split(", ", orig, parts, true);
651 EXPECT_EQ(parts.size(), 4);
652 EXPECT_EQ(parts[0], "All");
653 EXPECT_EQ(parts[1], "your base");
654 EXPECT_EQ(parts[2], "are ");
655 EXPECT_EQ(parts[3], "belong to us");
656 parts.clear();
657 folly::split(", ", orig, parts);
658 EXPECT_EQ(parts.size(), 6);
659 EXPECT_EQ(parts[0], "All");
660 EXPECT_EQ(parts[1], "");
661 EXPECT_EQ(parts[2], "your base");
662 EXPECT_EQ(parts[3], "are ");
663 EXPECT_EQ(parts[4], "");
664 EXPECT_EQ(parts[5], "belong to us");
665 parts.clear();
666
667 orig = ", Facebook, rul,es!, ";
668 folly::split(", ", orig, parts, true);
669 EXPECT_EQ(parts.size(), 2);
670 EXPECT_EQ(parts[0], "Facebook");
671 EXPECT_EQ(parts[1], "rul,es!");
672 parts.clear();
673 folly::split(", ", orig, parts);
674 EXPECT_EQ(parts.size(), 4);
675 EXPECT_EQ(parts[0], "");
676 EXPECT_EQ(parts[1], "Facebook");
677 EXPECT_EQ(parts[2], "rul,es!");
678 EXPECT_EQ(parts[3], "");
679}
680
681template <template <class, class> class VectorType>
682void piecesTest() {
683 VectorType<StringPiece, std::allocator<StringPiece>> pieces;
684 VectorType<StringPiece, std::allocator<StringPiece>> pieces2;
685
686 folly::split(',', "a,b,c", pieces);
687 EXPECT_EQ(pieces.size(), 3);
688 EXPECT_EQ(pieces[0], "a");
689 EXPECT_EQ(pieces[1], "b");
690 EXPECT_EQ(pieces[2], "c");
691
692 pieces.clear();
693
694 folly::split(',', "a,,c", pieces);
695 EXPECT_EQ(pieces.size(), 3);
696 EXPECT_EQ(pieces[0], "a");
697 EXPECT_EQ(pieces[1], "");
698 EXPECT_EQ(pieces[2], "c");
699 pieces.clear();
700
701 folly::split(',', "a,,c", pieces, true);
702 EXPECT_EQ(pieces.size(), 2);
703 EXPECT_EQ(pieces[0], "a");
704 EXPECT_EQ(pieces[1], "c");
705 pieces.clear();
706
707 folly::split(',', ",,a,,c,,,", pieces, true);
708 EXPECT_EQ(pieces.size(), 2);
709 EXPECT_EQ(pieces[0], "a");
710 EXPECT_EQ(pieces[1], "c");
711 pieces.clear();
712
713 // test multiple split w/o clear
714 folly::split(',', ",,a,,c,,,", pieces, true);
715 EXPECT_EQ(pieces.size(), 2);
716 EXPECT_EQ(pieces[0], "a");
717 EXPECT_EQ(pieces[1], "c");
718 folly::split(',', ",,a,,c,,,", pieces, true);
719 EXPECT_EQ(pieces.size(), 4);
720 EXPECT_EQ(pieces[2], "a");
721 EXPECT_EQ(pieces[3], "c");
722 pieces.clear();
723
724 // test multiple split rounds
725 folly::split(",", "a_b,c_d", pieces);
726 EXPECT_EQ(pieces.size(), 2);
727 EXPECT_EQ(pieces[0], "a_b");
728 EXPECT_EQ(pieces[1], "c_d");
729 folly::split("_", pieces[0], pieces2);
730 EXPECT_EQ(pieces2.size(), 2);
731 EXPECT_EQ(pieces2[0], "a");
732 EXPECT_EQ(pieces2[1], "b");
733 pieces2.clear();
734 folly::split("_", pieces[1], pieces2);
735 EXPECT_EQ(pieces2.size(), 2);
736 EXPECT_EQ(pieces2[0], "c");
737 EXPECT_EQ(pieces2[1], "d");
738 pieces.clear();
739 pieces2.clear();
740
741 // test splits that with multi-line delimiter
742 folly::split("ab", "dabcabkdbkab", pieces, true);
743 EXPECT_EQ(pieces.size(), 3);
744 EXPECT_EQ(pieces[0], "d");
745 EXPECT_EQ(pieces[1], "c");
746 EXPECT_EQ(pieces[2], "kdbk");
747 pieces.clear();
748
749 string orig = "ab2342asdfv~~!";
750 folly::split("", orig.c_str(), pieces, true);
751 EXPECT_EQ(pieces.size(), 1);
752 EXPECT_EQ(pieces[0], orig);
753 pieces.clear();
754
755 folly::split("452x;o38asfsajsdlfdf.j", "asfds", pieces, true);
756 EXPECT_EQ(pieces.size(), 1);
757 EXPECT_EQ(pieces[0], "asfds");
758 pieces.clear();
759
760 folly::split("a", "", pieces, true);
761 EXPECT_EQ(pieces.size(), 0);
762 pieces.clear();
763
764 folly::split("a", "", pieces);
765 EXPECT_EQ(pieces.size(), 1);
766 EXPECT_EQ(pieces[0], "");
767 pieces.clear();
768
769 folly::split("a", "abcdefg", pieces, true);
770 EXPECT_EQ(pieces.size(), 1);
771 EXPECT_EQ(pieces[0], "bcdefg");
772 pieces.clear();
773
774 orig = "All, , your base, are , , belong to us";
775 folly::split(", ", orig, pieces, true);
776 EXPECT_EQ(pieces.size(), 4);
777 EXPECT_EQ(pieces[0], "All");
778 EXPECT_EQ(pieces[1], "your base");
779 EXPECT_EQ(pieces[2], "are ");
780 EXPECT_EQ(pieces[3], "belong to us");
781 pieces.clear();
782 folly::split(", ", orig, pieces);
783 EXPECT_EQ(pieces.size(), 6);
784 EXPECT_EQ(pieces[0], "All");
785 EXPECT_EQ(pieces[1], "");
786 EXPECT_EQ(pieces[2], "your base");
787 EXPECT_EQ(pieces[3], "are ");
788 EXPECT_EQ(pieces[4], "");
789 EXPECT_EQ(pieces[5], "belong to us");
790 pieces.clear();
791
792 orig = ", Facebook, rul,es!, ";
793 folly::split(", ", orig, pieces, true);
794 EXPECT_EQ(pieces.size(), 2);
795 EXPECT_EQ(pieces[0], "Facebook");
796 EXPECT_EQ(pieces[1], "rul,es!");
797 pieces.clear();
798 folly::split(", ", orig, pieces);
799 EXPECT_EQ(pieces.size(), 4);
800 EXPECT_EQ(pieces[0], "");
801 EXPECT_EQ(pieces[1], "Facebook");
802 EXPECT_EQ(pieces[2], "rul,es!");
803 EXPECT_EQ(pieces[3], "");
804 pieces.clear();
805
806 const char* str = "a,b";
807 folly::split(',', StringPiece(str), pieces);
808 EXPECT_EQ(pieces.size(), 2);
809 EXPECT_EQ(pieces[0], "a");
810 EXPECT_EQ(pieces[1], "b");
811 EXPECT_EQ(pieces[0].start(), str);
812 EXPECT_EQ(pieces[1].start(), str + 2);
813
814 std::set<StringPiece> unique;
815 folly::splitTo<StringPiece>(
816 ":",
817 "asd:bsd:asd:asd:bsd:csd::asd",
818 std::inserter(unique, unique.begin()),
819 true);
820 EXPECT_EQ(unique.size(), 3);
821 if (unique.size() == 3) {
822 EXPECT_EQ(*unique.begin(), "asd");
823 EXPECT_EQ(*--unique.end(), "csd");
824 }
825
826 VectorType<fbstring, std::allocator<fbstring>> blah;
827 folly::split('-', "a-b-c-d-f-e", blah);
828 EXPECT_EQ(blah.size(), 6);
829}
830
831} // namespace
832
833TEST(Split, split_vector) {
834 splitTest<std::vector>();
835}
836TEST(Split, split_fbvector) {
837 splitTest<folly::fbvector>();
838}
839TEST(Split, pieces_vector) {
840 piecesTest<std::vector>();
841}
842TEST(Split, pieces_fbvector) {
843 piecesTest<folly::fbvector>();
844}
845
846TEST(Split, fixed) {
847 StringPiece a, b, c, d;
848
849 EXPECT_TRUE(folly::split<false>('.', "a.b.c.d", a, b, c, d));
850 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
851 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
852 EXPECT_TRUE(folly::split<false>('.', "a", a));
853
854 EXPECT_TRUE(folly::split('.', "a.b.c.d", a, b, c, d));
855 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
856 EXPECT_TRUE(folly::split('.', "a.b", a, b));
857 EXPECT_TRUE(folly::split('.', "a", a));
858
859 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
860 EXPECT_EQ("a", a);
861 EXPECT_EQ("b", b);
862 EXPECT_EQ("c", c);
863 EXPECT_FALSE(folly::split<false>('.', "a.b", a, b, c));
864 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b));
865 EXPECT_EQ("a", a);
866 EXPECT_EQ("b.c", b);
867
868 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
869 EXPECT_EQ("a", a);
870 EXPECT_EQ("b", b);
871 EXPECT_EQ("c", c);
872 EXPECT_FALSE(folly::split('.', "a.b.c", a, b));
873 EXPECT_FALSE(folly::split('.', "a.b", a, b, c));
874
875 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
876 EXPECT_EQ("a", a);
877 EXPECT_EQ("b", b);
878 EXPECT_FALSE(folly::split<false>('.', "a", a, b));
879 EXPECT_TRUE(folly::split<false>('.', "a.b", a));
880 EXPECT_EQ("a.b", a);
881
882 EXPECT_TRUE(folly::split('.', "a.b", a, b));
883 EXPECT_EQ("a", a);
884 EXPECT_EQ("b", b);
885 EXPECT_FALSE(folly::split('.', "a", a, b));
886 EXPECT_FALSE(folly::split('.', "a.b", a));
887}
888
889TEST(Split, std_string_fixed) {
890 std::string a, b, c, d;
891
892 EXPECT_TRUE(folly::split<false>('.', "a.b.c.d", a, b, c, d));
893 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
894 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
895 EXPECT_TRUE(folly::split<false>('.', "a", a));
896
897 EXPECT_TRUE(folly::split('.', "a.b.c.d", a, b, c, d));
898 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
899 EXPECT_TRUE(folly::split('.', "a.b", a, b));
900 EXPECT_TRUE(folly::split('.', "a", a));
901
902 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
903 EXPECT_EQ("a", a);
904 EXPECT_EQ("b", b);
905 EXPECT_EQ("c", c);
906 EXPECT_FALSE(folly::split<false>('.', "a.b", a, b, c));
907 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b));
908 EXPECT_EQ("a", a);
909 EXPECT_EQ("b.c", b);
910
911 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
912 EXPECT_EQ("a", a);
913 EXPECT_EQ("b", b);
914 EXPECT_EQ("c", c);
915 EXPECT_FALSE(folly::split('.', "a.b.c", a, b));
916 EXPECT_FALSE(folly::split('.', "a.b", a, b, c));
917
918 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
919 EXPECT_EQ("a", a);
920 EXPECT_EQ("b", b);
921 EXPECT_FALSE(folly::split<false>('.', "a", a, b));
922 EXPECT_TRUE(folly::split<false>('.', "a.b", a));
923 EXPECT_EQ("a.b", a);
924
925 EXPECT_TRUE(folly::split('.', "a.b", a, b));
926 EXPECT_EQ("a", a);
927 EXPECT_EQ("b", b);
928 EXPECT_FALSE(folly::split('.', "a", a, b));
929 EXPECT_FALSE(folly::split('.', "a.b", a));
930}
931
932TEST(Split, fixed_convert) {
933 StringPiece a, d;
934 int b;
935 double c = 0;
936
937 EXPECT_TRUE(folly::split(':', "a:13:14.7:b", a, b, c, d));
938 EXPECT_EQ("a", a);
939 EXPECT_EQ(13, b);
940 EXPECT_NEAR(14.7, c, 1e-10);
941 EXPECT_EQ("b", d);
942
943 EXPECT_TRUE(folly::split<false>(':', "b:14:15.3:c", a, b, c, d));
944 EXPECT_EQ("b", a);
945 EXPECT_EQ(14, b);
946 EXPECT_NEAR(15.3, c, 1e-10);
947 EXPECT_EQ("c", d);
948
949 EXPECT_FALSE(folly::split(':', "a:13:14.7:b", a, b, d));
950
951 EXPECT_TRUE(folly::split<false>(':', "a:13:14.7:b", a, b, d));
952 EXPECT_EQ("a", a);
953 EXPECT_EQ(13, b);
954 EXPECT_EQ("14.7:b", d);
955
956 // Enable verifying that a line only contains one field
957 EXPECT_TRUE(folly::split(' ', "hello", a));
958 EXPECT_FALSE(folly::split(' ', "hello world", a));
959
960 // Test cases with std::ignore.
961 EXPECT_TRUE(folly::split(':', "a:13:14.7:b", std::ignore, b, c, d));
962 EXPECT_EQ(13, b);
963 EXPECT_NEAR(14.7, c, 1e-10);
964 EXPECT_EQ("b", d);
965
966 EXPECT_TRUE(folly::split(':', "a:13:14.7:b", std::ignore, b, c, std::ignore));
967 EXPECT_EQ(13, b);
968 EXPECT_NEAR(14.7, c, 1e-10);
969
970 EXPECT_TRUE(folly::split<false>(':', "a:13:14.7:b", a, b, std::ignore));
971 EXPECT_EQ("a", a);
972 EXPECT_EQ(13, b);
973
974 EXPECT_FALSE(folly::split<false>(':', "a:13", std::ignore, b, std::ignore));
975 EXPECT_TRUE(folly::split<false>(':', ":13:", std::ignore, b, std::ignore));
976 EXPECT_EQ(13, b);
977}
978
979namespace my {
980
981enum class Color {
982 Red,
983 Blue,
984};
985
986enum class ColorErrorCode { INVALID_COLOR };
987
988struct ColorError : std::runtime_error {
989 using std::runtime_error::runtime_error;
990};
991
992ColorError makeConversionError(ColorErrorCode, StringPiece sp) {
993 return ColorError("Invalid my::Color representation : " + sp.str());
994}
995
996Expected<StringPiece, ColorErrorCode> parseTo(
997 StringPiece in,
998 Color& out) noexcept {
999 if (in == "R") {
1000 out = Color::Red;
1001 } else if (in == "B") {
1002 out = Color::Blue;
1003 } else {
1004 return makeUnexpected(ColorErrorCode::INVALID_COLOR);
1005 }
1006 return StringPiece(in.end(), in.end());
1007}
1008} // namespace my
1009
1010TEST(Split, fixed_convert_custom) {
1011 my::Color c1, c2;
1012
1013 EXPECT_TRUE(folly::split(',', "R,B", c1, c2));
1014 EXPECT_EQ(c1, my::Color::Red);
1015 EXPECT_EQ(c2, my::Color::Blue);
1016
1017 EXPECT_THROW(folly::split(',', "B,G", c1, c2), my::ColorError);
1018}
1019
1020TEST(String, join) {
1021 string output;
1022
1023 std::vector<int> empty = {};
1024 join(":", empty, output);
1025 EXPECT_TRUE(output.empty());
1026
1027 std::vector<std::string> input1 = {"1", "23", "456", ""};
1028 join(':', input1, output);
1029 EXPECT_EQ(output, "1:23:456:");
1030 output = join(':', input1);
1031 EXPECT_EQ(output, "1:23:456:");
1032
1033 auto input2 = {1, 23, 456};
1034 join("-*-", input2, output);
1035 EXPECT_EQ(output, "1-*-23-*-456");
1036 output = join("-*-", input2);
1037 EXPECT_EQ(output, "1-*-23-*-456");
1038
1039 auto input3 = {'f', 'a', 'c', 'e', 'b', 'o', 'o', 'k'};
1040 join("", input3, output);
1041 EXPECT_EQ(output, "facebook");
1042
1043 join("_", {"", "f", "a", "c", "e", "b", "o", "o", "k", ""}, output);
1044 EXPECT_EQ(output, "_f_a_c_e_b_o_o_k_");
1045
1046 output = join("", input3.begin(), input3.end());
1047 EXPECT_EQ(output, "facebook");
1048
1049 std::multiset<char> input4(input3);
1050 output = join("", input4);
1051 EXPECT_EQ("abcefkoo", output);
1052 output = join("", input4.begin(), input4.end());
1053 EXPECT_EQ("abcefkoo", output);
1054}
1055
1056TEST(String, hexlify) {
1057 string input1 = "0123";
1058 string output1;
1059 EXPECT_TRUE(hexlify(input1, output1));
1060 EXPECT_EQ("30313233", output1);
1061
1062 fbstring input2 = "abcdefg";
1063 input2[1] = 0;
1064 input2[3] = 0xff;
1065 input2[5] = 0xb6;
1066 fbstring output2;
1067 EXPECT_TRUE(hexlify(input2, output2));
1068 EXPECT_EQ("610063ff65b667", output2);
1069
1070 EXPECT_EQ("666f6f626172", hexlify("foobar"));
1071 auto bytes = folly::make_array<uint8_t>(1, 2, 3, 4);
1072 EXPECT_EQ("01020304", hexlify(ByteRange{bytes.data(), bytes.size()}));
1073}
1074
1075TEST(String, unhexlify) {
1076 string input1 = "30313233";
1077 string output1;
1078 EXPECT_TRUE(unhexlify(input1, output1));
1079 EXPECT_EQ(output1, "0123");
1080
1081 fbstring input2 = "610063ff65b667";
1082 fbstring output2;
1083 EXPECT_TRUE(unhexlify(input2, output2));
1084 EXPECT_EQ(output2.size(), 7);
1085 EXPECT_EQ(output2[0], 'a');
1086 EXPECT_EQ(output2[1], 0);
1087 EXPECT_EQ(output2[2], 'c');
1088 EXPECT_EQ(output2[3] & 0xff, 0xff);
1089 EXPECT_EQ(output2[4], 'e');
1090 EXPECT_EQ(output2[5] & 0xff, 0xb6);
1091 EXPECT_EQ(output2[6], 'g');
1092
1093 string input3 = "x";
1094 string output3;
1095 EXPECT_FALSE(unhexlify(input3, output3));
1096
1097 string input4 = "xy";
1098 string output4;
1099 EXPECT_FALSE(unhexlify(input4, output4));
1100
1101 EXPECT_EQ("foobar", unhexlify("666f6f626172"));
1102 EXPECT_EQ(StringPiece("foo\0bar", 7), unhexlify("666f6f00626172"));
1103 EXPECT_THROW(unhexlify("666f6fzz626172"), std::domain_error);
1104}
1105
1106TEST(String, backslashify) {
1107 EXPECT_EQ("abc", string("abc"));
1108 EXPECT_EQ("abc", backslashify(string("abc")));
1109 EXPECT_EQ("abc\\r", backslashify(string("abc\r")));
1110 EXPECT_EQ("abc\\x0d", backslashify(string("abc\r"), true));
1111 EXPECT_EQ("\\0\\0", backslashify(string(2, '\0')));
1112
1113 StringPiece input1 = "abc\r";
1114 std::string output1 = backslashify(input1);
1115 EXPECT_EQ("abc\\r", output1);
1116}
1117
1118TEST(String, humanify) {
1119 // Simple cases; output is obvious.
1120 EXPECT_EQ("abc", humanify(string("abc")));
1121 EXPECT_EQ("abc\\\\r", humanify(string("abc\\r")));
1122 EXPECT_EQ("0xff", humanify(string("\xff")));
1123 EXPECT_EQ("abc\\xff", humanify(string("abc\xff")));
1124 EXPECT_EQ("abc\\b", humanify(string("abc\b")));
1125 EXPECT_EQ("0x00", humanify(string(1, '\0')));
1126 EXPECT_EQ("0x0000", humanify(string(2, '\0')));
1127
1128 // Mostly printable, so backslash! 80, 60, and 40% printable, respectively
1129 EXPECT_EQ("aaaa\\xff", humanify(string("aaaa\xff")));
1130 EXPECT_EQ("aaa\\xff\\xff", humanify(string("aaa\xff\xff")));
1131 EXPECT_EQ("aa\\xff\\xff\\xff", humanify(string("aa\xff\xff\xff")));
1132
1133 // 20% printable, and the printable portion isn't the prefix; hexify!
1134 EXPECT_EQ(
1135 "0xff61ffffff",
1136 humanify(string("\xff"
1137 "a\xff\xff\xff")));
1138
1139 // Same as previous, except swap first two chars; prefix is
1140 // printable and within the threshold, so backslashify.
1141 EXPECT_EQ("a\\xff\\xff\\xff\\xff", humanify(string("a\xff\xff\xff\xff")));
1142
1143 // Just too much unprintable; hex, despite prefix.
1144 EXPECT_EQ("0x61ffffffffff", humanify(string("a\xff\xff\xff\xff\xff")));
1145}
1146
1147namespace {
1148
1149/**
1150 * Copy bytes from src to somewhere in the buffer referenced by dst. The
1151 * actual starting position of the copy will be the first address in the
1152 * destination buffer whose address mod 8 is equal to the src address mod 8.
1153 * The caller is responsible for ensuring that the destination buffer has
1154 * enough extra space to accommodate the shifted copy.
1155 */
1156char* copyWithSameAlignment(char* dst, const char* src, size_t length) {
1157 const char* originalDst = dst;
1158 size_t dstOffset = size_t(dst) & 0x7;
1159 size_t srcOffset = size_t(src) & 0x7;
1160 while (dstOffset != srcOffset) {
1161 dst++;
1162 dstOffset++;
1163 dstOffset &= 0x7;
1164 }
1165 CHECK(dst <= originalDst + 7);
1166 CHECK((size_t(dst) & 0x7) == (size_t(src) & 0x7));
1167 memcpy(dst, src, length);
1168 return dst;
1169}
1170
1171void testToLowerAscii(Range<const char*> src) {
1172 // Allocate extra space so we can make copies that start at the
1173 // same alignment (byte, word, quadword, etc) as the source buffer.
1174 auto controlBuf = std::vector<char>(src.size() + 7);
1175 char* control =
1176 copyWithSameAlignment(controlBuf.data(), src.begin(), src.size());
1177
1178 auto testBuf = std::vector<char>(src.size() + 7);
1179 char* test = copyWithSameAlignment(testBuf.data(), src.begin(), src.size());
1180
1181 for (size_t i = 0; i < src.size(); i++) {
1182 control[i] = tolower(control[i]);
1183 }
1184 toLowerAscii(test, src.size());
1185 for (size_t i = 0; i < src.size(); i++) {
1186 EXPECT_EQ(control[i], test[i]);
1187 }
1188}
1189
1190} // namespace
1191
1192TEST(String, toLowerAsciiAligned) {
1193 static const size_t kSize = 256;
1194 char input[kSize];
1195 for (size_t i = 0; i < kSize; i++) {
1196 input[i] = (char)(i & 0xff);
1197 }
1198 testToLowerAscii(Range<const char*>(input, kSize));
1199}
1200
1201TEST(String, toLowerAsciiUnaligned) {
1202 static const size_t kSize = 256;
1203 char input[kSize];
1204 for (size_t i = 0; i < kSize; i++) {
1205 input[i] = (char)(i & 0xff);
1206 }
1207 // Test input buffers of several lengths to exercise all the
1208 // cases: buffer at the start/middle/end of an aligned block, plus
1209 // buffers that span multiple aligned blocks. The longest test input
1210 // is 3 unaligned bytes + 4 32-bit aligned bytes + 8 64-bit aligned
1211 // + 4 32-bit aligned + 3 unaligned = 22 bytes.
1212 for (size_t length = 1; length < 23; length++) {
1213 for (size_t offset = 0; offset + length <= kSize; offset++) {
1214 testToLowerAscii(Range<const char*>(input + offset, length));
1215 }
1216 }
1217}
1218
1219TEST(String, whitespace) {
1220 // trimWhitespace:
1221 EXPECT_EQ("kavabanga", trimWhitespace("kavabanga"));
1222 EXPECT_EQ("kavabanga", trimWhitespace("kavabanga \t \n "));
1223 EXPECT_EQ("kavabanga", trimWhitespace(" \t \r \n \n kavabanga"));
1224 EXPECT_EQ("kavabanga", trimWhitespace("\t \r \n kavabanga \t \n "));
1225 EXPECT_EQ("kavabanga", trimWhitespace(" \t \r \n \n kavabanga"));
1226 EXPECT_EQ("kavabanga", trimWhitespace("\t \r \n kavabanga \t \n "));
1227 EXPECT_EQ(
1228 ltrimWhitespace(rtrimWhitespace("kavabanga")),
1229 rtrimWhitespace(ltrimWhitespace("kavabanga")));
1230 EXPECT_EQ(
1231 ltrimWhitespace(rtrimWhitespace("kavabanga \r\t\n")),
1232 rtrimWhitespace(ltrimWhitespace("kavabanga \r\t\n")));
1233 EXPECT_EQ("", trimWhitespace("\t \r \n \t \n "));
1234 EXPECT_EQ("", trimWhitespace(""));
1235 EXPECT_EQ("", trimWhitespace("\t"));
1236 EXPECT_EQ("", trimWhitespace("\r"));
1237 EXPECT_EQ("", trimWhitespace("\n"));
1238 EXPECT_EQ("", trimWhitespace("\t "));
1239 EXPECT_EQ("", trimWhitespace("\r "));
1240 EXPECT_EQ("", trimWhitespace("\n "));
1241 EXPECT_EQ("", trimWhitespace(" \t"));
1242 EXPECT_EQ("", trimWhitespace(" \r"));
1243 EXPECT_EQ("", trimWhitespace(" \n"));
1244
1245 // ltrimWhitespace:
1246 EXPECT_EQ("kavabanga", ltrimWhitespace("\t kavabanga"));
1247 EXPECT_EQ("kavabanga \r\n", ltrimWhitespace("\t kavabanga \r\n"));
1248 EXPECT_EQ("", ltrimWhitespace("\r "));
1249 EXPECT_EQ("", ltrimWhitespace("\n "));
1250 EXPECT_EQ("", ltrimWhitespace("\r "));
1251
1252 // rtrimWhitespace:
1253 EXPECT_EQ("\t kavabanga", rtrimWhitespace("\t kavabanga"));
1254 EXPECT_EQ("\t kavabanga", rtrimWhitespace("\t kavabanga \r\n"));
1255 EXPECT_EQ("", rtrimWhitespace("\r "));
1256 EXPECT_EQ("", rtrimWhitespace("\n "));
1257 EXPECT_EQ("", rtrimWhitespace("\r "));
1258}
1259
1260TEST(String, stripLeftMargin_really_empty) {
1261 auto input = "";
1262 auto expected = "";
1263 EXPECT_EQ(expected, stripLeftMargin(input));
1264}
1265
1266TEST(String, stripLeftMargin_empty) {
1267 auto input = R"TEXT(
1268 )TEXT";
1269 auto expected = "";
1270 EXPECT_EQ(expected, stripLeftMargin(input));
1271}
1272
1273TEST(String, stripLeftMargin_only_whitespace) {
1274 // using ~ as a marker
1275 string input = R"TEXT(
1276 ~
1277 )TEXT";
1278 input = boost::regex_replace(input, boost::regex("~"), "");
1279 EXPECT_EQ("\n \n ", input);
1280 auto expected = "\n";
1281 EXPECT_EQ(expected, stripLeftMargin(input));
1282}
1283
1284TEST(String, stripLeftMargin_only_uneven_whitespace) {
1285 // using ~ as a marker1
1286 string input = R"TEXT(
1287 ~
1288 ~
1289 )TEXT";
1290 input = boost::regex_replace(input, boost::regex("~"), "");
1291 EXPECT_EQ("\n \n \n ", input);
1292 auto expected = "\n\n";
1293
1294 EXPECT_EQ(expected, stripLeftMargin(input));
1295}
1296
1297TEST(String, stripLeftMargin_one_line) {
1298 auto input = R"TEXT(
1299 hi there bob!
1300 )TEXT";
1301 auto expected = "hi there bob!\n";
1302 EXPECT_EQ(expected, stripLeftMargin(input));
1303}
1304
1305TEST(String, stripLeftMargin_two_lines) {
1306 auto input = R"TEXT(
1307 hi there bob!
1308 nice weather today!
1309 )TEXT";
1310 auto expected = "hi there bob!\nnice weather today!\n";
1311 EXPECT_EQ(expected, stripLeftMargin(input));
1312}
1313
1314TEST(String, stripLeftMargin_three_lines_uneven) {
1315 auto input = R"TEXT(
1316 hi there bob!
1317 nice weather today!
1318 so long!
1319 )TEXT";
1320 auto expected = " hi there bob!\nnice weather today!\n so long!\n";
1321 EXPECT_EQ(expected, stripLeftMargin(input));
1322}
1323
1324TEST(String, stripLeftMargin_preceding_blank_lines) {
1325 auto input = R"TEXT(
1326
1327
1328 hi there bob!
1329 )TEXT";
1330 auto expected = "\n\nhi there bob!\n";
1331 EXPECT_EQ(expected, stripLeftMargin(input));
1332}
1333
1334TEST(String, stripLeftMargin_succeeding_blank_lines) {
1335 auto input = R"TEXT(
1336 hi there bob!
1337
1338
1339 )TEXT";
1340 auto expected = "hi there bob!\n\n\n";
1341 EXPECT_EQ(expected, stripLeftMargin(input));
1342}
1343
1344TEST(String, stripLeftMargin_interstitial_undented_whiteline) {
1345 // using ~ as a marker
1346 string input = R"TEXT(
1347 hi there bob!
1348 ~
1349 so long!
1350 )TEXT";
1351 input = boost::regex_replace(input, boost::regex(" +~"), "");
1352 EXPECT_EQ("\n hi there bob!\n\n so long!\n ", input);
1353 auto expected = "hi there bob!\n\nso long!\n";
1354 EXPECT_EQ(expected, stripLeftMargin(input));
1355}
1356
1357TEST(String, stripLeftMargin_interstitial_dedented_whiteline) {
1358 // using ~ as a marker
1359 string input = R"TEXT(
1360 hi there bob!
1361 ~
1362 so long!
1363 )TEXT";
1364 input = boost::regex_replace(input, boost::regex("~"), "");
1365 EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
1366 auto expected = "hi there bob!\n\nso long!\n";
1367 EXPECT_EQ(expected, stripLeftMargin(input));
1368}
1369
1370TEST(String, stripLeftMargin_interstitial_equidented_whiteline) {
1371 // using ~ as a marker
1372 string input = R"TEXT(
1373 hi there bob!
1374 ~
1375 so long!
1376 )TEXT";
1377 input = boost::regex_replace(input, boost::regex("~"), "");
1378 EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
1379 auto expected = "hi there bob!\n\nso long!\n";
1380 EXPECT_EQ(expected, stripLeftMargin(input));
1381}
1382
1383TEST(String, stripLeftMargin_interstitial_indented_whiteline) {
1384 // using ~ as a marker
1385 string input = R"TEXT(
1386 hi there bob!
1387 ~
1388 so long!
1389 )TEXT";
1390 input = boost::regex_replace(input, boost::regex("~"), "");
1391 EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
1392 auto expected = "hi there bob!\n \nso long!\n";
1393 EXPECT_EQ(expected, stripLeftMargin(input));
1394}
1395
1396TEST(String, stripLeftMargin_no_pre_whitespace) {
1397 // using ~ as a marker
1398 string input = R"TEXT( hi there bob!
1399 ~
1400 so long!
1401 )TEXT";
1402 input = boost::regex_replace(input, boost::regex("~"), "");
1403 EXPECT_EQ(" hi there bob!\n \n so long!\n ", input);
1404 auto expected = "hi there bob!\n \nso long!\n";
1405 EXPECT_EQ(expected, stripLeftMargin(input));
1406}
1407
1408TEST(String, stripLeftMargin_no_post_whitespace) {
1409 // using ~ as a marker
1410 string input = R"TEXT(
1411 hi there bob!
1412 ~
1413 so long! )TEXT";
1414 input = boost::regex_replace(input, boost::regex("~"), "");
1415 EXPECT_EQ("\n hi there bob!\n \n so long! ", input);
1416 auto expected = "hi there bob!\n \nso long! ";
1417 EXPECT_EQ(expected, stripLeftMargin(input));
1418}
1419