2 * Copyright 2014 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/String.h>
20 #include <boost/algorithm/string.hpp>
21 #include <gtest/gtest.h>
23 #include <folly/Benchmark.h>
25 using namespace folly;
28 TEST(StringPrintf, BasicTest) {
29 EXPECT_EQ("abc", stringPrintf("%s", "abc"));
30 EXPECT_EQ("abc", stringPrintf("%sbc", "a"));
31 EXPECT_EQ("abc", stringPrintf("a%sc", "b"));
32 EXPECT_EQ("abc", stringPrintf("ab%s", "c"));
34 EXPECT_EQ("abc", stringPrintf("abc"));
37 TEST(StringPrintf, NumericFormats) {
38 EXPECT_EQ("12", stringPrintf("%d", 12));
39 EXPECT_EQ("5000000000", stringPrintf("%ld", 5000000000UL));
40 EXPECT_EQ("5000000000", stringPrintf("%ld", 5000000000L));
41 EXPECT_EQ("-5000000000", stringPrintf("%ld", -5000000000L));
42 EXPECT_EQ("-1", stringPrintf("%d", 0xffffffff));
43 EXPECT_EQ("-1", stringPrintf("%ld", 0xffffffffffffffff));
44 EXPECT_EQ("-1", stringPrintf("%ld", 0xffffffffffffffffUL));
46 EXPECT_EQ("7.7", stringPrintf("%1.1f", 7.7));
47 EXPECT_EQ("7.7", stringPrintf("%1.1lf", 7.7));
48 EXPECT_EQ("7.70000000000000018",
49 stringPrintf("%.17f", 7.7));
50 EXPECT_EQ("7.70000000000000018",
51 stringPrintf("%.17lf", 7.7));
54 TEST(StringPrintf, Appending) {
56 stringAppendf(&s, "a%s", "b");
57 stringAppendf(&s, "%c", 'c');
59 stringAppendf(&s, " %d", 123);
60 EXPECT_EQ(s, "abc 123");
63 TEST(StringPrintf, VariousSizes) {
64 // Test a wide variety of output sizes
65 for (int i = 0; i < 100; ++i) {
66 string expected(i + 1, 'a');
67 EXPECT_EQ("X" + expected + "X", stringPrintf("X%sX", expected.c_str()));
70 EXPECT_EQ("abc12345678910111213141516171819202122232425xyz",
71 stringPrintf("abc%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
72 "%d%d%d%d%d%d%d%d%d%d%dxyz",
73 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
74 17, 18, 19, 20, 21, 22, 23, 24, 25));
77 TEST(StringPrintf, oldStringPrintfTests) {
78 EXPECT_EQ(string("a/b/c/d"),
79 stringPrintf("%s/%s/%s/%s", "a", "b", "c", "d"));
81 EXPECT_EQ(string(" 5 10"),
82 stringPrintf("%5d %5d", 5, 10));
84 // check printing w/ a big buffer
85 for (int size = (1 << 8); size <= (1 << 15); size <<= 1) {
87 string b = stringPrintf("%s", a.c_str());
88 EXPECT_EQ(a.size(), b.size());
92 TEST(StringPrintf, oldStringAppendf) {
94 stringAppendf(&s, "%s/%s/%s/%s", "a", "b", "c", "d");
95 EXPECT_EQ(string("helloa/b/c/d"), s);
98 BENCHMARK(new_stringPrintfSmall, iters) {
99 for (int64_t i = 0; i < iters; ++i) {
100 int32_t x = int32_t(i);
101 int32_t y = int32_t(i + 1);
103 stringPrintf("msg msg msg msg msg msg msg msg: %d, %d, %s",
108 TEST(Escape, cEscape) {
109 EXPECT_EQ("hello world", cEscape<std::string>("hello world"));
110 EXPECT_EQ("hello \\\\world\\\" goodbye",
111 cEscape<std::string>("hello \\world\" goodbye"));
112 EXPECT_EQ("hello\\nworld", cEscape<std::string>("hello\nworld"));
113 EXPECT_EQ("hello\\377\\376", cEscape<std::string>("hello\xff\xfe"));
116 TEST(Escape, cUnescape) {
117 EXPECT_EQ("hello world", cUnescape<std::string>("hello world"));
118 EXPECT_EQ("hello \\world\" goodbye",
119 cUnescape<std::string>("hello \\\\world\\\" goodbye"));
120 EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\nworld"));
121 EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\012world"));
122 EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\x0aworld"));
123 EXPECT_EQ("hello\xff\xfe", cUnescape<std::string>("hello\\377\\376"));
124 EXPECT_EQ("hello\xff\xfe", cUnescape<std::string>("hello\\xff\\xfe"));
126 EXPECT_THROW({cUnescape<std::string>("hello\\");},
127 std::invalid_argument);
128 EXPECT_THROW({cUnescape<std::string>("hello\\x");},
129 std::invalid_argument);
130 EXPECT_THROW({cUnescape<std::string>("hello\\q");},
131 std::invalid_argument);
134 TEST(Escape, uriEscape) {
135 EXPECT_EQ("hello%2c%20%2fworld", uriEscape<std::string>("hello, /world"));
136 EXPECT_EQ("hello%2c%20/world", uriEscape<std::string>("hello, /world",
137 UriEscapeMode::PATH));
138 EXPECT_EQ("hello%2c+%2fworld", uriEscape<std::string>("hello, /world",
139 UriEscapeMode::QUERY));
142 TEST(Escape, uriUnescape) {
143 EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello, /world"));
144 EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello%2c%20%2fworld"));
145 EXPECT_EQ("hello,+/world", uriUnescape<std::string>("hello%2c+%2fworld"));
146 EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello%2c+%2fworld",
147 UriEscapeMode::QUERY));
148 EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2f"));
149 EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2F"));
150 EXPECT_THROW({uriUnescape<std::string>("hello%");},
151 std::invalid_argument);
152 EXPECT_THROW({uriUnescape<std::string>("hello%2");},
153 std::invalid_argument);
154 EXPECT_THROW({uriUnescape<std::string>("hello%2g");},
155 std::invalid_argument);
159 void expectPrintable(StringPiece s) {
167 TEST(Escape, uriEscapeAllCombinations) {
170 StringPiece in(c, 2);
173 for (int i = 0; i < 256; ++i) {
175 for (int j = 0; j < 256; ++j) {
180 expectPrintable(tmp);
181 uriUnescape(tmp, out);
189 return ((v >= '0' && v <= '9') ||
190 (v >= 'A' && v <= 'F') ||
191 (v >= 'a' && v <= 'f'));
195 TEST(Escape, uriUnescapePercentDecoding) {
196 char c[4] = {'%', '\0', '\0', '\0'};
197 StringPiece in(c, 3);
199 unsigned int expected = 0;
200 for (int i = 0; i < 256; ++i) {
202 for (int j = 0; j < 256; ++j) {
204 if (isHex(i) && isHex(j)) {
206 uriUnescape(in, out);
207 EXPECT_EQ(1, out.size());
208 EXPECT_EQ(1, sscanf(c + 1, "%x", &expected));
209 unsigned char v = out[0];
210 EXPECT_EQ(expected, v);
212 EXPECT_THROW({uriUnescape(in, out);}, std::invalid_argument);
220 fbstring cbmEscapedString;
221 fbstring cEscapedString;
222 fbstring cUnescapedString;
223 const size_t kCBmStringLength = 64 << 10;
224 const uint32_t kCPrintablePercentage = 90;
226 fbstring uribmString;
227 fbstring uribmEscapedString;
228 fbstring uriEscapedString;
229 fbstring uriUnescapedString;
230 const size_t kURIBmStringLength = 256;
231 const uint32_t kURIPassThroughPercentage = 50;
233 void initBenchmark() {
237 std::uniform_int_distribution<uint32_t> printable(32, 126);
238 std::uniform_int_distribution<uint32_t> nonPrintable(0, 160);
239 std::uniform_int_distribution<uint32_t> percentage(0, 99);
241 cbmString.reserve(kCBmStringLength);
242 for (size_t i = 0; i < kCBmStringLength; ++i) {
244 if (percentage(rnd) < kCPrintablePercentage) {
247 c = nonPrintable(rnd);
248 // Generate characters in both non-printable ranges:
249 // 0..31 and 127..255
254 cbmString.push_back(c);
257 cbmEscapedString = cEscape<fbstring>(cbmString);
260 std::uniform_int_distribution<uint32_t> passthrough('a', 'z');
261 std::string encodeChars = " ?!\"',+[]";
262 std::uniform_int_distribution<uint32_t> encode(0, encodeChars.size() - 1);
264 uribmString.reserve(kURIBmStringLength);
265 for (size_t i = 0; i < kURIBmStringLength; ++i) {
267 if (percentage(rnd) < kURIPassThroughPercentage) {
268 c = passthrough(rnd);
270 c = encodeChars[encode(rnd)];
272 uribmString.push_back(c);
275 uribmEscapedString = uriEscape<fbstring>(uribmString);
278 BENCHMARK(BM_cEscape, iters) {
280 cEscapedString = cEscape<fbstring>(cbmString);
281 doNotOptimizeAway(cEscapedString.size());
285 BENCHMARK(BM_cUnescape, iters) {
287 cUnescapedString = cUnescape<fbstring>(cbmEscapedString);
288 doNotOptimizeAway(cUnescapedString.size());
292 BENCHMARK(BM_uriEscape, iters) {
294 uriEscapedString = uriEscape<fbstring>(uribmString);
295 doNotOptimizeAway(uriEscapedString.size());
299 BENCHMARK(BM_uriUnescape, iters) {
301 uriUnescapedString = uriUnescape<fbstring>(uribmEscapedString);
302 doNotOptimizeAway(uriUnescapedString.size());
310 double pow2(int exponent) {
311 return double(int64_t(1) << exponent);
315 struct PrettyTestCase{
316 std::string prettyString;
318 PrettyType prettyType;
321 PrettyTestCase prettyTestCases[] =
323 {string("8.53e+07 s "), 85.3e6, PRETTY_TIME},
324 {string("8.53e+07 s "), 85.3e6, PRETTY_TIME},
325 {string("85.3 ms"), 85.3e-3, PRETTY_TIME},
326 {string("85.3 us"), 85.3e-6, PRETTY_TIME},
327 {string("85.3 ns"), 85.3e-9, PRETTY_TIME},
328 {string("85.3 ps"), 85.3e-12, PRETTY_TIME},
329 {string("8.53e-14 s "), 85.3e-15, PRETTY_TIME},
331 {string("0 s "), 0, PRETTY_TIME},
332 {string("1 s "), 1.0, PRETTY_TIME},
333 {string("1 ms"), 1.0e-3, PRETTY_TIME},
334 {string("1 us"), 1.0e-6, PRETTY_TIME},
335 {string("1 ns"), 1.0e-9, PRETTY_TIME},
336 {string("1 ps"), 1.0e-12, PRETTY_TIME},
338 // check bytes printing
339 {string("853 B "), 853., PRETTY_BYTES},
340 {string("833 kB"), 853.e3, PRETTY_BYTES},
341 {string("813.5 MB"), 853.e6, PRETTY_BYTES},
342 {string("7.944 GB"), 8.53e9, PRETTY_BYTES},
343 {string("794.4 GB"), 853.e9, PRETTY_BYTES},
344 {string("775.8 TB"), 853.e12, PRETTY_BYTES},
346 {string("0 B "), 0, PRETTY_BYTES},
347 {string("1 B "), pow2(0), PRETTY_BYTES},
348 {string("1 kB"), pow2(10), PRETTY_BYTES},
349 {string("1 MB"), pow2(20), PRETTY_BYTES},
350 {string("1 GB"), pow2(30), PRETTY_BYTES},
351 {string("1 TB"), pow2(40), PRETTY_BYTES},
353 {string("853 B "), 853., PRETTY_BYTES_IEC},
354 {string("833 KiB"), 853.e3, PRETTY_BYTES_IEC},
355 {string("813.5 MiB"), 853.e6, PRETTY_BYTES_IEC},
356 {string("7.944 GiB"), 8.53e9, PRETTY_BYTES_IEC},
357 {string("794.4 GiB"), 853.e9, PRETTY_BYTES_IEC},
358 {string("775.8 TiB"), 853.e12, PRETTY_BYTES_IEC},
360 {string("0 B "), 0, PRETTY_BYTES_IEC},
361 {string("1 B "), pow2(0), PRETTY_BYTES_IEC},
362 {string("1 KiB"), pow2(10), PRETTY_BYTES_IEC},
363 {string("1 MiB"), pow2(20), PRETTY_BYTES_IEC},
364 {string("1 GiB"), pow2(30), PRETTY_BYTES_IEC},
365 {string("1 TiB"), pow2(40), PRETTY_BYTES_IEC},
367 // check bytes metric printing
368 {string("853 B "), 853., PRETTY_BYTES_METRIC},
369 {string("853 kB"), 853.e3, PRETTY_BYTES_METRIC},
370 {string("853 MB"), 853.e6, PRETTY_BYTES_METRIC},
371 {string("8.53 GB"), 8.53e9, PRETTY_BYTES_METRIC},
372 {string("853 GB"), 853.e9, PRETTY_BYTES_METRIC},
373 {string("853 TB"), 853.e12, PRETTY_BYTES_METRIC},
375 {string("0 B "), 0, PRETTY_BYTES_METRIC},
376 {string("1 B "), 1.0, PRETTY_BYTES_METRIC},
377 {string("1 kB"), 1.0e+3, PRETTY_BYTES_METRIC},
378 {string("1 MB"), 1.0e+6, PRETTY_BYTES_METRIC},
380 {string("1 GB"), 1.0e+9, PRETTY_BYTES_METRIC},
381 {string("1 TB"), 1.0e+12, PRETTY_BYTES_METRIC},
383 // check metric-units (powers of 1000) printing
384 {string("853 "), 853., PRETTY_UNITS_METRIC},
385 {string("853 k"), 853.e3, PRETTY_UNITS_METRIC},
386 {string("853 M"), 853.e6, PRETTY_UNITS_METRIC},
387 {string("8.53 bil"), 8.53e9, PRETTY_UNITS_METRIC},
388 {string("853 bil"), 853.e9, PRETTY_UNITS_METRIC},
389 {string("853 tril"), 853.e12, PRETTY_UNITS_METRIC},
391 // check binary-units (powers of 1024) printing
392 {string("0 "), 0, PRETTY_UNITS_BINARY},
393 {string("1 "), pow2(0), PRETTY_UNITS_BINARY},
394 {string("1 k"), pow2(10), PRETTY_UNITS_BINARY},
395 {string("1 M"), pow2(20), PRETTY_UNITS_BINARY},
396 {string("1 G"), pow2(30), PRETTY_UNITS_BINARY},
397 {string("1 T"), pow2(40), PRETTY_UNITS_BINARY},
399 {string("1023 "), pow2(10) - 1, PRETTY_UNITS_BINARY},
400 {string("1024 k"), pow2(20) - 1, PRETTY_UNITS_BINARY},
401 {string("1024 M"), pow2(30) - 1, PRETTY_UNITS_BINARY},
402 {string("1024 G"), pow2(40) - 1, PRETTY_UNITS_BINARY},
404 {string("0 "), 0, PRETTY_UNITS_BINARY_IEC},
405 {string("1 "), pow2(0), PRETTY_UNITS_BINARY_IEC},
406 {string("1 Ki"), pow2(10), PRETTY_UNITS_BINARY_IEC},
407 {string("1 Mi"), pow2(20), PRETTY_UNITS_BINARY_IEC},
408 {string("1 Gi"), pow2(30), PRETTY_UNITS_BINARY_IEC},
409 {string("1 Ti"), pow2(40), PRETTY_UNITS_BINARY_IEC},
411 {string("1023 "), pow2(10) - 1, PRETTY_UNITS_BINARY_IEC},
412 {string("1024 Ki"), pow2(20) - 1, PRETTY_UNITS_BINARY_IEC},
413 {string("1024 Mi"), pow2(30) - 1, PRETTY_UNITS_BINARY_IEC},
414 {string("1024 Gi"), pow2(40) - 1, PRETTY_UNITS_BINARY_IEC},
416 //check border SI cases
418 {string("1 Y"), 1e24, PRETTY_SI},
419 {string("10 Y"), 1e25, PRETTY_SI},
420 {string("1 y"), 1e-24, PRETTY_SI},
421 {string("10 y"), 1e-23, PRETTY_SI},
423 // check that negative values work
424 {string("-85.3 s "), -85.3, PRETTY_TIME},
425 {string("-85.3 ms"), -85.3e-3, PRETTY_TIME},
426 {string("-85.3 us"), -85.3e-6, PRETTY_TIME},
427 {string("-85.3 ns"), -85.3e-9, PRETTY_TIME},
429 {string("endoftest"), 0, PRETTY_NUM_TYPES}
432 TEST(PrettyPrint, Basic) {
433 for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i){
434 const PrettyTestCase& prettyTest = prettyTestCases[i];
435 EXPECT_EQ(prettyTest.prettyString,
436 prettyPrint(prettyTest.realValue, prettyTest.prettyType));
440 TEST(PrettyToDouble, Basic) {
441 // check manually created tests
442 for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i){
443 PrettyTestCase testCase = prettyTestCases[i];
444 PrettyType formatType = testCase.prettyType;
445 double x = testCase.realValue;
446 std::string testString = testCase.prettyString;
449 recoveredX = prettyToDouble(testString, formatType);
450 } catch (std::range_error &ex){
453 double relativeError = fabs(x) < 1e-5 ? (x-recoveredX) :
454 (x - recoveredX) / x;
455 EXPECT_NEAR(0, relativeError, 1e-3);
458 // checks for compatibility with prettyPrint over the whole parameter space
459 for (int i = 0 ; i < PRETTY_NUM_TYPES; ++i){
460 PrettyType formatType = static_cast<PrettyType>(i);
461 for (double x = 1e-18; x < 1e40; x *= 1.9){
462 bool addSpace = static_cast<PrettyType> (i) == PRETTY_SI;
463 for (int it = 0; it < 2; ++it, addSpace = true){
466 recoveredX = prettyToDouble(prettyPrint(x, formatType, addSpace),
468 } catch (std::range_error &ex){
471 double relativeError = (x - recoveredX) / x;
472 EXPECT_NEAR(0, relativeError, 1e-3);
477 // check for incorrect values
478 EXPECT_THROW(prettyToDouble("10Mx", PRETTY_SI), std::range_error);
479 EXPECT_THROW(prettyToDouble("10 Mx", PRETTY_SI), std::range_error);
480 EXPECT_THROW(prettyToDouble("10 M x", PRETTY_SI), std::range_error);
482 StringPiece testString = "10Mx";
483 EXPECT_DOUBLE_EQ(prettyToDouble(&testString, PRETTY_UNITS_METRIC), 10e6);
484 EXPECT_EQ(testString, "x");
487 TEST(PrettyPrint, HexDump) {
488 std::string a("abc\x00\x02\xa0", 6); // embedded NUL
490 "00000000 61 62 63 00 02 a0 "
492 hexDump(a.data(), a.size()));
494 a = "abcdefghijklmnopqrstuvwxyz";
496 "00000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 "
497 "|abcdefghijklmnop|\n"
498 "00000010 71 72 73 74 75 76 77 78 79 7a "
500 hexDump(a.data(), a.size()));
503 TEST(System, errnoStr) {
505 EXPECT_EQ(EACCES, errno);
506 EXPECT_EQ(EACCES, errno); // twice to make sure EXPECT_EQ doesn't change it
508 fbstring expected = strerror(ENOENT);
511 EXPECT_EQ(expected, errnoStr(ENOENT));
512 // Ensure that errno isn't changed
513 EXPECT_EQ(EACCES, errno);
515 // Per POSIX, all errno values are positive, so -1 is invalid
518 // Ensure that errno isn't changed
519 EXPECT_EQ(EACCES, errno);
522 namespace folly_test {
523 struct ThisIsAVeryLongStructureName {
525 } // namespace folly_test
527 #if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK
528 TEST(System, demangle) {
529 char expected[] = "folly_test::ThisIsAVeryLongStructureName";
532 demangle(typeid(folly_test::ThisIsAVeryLongStructureName)).c_str());
535 char buf[sizeof(expected)];
536 EXPECT_EQ(sizeof(expected) - 1,
537 demangle(typeid(folly_test::ThisIsAVeryLongStructureName),
539 EXPECT_STREQ(expected, buf);
541 EXPECT_EQ(sizeof(expected) - 1,
542 demangle(typeid(folly_test::ThisIsAVeryLongStructureName),
544 EXPECT_STREQ("folly_test", buf);
551 template<template<class,class> class VectorType>
553 VectorType<string,std::allocator<string> > parts;
555 folly::split(',', "a,b,c", parts);
556 EXPECT_EQ(parts.size(), 3);
557 EXPECT_EQ(parts[0], "a");
558 EXPECT_EQ(parts[1], "b");
559 EXPECT_EQ(parts[2], "c");
562 folly::split(',', StringPiece("a,b,c"), parts);
563 EXPECT_EQ(parts.size(), 3);
564 EXPECT_EQ(parts[0], "a");
565 EXPECT_EQ(parts[1], "b");
566 EXPECT_EQ(parts[2], "c");
569 folly::split(',', string("a,b,c"), parts);
570 EXPECT_EQ(parts.size(), 3);
571 EXPECT_EQ(parts[0], "a");
572 EXPECT_EQ(parts[1], "b");
573 EXPECT_EQ(parts[2], "c");
576 folly::split(',', "a,,c", parts);
577 EXPECT_EQ(parts.size(), 3);
578 EXPECT_EQ(parts[0], "a");
579 EXPECT_EQ(parts[1], "");
580 EXPECT_EQ(parts[2], "c");
583 folly::split(',', string("a,,c"), parts);
584 EXPECT_EQ(parts.size(), 3);
585 EXPECT_EQ(parts[0], "a");
586 EXPECT_EQ(parts[1], "");
587 EXPECT_EQ(parts[2], "c");
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");
596 folly::split(',', string("a,,c"), parts, true);
597 EXPECT_EQ(parts.size(), 2);
598 EXPECT_EQ(parts[0], "a");
599 EXPECT_EQ(parts[1], "c");
602 folly::split(',', string(",,a,,c,,,"), parts, true);
603 EXPECT_EQ(parts.size(), 2);
604 EXPECT_EQ(parts[0], "a");
605 EXPECT_EQ(parts[1], "c");
608 // test multiple split w/o clear
609 folly::split(',', ",,a,,c,,,", parts, true);
610 EXPECT_EQ(parts.size(), 2);
611 EXPECT_EQ(parts[0], "a");
612 EXPECT_EQ(parts[1], "c");
613 folly::split(',', ",,a,,c,,,", parts, true);
614 EXPECT_EQ(parts.size(), 4);
615 EXPECT_EQ(parts[2], "a");
616 EXPECT_EQ(parts[3], "c");
619 // test splits that with multi-line delimiter
620 folly::split("ab", "dabcabkdbkab", parts, true);
621 EXPECT_EQ(parts.size(), 3);
622 EXPECT_EQ(parts[0], "d");
623 EXPECT_EQ(parts[1], "c");
624 EXPECT_EQ(parts[2], "kdbk");
627 // test last part is shorter than the delimiter
628 folly::split("bc", "abcd", parts, true);
629 EXPECT_EQ(parts.size(), 2);
630 EXPECT_EQ(parts[0], "a");
631 EXPECT_EQ(parts[1], "d");
634 string orig = "ab2342asdfv~~!";
635 folly::split("", orig, parts, true);
636 EXPECT_EQ(parts.size(), 1);
637 EXPECT_EQ(parts[0], orig);
640 folly::split("452x;o38asfsajsdlfdf.j", "asfds", parts, true);
641 EXPECT_EQ(parts.size(), 1);
642 EXPECT_EQ(parts[0], "asfds");
645 folly::split("a", "", parts, true);
646 EXPECT_EQ(parts.size(), 0);
649 folly::split("a", "", parts);
650 EXPECT_EQ(parts.size(), 1);
651 EXPECT_EQ(parts[0], "");
654 folly::split("a", StringPiece(), parts, true);
655 EXPECT_EQ(parts.size(), 0);
658 folly::split("a", StringPiece(), parts);
659 EXPECT_EQ(parts.size(), 1);
660 EXPECT_EQ(parts[0], "");
663 folly::split("a", "abcdefg", parts, true);
664 EXPECT_EQ(parts.size(), 1);
665 EXPECT_EQ(parts[0], "bcdefg");
668 orig = "All, , your base, are , , belong to us";
669 folly::split(", ", orig, parts, true);
670 EXPECT_EQ(parts.size(), 4);
671 EXPECT_EQ(parts[0], "All");
672 EXPECT_EQ(parts[1], "your base");
673 EXPECT_EQ(parts[2], "are ");
674 EXPECT_EQ(parts[3], "belong to us");
676 folly::split(", ", orig, parts);
677 EXPECT_EQ(parts.size(), 6);
678 EXPECT_EQ(parts[0], "All");
679 EXPECT_EQ(parts[1], "");
680 EXPECT_EQ(parts[2], "your base");
681 EXPECT_EQ(parts[3], "are ");
682 EXPECT_EQ(parts[4], "");
683 EXPECT_EQ(parts[5], "belong to us");
686 orig = ", Facebook, rul,es!, ";
687 folly::split(", ", orig, parts, true);
688 EXPECT_EQ(parts.size(), 2);
689 EXPECT_EQ(parts[0], "Facebook");
690 EXPECT_EQ(parts[1], "rul,es!");
692 folly::split(", ", orig, parts);
693 EXPECT_EQ(parts.size(), 4);
694 EXPECT_EQ(parts[0], "");
695 EXPECT_EQ(parts[1], "Facebook");
696 EXPECT_EQ(parts[2], "rul,es!");
697 EXPECT_EQ(parts[3], "");
700 template<template<class,class> class VectorType>
702 VectorType<StringPiece,std::allocator<StringPiece> > pieces;
703 VectorType<StringPiece,std::allocator<StringPiece> > pieces2;
705 folly::split(',', "a,b,c", pieces);
706 EXPECT_EQ(pieces.size(), 3);
707 EXPECT_EQ(pieces[0], "a");
708 EXPECT_EQ(pieces[1], "b");
709 EXPECT_EQ(pieces[2], "c");
713 folly::split(',', "a,,c", pieces);
714 EXPECT_EQ(pieces.size(), 3);
715 EXPECT_EQ(pieces[0], "a");
716 EXPECT_EQ(pieces[1], "");
717 EXPECT_EQ(pieces[2], "c");
720 folly::split(',', "a,,c", pieces, true);
721 EXPECT_EQ(pieces.size(), 2);
722 EXPECT_EQ(pieces[0], "a");
723 EXPECT_EQ(pieces[1], "c");
726 folly::split(',', ",,a,,c,,,", pieces, true);
727 EXPECT_EQ(pieces.size(), 2);
728 EXPECT_EQ(pieces[0], "a");
729 EXPECT_EQ(pieces[1], "c");
732 // test multiple split w/o clear
733 folly::split(',', ",,a,,c,,,", pieces, true);
734 EXPECT_EQ(pieces.size(), 2);
735 EXPECT_EQ(pieces[0], "a");
736 EXPECT_EQ(pieces[1], "c");
737 folly::split(',', ",,a,,c,,,", pieces, true);
738 EXPECT_EQ(pieces.size(), 4);
739 EXPECT_EQ(pieces[2], "a");
740 EXPECT_EQ(pieces[3], "c");
743 // test multiple split rounds
744 folly::split(",", "a_b,c_d", pieces);
745 EXPECT_EQ(pieces.size(), 2);
746 EXPECT_EQ(pieces[0], "a_b");
747 EXPECT_EQ(pieces[1], "c_d");
748 folly::split("_", pieces[0], pieces2);
749 EXPECT_EQ(pieces2.size(), 2);
750 EXPECT_EQ(pieces2[0], "a");
751 EXPECT_EQ(pieces2[1], "b");
753 folly::split("_", pieces[1], pieces2);
754 EXPECT_EQ(pieces2.size(), 2);
755 EXPECT_EQ(pieces2[0], "c");
756 EXPECT_EQ(pieces2[1], "d");
760 // test splits that with multi-line delimiter
761 folly::split("ab", "dabcabkdbkab", pieces, true);
762 EXPECT_EQ(pieces.size(), 3);
763 EXPECT_EQ(pieces[0], "d");
764 EXPECT_EQ(pieces[1], "c");
765 EXPECT_EQ(pieces[2], "kdbk");
768 string orig = "ab2342asdfv~~!";
769 folly::split("", orig.c_str(), pieces, true);
770 EXPECT_EQ(pieces.size(), 1);
771 EXPECT_EQ(pieces[0], orig);
774 folly::split("452x;o38asfsajsdlfdf.j", "asfds", pieces, true);
775 EXPECT_EQ(pieces.size(), 1);
776 EXPECT_EQ(pieces[0], "asfds");
779 folly::split("a", "", pieces, true);
780 EXPECT_EQ(pieces.size(), 0);
783 folly::split("a", "", pieces);
784 EXPECT_EQ(pieces.size(), 1);
785 EXPECT_EQ(pieces[0], "");
788 folly::split("a", "abcdefg", pieces, true);
789 EXPECT_EQ(pieces.size(), 1);
790 EXPECT_EQ(pieces[0], "bcdefg");
793 orig = "All, , your base, are , , belong to us";
794 folly::split(", ", orig, pieces, true);
795 EXPECT_EQ(pieces.size(), 4);
796 EXPECT_EQ(pieces[0], "All");
797 EXPECT_EQ(pieces[1], "your base");
798 EXPECT_EQ(pieces[2], "are ");
799 EXPECT_EQ(pieces[3], "belong to us");
801 folly::split(", ", orig, pieces);
802 EXPECT_EQ(pieces.size(), 6);
803 EXPECT_EQ(pieces[0], "All");
804 EXPECT_EQ(pieces[1], "");
805 EXPECT_EQ(pieces[2], "your base");
806 EXPECT_EQ(pieces[3], "are ");
807 EXPECT_EQ(pieces[4], "");
808 EXPECT_EQ(pieces[5], "belong to us");
811 orig = ", Facebook, rul,es!, ";
812 folly::split(", ", orig, pieces, true);
813 EXPECT_EQ(pieces.size(), 2);
814 EXPECT_EQ(pieces[0], "Facebook");
815 EXPECT_EQ(pieces[1], "rul,es!");
817 folly::split(", ", orig, pieces);
818 EXPECT_EQ(pieces.size(), 4);
819 EXPECT_EQ(pieces[0], "");
820 EXPECT_EQ(pieces[1], "Facebook");
821 EXPECT_EQ(pieces[2], "rul,es!");
822 EXPECT_EQ(pieces[3], "");
825 const char* str = "a,b";
826 folly::split(',', StringPiece(str), pieces);
827 EXPECT_EQ(pieces.size(), 2);
828 EXPECT_EQ(pieces[0], "a");
829 EXPECT_EQ(pieces[1], "b");
830 EXPECT_EQ(pieces[0].start(), str);
831 EXPECT_EQ(pieces[1].start(), str + 2);
833 std::set<StringPiece> unique;
834 folly::splitTo<StringPiece>(":", "asd:bsd:asd:asd:bsd:csd::asd",
835 std::inserter(unique, unique.begin()), true);
836 EXPECT_EQ(unique.size(), 3);
837 if (unique.size() == 3) {
838 EXPECT_EQ(*unique.begin(), "asd");
839 EXPECT_EQ(*--unique.end(), "csd");
842 VectorType<fbstring,std::allocator<fbstring> > blah;
843 folly::split('-', "a-b-c-d-f-e", blah);
844 EXPECT_EQ(blah.size(), 6);
849 TEST(Split, split_vector) {
850 splitTest<std::vector>();
852 TEST(Split, split_fbvector) {
853 splitTest<folly::fbvector>();
855 TEST(Split, pieces_vector) {
856 piecesTest<std::vector>();
858 TEST(Split, pieces_fbvector) {
859 piecesTest<folly::fbvector>();
863 StringPiece a, b, c, d;
865 EXPECT_TRUE(folly::split<false>('.', "a.b.c.d", a, b, c, d));
866 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
867 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
868 EXPECT_TRUE(folly::split<false>('.', "a", a));
870 EXPECT_TRUE(folly::split('.', "a.b.c.d", a, b, c, d));
871 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
872 EXPECT_TRUE(folly::split('.', "a.b", a, b));
873 EXPECT_TRUE(folly::split('.', "a", a));
875 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
879 EXPECT_FALSE(folly::split<false>('.', "a.b", a, b, c));
880 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b));
884 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
888 EXPECT_FALSE(folly::split('.', "a.b.c", a, b));
889 EXPECT_FALSE(folly::split('.', "a.b", a, b, c));
891 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
894 EXPECT_FALSE(folly::split<false>('.', "a", a, b));
895 EXPECT_TRUE(folly::split<false>('.', "a.b", a));
898 EXPECT_TRUE(folly::split('.', "a.b", a, b));
901 EXPECT_FALSE(folly::split('.', "a", a, b));
902 EXPECT_FALSE(folly::split('.', "a.b", a));
905 TEST(Split, std_string_fixed) {
906 std::string a, b, c, d;
908 EXPECT_TRUE(folly::split<false>('.', "a.b.c.d", a, b, c, d));
909 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
910 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
911 EXPECT_TRUE(folly::split<false>('.', "a", a));
913 EXPECT_TRUE(folly::split('.', "a.b.c.d", a, b, c, d));
914 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
915 EXPECT_TRUE(folly::split('.', "a.b", a, b));
916 EXPECT_TRUE(folly::split('.', "a", a));
918 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
922 EXPECT_FALSE(folly::split<false>('.', "a.b", a, b, c));
923 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b));
927 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
931 EXPECT_FALSE(folly::split('.', "a.b.c", a, b));
932 EXPECT_FALSE(folly::split('.', "a.b", a, b, c));
934 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
937 EXPECT_FALSE(folly::split<false>('.', "a", a, b));
938 EXPECT_TRUE(folly::split<false>('.', "a.b", a));
941 EXPECT_TRUE(folly::split('.', "a.b", a, b));
944 EXPECT_FALSE(folly::split('.', "a", a, b));
945 EXPECT_FALSE(folly::split('.', "a.b", a));
948 TEST(Split, fixed_convert) {
953 EXPECT_TRUE(folly::split(':', "a:13:14.7:b", a, b, c, d));
956 EXPECT_NEAR(14.7, c, 1e-10);
959 EXPECT_TRUE(folly::split<false>(':', "b:14:15.3:c", a, b, c, d));
962 EXPECT_NEAR(15.3, c, 1e-10);
965 EXPECT_FALSE(folly::split(':', "a:13:14.7:b", a, b, d));
967 EXPECT_TRUE(folly::split<false>(':', "a:13:14.7:b", a, b, d));
970 EXPECT_EQ("14.7:b", d);
972 EXPECT_THROW(folly::split<false>(':', "a:13:14.7:b", a, b, c),
979 std::vector<int> empty = { };
980 join(":", empty, output);
981 EXPECT_TRUE(output.empty());
983 std::vector<std::string> input1 = { "1", "23", "456", "" };
984 join(':', input1, output);
985 EXPECT_EQ(output, "1:23:456:");
986 output = join(':', input1);
987 EXPECT_EQ(output, "1:23:456:");
989 auto input2 = { 1, 23, 456 };
990 join("-*-", input2, output);
991 EXPECT_EQ(output, "1-*-23-*-456");
992 output = join("-*-", input2);
993 EXPECT_EQ(output, "1-*-23-*-456");
995 auto input3 = { 'f', 'a', 'c', 'e', 'b', 'o', 'o', 'k' };
996 join("", input3, output);
997 EXPECT_EQ(output, "facebook");
999 join("_", { "", "f", "a", "c", "e", "b", "o", "o", "k", "" }, output);
1000 EXPECT_EQ(output, "_f_a_c_e_b_o_o_k_");
1003 TEST(String, hexlify) {
1004 string input1 = "0123";
1006 EXPECT_TRUE(hexlify(input1, output1));
1007 EXPECT_EQ(output1, "30313233");
1009 fbstring input2 = "abcdefg";
1014 EXPECT_TRUE(hexlify(input2, output2));
1015 EXPECT_EQ(output2, "610063ff65b667");
1018 TEST(String, unhexlify) {
1019 string input1 = "30313233";
1021 EXPECT_TRUE(unhexlify(input1, output1));
1022 EXPECT_EQ(output1, "0123");
1024 fbstring input2 = "610063ff65b667";
1026 EXPECT_TRUE(unhexlify(input2, output2));
1027 EXPECT_EQ(output2.size(), 7);
1028 EXPECT_EQ(output2[0], 'a');
1029 EXPECT_EQ(output2[1], 0);
1030 EXPECT_EQ(output2[2], 'c');
1031 EXPECT_EQ(output2[3] & 0xff, 0xff);
1032 EXPECT_EQ(output2[4], 'e');
1033 EXPECT_EQ(output2[5] & 0xff, 0xb6);
1034 EXPECT_EQ(output2[6], 'g');
1036 string input3 = "x";
1038 EXPECT_FALSE(unhexlify(input3, output3));
1040 string input4 = "xy";
1042 EXPECT_FALSE(unhexlify(input4, output4));
1045 TEST(String, backslashify) {
1046 EXPECT_EQ("abc", string("abc"));
1047 EXPECT_EQ("abc", backslashify(string("abc")));
1048 EXPECT_EQ("abc\\r", backslashify(string("abc\r")));
1049 EXPECT_EQ("abc\\x0d", backslashify(string("abc\r"), true));
1050 EXPECT_EQ("\\0\\0", backslashify(string(2, '\0')));
1053 TEST(String, humanify) {
1054 // Simple cases; output is obvious.
1055 EXPECT_EQ("abc", humanify(string("abc")));
1056 EXPECT_EQ("abc\\\\r", humanify(string("abc\\r")));
1057 EXPECT_EQ("0xff", humanify(string("\xff")));
1058 EXPECT_EQ("abc\\xff", humanify(string("abc\xff")));
1059 EXPECT_EQ("abc\\b", humanify(string("abc\b")));
1060 EXPECT_EQ("0x00", humanify(string(1, '\0')));
1061 EXPECT_EQ("0x0000", humanify(string(2, '\0')));
1064 // Mostly printable, so backslash! 80, 60, and 40% printable, respectively
1065 EXPECT_EQ("aaaa\\xff", humanify(string("aaaa\xff")));
1066 EXPECT_EQ("aaa\\xff\\xff", humanify(string("aaa\xff\xff")));
1067 EXPECT_EQ("aa\\xff\\xff\\xff", humanify(string("aa\xff\xff\xff")));
1069 // 20% printable, and the printable portion isn't the prefix; hexify!
1070 EXPECT_EQ("0xff61ffffff", humanify(string("\xff" "a\xff\xff\xff")));
1072 // Same as previous, except swap first two chars; prefix is
1073 // printable and within the threshold, so backslashify.
1074 EXPECT_EQ("a\\xff\\xff\\xff\\xff", humanify(string("a\xff\xff\xff\xff")));
1076 // Just too much unprintable; hex, despite prefix.
1077 EXPECT_EQ("0x61ffffffffff", humanify(string("a\xff\xff\xff\xff\xff")));
1083 * Copy bytes from src to somewhere in the buffer referenced by dst. The
1084 * actual starting position of the copy will be the first address in the
1085 * destination buffer whose address mod 8 is equal to the src address mod 8.
1086 * The caller is responsible for ensuring that the destination buffer has
1087 * enough extra space to accommodate the shifted copy.
1089 char* copyWithSameAlignment(char* dst, const char* src, size_t length) {
1090 const char* originalDst = dst;
1091 size_t dstOffset = size_t(dst) & 0x7;
1092 size_t srcOffset = size_t(src) & 0x7;
1093 while (dstOffset != srcOffset) {
1098 CHECK(dst <= originalDst + 7);
1099 CHECK((size_t(dst) & 0x7) == (size_t(src) & 0x7));
1100 memcpy(dst, src, length);
1104 void testToLowerAscii(Range<const char*> src) {
1105 // Allocate extra space so we can make copies that start at the
1106 // same alignment (byte, word, quadword, etc) as the source buffer.
1107 char controlBuf[src.size() + 7];
1108 char* control = copyWithSameAlignment(controlBuf, src.begin(), src.size());
1110 char testBuf[src.size() + 7];
1111 char* test = copyWithSameAlignment(testBuf, src.begin(), src.size());
1113 for (size_t i = 0; i < src.size(); i++) {
1114 control[i] = tolower(control[i]);
1116 toLowerAscii(test, src.size());
1117 for (size_t i = 0; i < src.size(); i++) {
1118 EXPECT_EQ(control[i], test[i]);
1124 TEST(String, toLowerAsciiAligned) {
1125 static const size_t kSize = 256;
1127 for (size_t i = 0; i < kSize; i++) {
1128 input[i] = (char)(i & 0xff);
1130 testToLowerAscii(Range<const char*>(input, kSize));
1133 TEST(String, toLowerAsciiUnaligned) {
1134 static const size_t kSize = 256;
1136 for (size_t i = 0; i < kSize; i++) {
1137 input[i] = (char)(i & 0xff);
1139 // Test input buffers of several lengths to exercise all the
1140 // cases: buffer at the start/middle/end of an aligned block, plus
1141 // buffers that span multiple aligned blocks. The longest test input
1142 // is 3 unaligned bytes + 4 32-bit aligned bytes + 8 64-bit aligned
1143 // + 4 32-bit aligned + 3 unaligned = 22 bytes.
1144 for (size_t length = 1; length < 23; length++) {
1145 for (size_t offset = 0; offset + length <= kSize; offset++) {
1146 testToLowerAscii(Range<const char*>(input + offset, length));
1151 //////////////////////////////////////////////////////////////////////
1153 BENCHMARK(splitOnSingleChar, iters) {
1154 static const std::string line = "one:two:three:four";
1155 for (int i = 0; i < iters << 4; ++i) {
1156 std::vector<StringPiece> pieces;
1157 folly::split(':', line, pieces);
1161 BENCHMARK(splitOnSingleCharFixed, iters) {
1162 static const std::string line = "one:two:three:four";
1163 for (int i = 0; i < iters << 4; ++i) {
1164 StringPiece a, b, c, d;
1165 folly::split(':', line, a, b, c, d);
1169 BENCHMARK(splitOnSingleCharFixedAllowExtra, iters) {
1170 static const std::string line = "one:two:three:four";
1171 for (int i = 0; i < iters << 4; ++i) {
1172 StringPiece a, b, c, d;
1173 folly::split<false>(':', line, a, b, c, d);
1177 BENCHMARK(splitStr, iters) {
1178 static const std::string line = "one-*-two-*-three-*-four";
1179 for (int i = 0; i < iters << 4; ++i) {
1180 std::vector<StringPiece> pieces;
1181 folly::split("-*-", line, pieces);
1185 BENCHMARK(splitStrFixed, iters) {
1186 static const std::string line = "one-*-two-*-three-*-four";
1187 for (int i = 0; i < iters << 4; ++i) {
1188 StringPiece a, b, c, d;
1189 folly::split("-*-", line, a, b, c, d);
1193 BENCHMARK(boost_splitOnSingleChar, iters) {
1194 static const std::string line = "one:two:three:four";
1195 bool(*pred)(char) = [] (char c) -> bool { return c == ':'; };
1196 for (int i = 0; i < iters << 4; ++i) {
1197 std::vector<boost::iterator_range<std::string::const_iterator> > pieces;
1198 boost::split(pieces, line, pred);
1202 BENCHMARK(joinCharStr, iters) {
1203 static const std::vector<std::string> input = {
1204 "one", "two", "three", "four", "five", "six", "seven" };
1205 for (int i = 0; i < iters << 4; ++i) {
1207 folly::join(':', input, output);
1211 BENCHMARK(joinStrStr, iters) {
1212 static const std::vector<std::string> input = {
1213 "one", "two", "three", "four", "five", "six", "seven" };
1214 for (int i = 0; i < iters << 4; ++i) {
1216 folly::join(":", input, output);
1220 BENCHMARK(joinInt, iters) {
1221 static const auto input = {
1222 123, 456, 78910, 1112, 1314, 151, 61718 };
1223 for (int i = 0; i < iters << 4; ++i) {
1225 folly::join(":", input, output);
1229 int main(int argc, char *argv[]) {
1230 testing::InitGoogleTest(&argc, argv);
1231 gflags::ParseCommandLineFlags(&argc, &argv, true);
1232 auto ret = RUN_ALL_TESTS();
1235 if (FLAGS_benchmark) {
1236 folly::runBenchmarks();