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