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