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