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