proxygen
StringTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present 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 #ifndef __STDC_FORMAT_MACROS
18 #define __STDC_FORMAT_MACROS 1
19 #endif
20 
21 #include <folly/String.h>
22 #include <tuple>
23 
24 #include <cinttypes>
25 #include <set>
26 
27 #include <boost/regex.hpp>
28 
29 #include <folly/container/Array.h>
31 #include <folly/test/TestUtils.h>
32 
33 using namespace folly;
34 using namespace std;
35 
36 TEST(StringPrintf, BasicTest) {
37  EXPECT_EQ("abc", stringPrintf("%s", "abc"));
38  EXPECT_EQ("abc", stringPrintf("%sbc", "a"));
39  EXPECT_EQ("abc", stringPrintf("a%sc", "b"));
40  EXPECT_EQ("abc", stringPrintf("ab%s", "c"));
41 
42  EXPECT_EQ("abc", stringPrintf("abc"));
43 }
44 
45 TEST(StringPrintf, NumericFormats) {
46  EXPECT_EQ("12", stringPrintf("%d", 12));
47  EXPECT_EQ("2000000000", stringPrintf("%ld", 2000000000UL));
48  EXPECT_EQ("2000000000", stringPrintf("%ld", 2000000000L));
49  EXPECT_EQ("-2000000000", stringPrintf("%ld", -2000000000L));
50  EXPECT_EQ("5000000000", stringPrintf("%lld", 5000000000ULL));
51  EXPECT_EQ("5000000000", stringPrintf("%lld", 5000000000LL));
52  EXPECT_EQ("-5000000000", stringPrintf("%lld", -5000000000LL));
53  EXPECT_EQ("-1", stringPrintf("%d", 0xffffffff));
54  EXPECT_EQ(
55  "-1",
56  stringPrintf("%" PRId64, static_cast<int64_t>(0xffffffffffffffffLL)));
57  EXPECT_EQ(
58  "-1",
59  stringPrintf("%" PRId64, static_cast<uint64_t>(0xffffffffffffffffULL)));
60 
61  EXPECT_EQ("7.7", stringPrintf("%1.1f", 7.7));
62  EXPECT_EQ("7.7", stringPrintf("%1.1lf", 7.7));
63  EXPECT_EQ("7.70000000000000018", stringPrintf("%.17f", 7.7));
64  EXPECT_EQ("7.70000000000000018", stringPrintf("%.17lf", 7.7));
65 }
66 
67 TEST(StringPrintf, Appending) {
68  string s;
69  stringAppendf(&s, "a%s", "b");
70  stringAppendf(&s, "%c", 'c');
71  EXPECT_EQ(s, "abc");
72  stringAppendf(&s, " %d", 123);
73  EXPECT_EQ(s, "abc 123");
74 }
75 
76 void vprintfCheck(const char* expected, const char* fmt, ...) {
77  va_list apOrig;
78  va_start(apOrig, fmt);
79  SCOPE_EXIT {
80  va_end(apOrig);
81  };
82  va_list ap;
83  va_copy(ap, apOrig);
84  SCOPE_EXIT {
85  va_end(ap);
86  };
87 
88  // Check both APIs for calling stringVPrintf()
89  EXPECT_EQ(expected, stringVPrintf(fmt, ap));
90  va_end(ap);
91  va_copy(ap, apOrig);
92 
93  std::string out;
94  stringVPrintf(&out, fmt, ap);
95  va_end(ap);
96  va_copy(ap, apOrig);
97  EXPECT_EQ(expected, out);
98 
99  // Check stringVAppendf() as well
100  std::string prefix = "foobar";
101  out = prefix;
102  EXPECT_EQ(prefix + expected, stringVAppendf(&out, fmt, ap));
103  va_end(ap);
104  va_copy(ap, apOrig);
105 }
106 
107 void vprintfError(const char* fmt, ...) {
108  va_list ap;
109  va_start(ap, fmt);
110  SCOPE_EXIT {
111  va_end(ap);
112  };
113 
114 #ifdef HAVE_VSNPRINTF_ERRORS
115  // OSX's sprintf family does not return a negative number on a bad format
116  // string, but Linux does. It's unclear to me which behavior is more
117  // correct.
118  EXPECT_THROW({ stringVPrintf(fmt, ap); }, std::runtime_error);
119 #endif
120 }
121 
122 TEST(StringPrintf, VPrintf) {
123  vprintfCheck("foo", "%s", "foo");
124  vprintfCheck(
125  "long string requiring reallocation 1 2 3 0x12345678",
126  "%s %s %d %d %d %#x",
127  "long string",
128  "requiring reallocation",
129  1,
130  2,
131  3,
132  0x12345678);
133  vprintfError("bogus%", "foo");
134 }
135 
136 TEST(StringPrintf, VariousSizes) {
137  // Test a wide variety of output sizes, making sure to cross the
138  // vsnprintf buffer boundary implementation detail.
139  for (int i = 0; i < 4096; ++i) {
140  string expected(i + 1, 'a');
141  expected = "X" + expected + "X";
142  string result = stringPrintf("%s", expected.c_str());
143  EXPECT_EQ(expected.size(), result.size());
144  EXPECT_EQ(expected, result);
145  }
146 
147  // clang-format off
148  EXPECT_EQ("abc12345678910111213141516171819202122232425xyz",
149  stringPrintf("abc%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
150  "%d%d%d%d%d%d%d%d%d%d%dxyz",
151  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
152  17, 18, 19, 20, 21, 22, 23, 24, 25));
153  // clang-format on
154 }
155 
156 TEST(StringPrintf, oldStringPrintfTests) {
157  EXPECT_EQ(string("a/b/c/d"), stringPrintf("%s/%s/%s/%s", "a", "b", "c", "d"));
158 
159  EXPECT_EQ(string(" 5 10"), stringPrintf("%5d %5d", 5, 10));
160 
161  // check printing w/ a big buffer
162  for (int size = (1 << 8); size <= (1 << 15); size <<= 1) {
163  string a(size, 'z');
164  string b = stringPrintf("%s", a.c_str());
165  EXPECT_EQ(a.size(), b.size());
166  }
167 }
168 
169 TEST(StringPrintf, oldStringAppendf) {
170  string s = "hello";
171  stringAppendf(&s, "%s/%s/%s/%s", "a", "b", "c", "d");
172  EXPECT_EQ(string("helloa/b/c/d"), s);
173 }
174 
175 TEST(Escape, cEscape) {
176  EXPECT_EQ("hello world", cEscape<std::string>("hello world"));
177  EXPECT_EQ(
178  "hello \\\\world\\\" goodbye",
179  cEscape<std::string>("hello \\world\" goodbye"));
180  EXPECT_EQ("hello\\nworld", cEscape<std::string>("hello\nworld"));
181  EXPECT_EQ("hello\\377\\376", cEscape<std::string>("hello\xff\xfe"));
182 }
183 
184 TEST(Escape, cUnescape) {
185  EXPECT_EQ("hello world", cUnescape<std::string>("hello world"));
186  EXPECT_EQ(
187  "hello \\world\" goodbye",
188  cUnescape<std::string>("hello \\\\world\\\" goodbye"));
189  EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\nworld"));
190  EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\012world"));
191  EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\x0aworld"));
192  EXPECT_EQ("hello\xff\xfe", cUnescape<std::string>("hello\\377\\376"));
193  EXPECT_EQ("hello\xff\xfe", cUnescape<std::string>("hello\\xff\\xfe"));
194  EXPECT_EQ("hello\\", cUnescape<std::string>("hello\\", false));
195 
197  cUnescape<std::string>("hello\\"),
198  std::invalid_argument,
199  "incomplete escape sequence");
201  cUnescape<std::string>("hello\\x"),
202  std::invalid_argument,
203  "incomplete hex escape sequence");
205  cUnescape<std::string>("hello\\q"),
206  std::invalid_argument,
207  "invalid escape sequence");
208 }
209 
210 TEST(Escape, uriEscape) {
211  EXPECT_EQ("hello%2c%20%2fworld", uriEscape<std::string>("hello, /world"));
212  EXPECT_EQ(
213  "hello%2c%20/world",
214  uriEscape<std::string>("hello, /world", UriEscapeMode::PATH));
215  EXPECT_EQ(
216  "hello%2c+%2fworld",
217  uriEscape<std::string>("hello, /world", UriEscapeMode::QUERY));
218  EXPECT_EQ(
219  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~",
220  uriEscape<std::string>(
221  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~"));
222 }
223 
224 TEST(Escape, uriUnescape) {
225  EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello, /world"));
226  EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello%2c%20%2fworld"));
227  EXPECT_EQ("hello,+/world", uriUnescape<std::string>("hello%2c+%2fworld"));
228  EXPECT_EQ(
229  "hello, /world",
230  uriUnescape<std::string>("hello%2c+%2fworld", UriEscapeMode::QUERY));
231  EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2f"));
232  EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2F"));
233  EXPECT_THROW({ uriUnescape<std::string>("hello%"); }, std::invalid_argument);
234  EXPECT_THROW({ uriUnescape<std::string>("hello%2"); }, std::invalid_argument);
235  EXPECT_THROW(
236  { uriUnescape<std::string>("hello%2g"); }, std::invalid_argument);
237 }
238 
239 namespace {
240 void expectPrintable(StringPiece s) {
241  for (char c : s) {
242  EXPECT_LE(32, c);
243  EXPECT_GE(127, c);
244  }
245 }
246 } // namespace
247 
248 TEST(Escape, uriEscapeAllCombinations) {
249  char c[3];
250  c[2] = '\0';
251  StringPiece in(c, 2);
252  fbstring tmp;
253  fbstring out;
254  for (int i = 0; i < 256; ++i) {
255  c[0] = i;
256  for (int j = 0; j < 256; ++j) {
257  c[1] = j;
258  tmp.clear();
259  out.clear();
260  uriEscape(in, tmp);
261  expectPrintable(tmp);
262  uriUnescape(tmp, out);
263  EXPECT_EQ(in, out);
264  }
265  }
266 }
267 
268 namespace {
269 bool isHex(int v) {
270  return (
271  (v >= '0' && v <= '9') || (v >= 'A' && v <= 'F') ||
272  (v >= 'a' && v <= 'f'));
273 }
274 } // namespace
275 
276 TEST(Escape, uriUnescapePercentDecoding) {
277  char c[4] = {'%', '\0', '\0', '\0'};
278  StringPiece in(c, 3);
279  fbstring out;
280  unsigned int expected = 0;
281  for (int i = 0; i < 256; ++i) {
282  c[1] = i;
283  for (int j = 0; j < 256; ++j) {
284  c[2] = j;
285  if (isHex(i) && isHex(j)) {
286  out.clear();
287  uriUnescape(in, out);
288  EXPECT_EQ(1, out.size());
289  EXPECT_EQ(1, sscanf(c + 1, "%x", &expected));
290  unsigned char v = out[0];
291  EXPECT_EQ(expected, v);
292  } else {
293  EXPECT_THROW({ uriUnescape(in, out); }, std::invalid_argument);
294  }
295  }
296  }
297 }
298 
299 namespace {
300 
301 double pow2(int exponent) {
302  return double(int64_t(1) << exponent);
303 }
304 
305 } // namespace
306 
309  double realValue;
311 };
312 
314  {string("853 ms"), 85.3e-2, PRETTY_TIME_HMS},
315  {string("8.53 s "), 85.3e-1, PRETTY_TIME_HMS},
316  {string("1.422 m "), 85.3, PRETTY_TIME_HMS},
317  {string("14.22 m "), 85.3e1, PRETTY_TIME_HMS},
318  {string("2.369 h "), 85.3e2, PRETTY_TIME_HMS},
319  {string("2.369e+04 h "), 85.3e6, PRETTY_TIME_HMS},
320 
321  {string("8.53e+07 s "), 85.3e6, PRETTY_TIME},
322  {string("8.53e+07 s "), 85.3e6, PRETTY_TIME},
323  {string("85.3 ms"), 85.3e-3, PRETTY_TIME},
324  {string("85.3 us"), 85.3e-6, PRETTY_TIME},
325  {string("85.3 ns"), 85.3e-9, PRETTY_TIME},
326  {string("85.3 ps"), 85.3e-12, PRETTY_TIME},
327  {string("8.53e-14 s "), 85.3e-15, PRETTY_TIME},
328 
329  {string("0 s "), 0, PRETTY_TIME},
330  {string("1 s "), 1.0, PRETTY_TIME},
331  {string("1 ms"), 1.0e-3, PRETTY_TIME},
332  {string("1 us"), 1.0e-6, PRETTY_TIME},
333  {string("1 ns"), 1.0e-9, PRETTY_TIME},
334  {string("1 ps"), 1.0e-12, PRETTY_TIME},
335 
336  // check bytes printing
337  {string("853 B "), 853., PRETTY_BYTES},
338  {string("833 kB"), 853.e3, PRETTY_BYTES},
339  {string("813.5 MB"), 853.e6, PRETTY_BYTES},
340  {string("7.944 GB"), 8.53e9, PRETTY_BYTES},
341  {string("794.4 GB"), 853.e9, PRETTY_BYTES},
342  {string("775.8 TB"), 853.e12, PRETTY_BYTES},
343 
344  {string("0 B "), 0, PRETTY_BYTES},
345  {string("1 B "), pow2(0), PRETTY_BYTES},
346  {string("1 kB"), pow2(10), PRETTY_BYTES},
347  {string("1 MB"), pow2(20), PRETTY_BYTES},
348  {string("1 GB"), pow2(30), PRETTY_BYTES},
349  {string("1 TB"), pow2(40), PRETTY_BYTES},
350  {string("1 PB"), pow2(50), PRETTY_BYTES},
351  {string("1 EB"), pow2(60), PRETTY_BYTES},
352 
353  {string("853 B "), 853., PRETTY_BYTES_IEC},
354  {string("833 KiB"), 853.e3, PRETTY_BYTES_IEC},
355  {string("813.5 MiB"), 853.e6, PRETTY_BYTES_IEC},
356  {string("7.944 GiB"), 8.53e9, PRETTY_BYTES_IEC},
357  {string("794.4 GiB"), 853.e9, PRETTY_BYTES_IEC},
358  {string("775.8 TiB"), 853.e12, PRETTY_BYTES_IEC},
359  {string("1.776 PiB"), 2e15, PRETTY_BYTES_IEC},
360  {string("1.735 EiB"), 2e18, PRETTY_BYTES_IEC},
361 
362  {string("0 B "), 0, PRETTY_BYTES_IEC},
363  {string("1 B "), pow2(0), PRETTY_BYTES_IEC},
364  {string("1 KiB"), pow2(10), PRETTY_BYTES_IEC},
365  {string("1 MiB"), pow2(20), PRETTY_BYTES_IEC},
366  {string("1 GiB"), pow2(30), PRETTY_BYTES_IEC},
367  {string("1 TiB"), pow2(40), PRETTY_BYTES_IEC},
368  {string("1 PiB"), pow2(50), PRETTY_BYTES_IEC},
369  {string("1 EiB"), pow2(60), PRETTY_BYTES_IEC},
370 
371  // check bytes metric printing
372  {string("853 B "), 853., PRETTY_BYTES_METRIC},
373  {string("853 kB"), 853.e3, PRETTY_BYTES_METRIC},
374  {string("853 MB"), 853.e6, PRETTY_BYTES_METRIC},
375  {string("8.53 GB"), 8.53e9, PRETTY_BYTES_METRIC},
376  {string("853 GB"), 853.e9, PRETTY_BYTES_METRIC},
377  {string("853 TB"), 853.e12, PRETTY_BYTES_METRIC},
378 
379  {string("0 B "), 0, PRETTY_BYTES_METRIC},
380  {string("1 B "), 1.0, PRETTY_BYTES_METRIC},
381  {string("1 kB"), 1.0e+3, PRETTY_BYTES_METRIC},
382  {string("1 MB"), 1.0e+6, PRETTY_BYTES_METRIC},
383  {string("1 GB"), 1.0e+9, PRETTY_BYTES_METRIC},
384  {string("1 TB"), 1.0e+12, PRETTY_BYTES_METRIC},
385  {string("1 PB"), 1.0e+15, PRETTY_BYTES_METRIC},
386  {string("1 EB"), 1.0e+18, PRETTY_BYTES_METRIC},
387 
388  // check metric-units (powers of 1000) printing
389  {string("853 "), 853., PRETTY_UNITS_METRIC},
390  {string("853 k"), 853.e3, PRETTY_UNITS_METRIC},
391  {string("853 M"), 853.e6, PRETTY_UNITS_METRIC},
392  {string("8.53 bil"), 8.53e9, PRETTY_UNITS_METRIC},
393  {string("853 bil"), 853.e9, PRETTY_UNITS_METRIC},
394  {string("853 tril"), 853.e12, PRETTY_UNITS_METRIC},
395 
396  // check binary-units (powers of 1024) printing
397  {string("0 "), 0, PRETTY_UNITS_BINARY},
398  {string("1 "), pow2(0), PRETTY_UNITS_BINARY},
399  {string("1 k"), pow2(10), PRETTY_UNITS_BINARY},
400  {string("1 M"), pow2(20), PRETTY_UNITS_BINARY},
401  {string("1 G"), pow2(30), PRETTY_UNITS_BINARY},
402  {string("1 T"), pow2(40), PRETTY_UNITS_BINARY},
403 
404  {string("1023 "), pow2(10) - 1, PRETTY_UNITS_BINARY},
405  {string("1024 k"), pow2(20) - 1, PRETTY_UNITS_BINARY},
406  {string("1024 M"), pow2(30) - 1, PRETTY_UNITS_BINARY},
407  {string("1024 G"), pow2(40) - 1, PRETTY_UNITS_BINARY},
408 
409  {string("0 "), 0, PRETTY_UNITS_BINARY_IEC},
410  {string("1 "), pow2(0), PRETTY_UNITS_BINARY_IEC},
411  {string("1 Ki"), pow2(10), PRETTY_UNITS_BINARY_IEC},
412  {string("1 Mi"), pow2(20), PRETTY_UNITS_BINARY_IEC},
413  {string("1 Gi"), pow2(30), PRETTY_UNITS_BINARY_IEC},
414  {string("1 Ti"), pow2(40), PRETTY_UNITS_BINARY_IEC},
415 
416  {string("1023 "), pow2(10) - 1, PRETTY_UNITS_BINARY_IEC},
417  {string("1024 Ki"), pow2(20) - 1, PRETTY_UNITS_BINARY_IEC},
418  {string("1024 Mi"), pow2(30) - 1, PRETTY_UNITS_BINARY_IEC},
419  {string("1024 Gi"), pow2(40) - 1, PRETTY_UNITS_BINARY_IEC},
420 
421  // check border SI cases
422 
423  {string("1 Y"), 1e24, PRETTY_SI},
424  {string("10 Y"), 1e25, PRETTY_SI},
425  {string("1 y"), 1e-24, PRETTY_SI},
426  {string("10 y"), 1e-23, PRETTY_SI},
427 
428  // check that negative values work
429  {string("-85.3 s "), -85.3, PRETTY_TIME},
430  {string("-85.3 ms"), -85.3e-3, PRETTY_TIME},
431  {string("-85.3 us"), -85.3e-6, PRETTY_TIME},
432  {string("-85.3 ns"), -85.3e-9, PRETTY_TIME},
433 
434  // end of test
435  {string("endoftest"), 0, PRETTY_NUM_TYPES},
436 };
437 
438 TEST(PrettyPrint, Basic) {
439  for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i) {
440  const PrettyTestCase& prettyTest = prettyTestCases[i];
441  EXPECT_EQ(
442  prettyTest.prettyString,
443  prettyPrint(prettyTest.realValue, prettyTest.prettyType));
444  }
445 }
446 
447 TEST(PrettyToDouble, Basic) {
448  // check manually created tests
449  for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i) {
450  PrettyTestCase testCase = prettyTestCases[i];
451  PrettyType formatType = testCase.prettyType;
452  double x = testCase.realValue;
453  std::string testString = testCase.prettyString;
454  double recoveredX = 0;
455  try {
456  recoveredX = prettyToDouble(testString, formatType);
457  } catch (const std::exception& ex) {
458  ADD_FAILURE() << testCase.prettyString << " -> " << ex.what();
459  }
460  double relativeError =
461  fabs(x) < 1e-5 ? (x - recoveredX) : (x - recoveredX) / x;
462  EXPECT_NEAR(0, relativeError, 1e-3);
463  }
464 
465  // checks for compatibility with prettyPrint over the whole parameter space
466  for (int i = 0; i < PRETTY_NUM_TYPES; ++i) {
467  PrettyType formatType = static_cast<PrettyType>(i);
468  for (double x = 1e-18; x < 1e40; x *= 1.9) {
469  bool addSpace = static_cast<PrettyType>(i) == PRETTY_SI;
470  for (int it = 0; it < 2; ++it, addSpace = true) {
471  double recoveredX = 0;
472  try {
473  recoveredX =
474  prettyToDouble(prettyPrint(x, formatType, addSpace), formatType);
475  } catch (const std::exception& ex) {
477  }
478  double relativeError = (x - recoveredX) / x;
479  EXPECT_NEAR(0, relativeError, 1e-3);
480  }
481  }
482  }
483 
484  // check for incorrect values
485  EXPECT_THROW(prettyToDouble("10Mx", PRETTY_SI), std::range_error);
486  EXPECT_THROW(prettyToDouble("10 Mx", PRETTY_SI), std::range_error);
487  EXPECT_THROW(prettyToDouble("10 M x", PRETTY_SI), std::range_error);
488 
489  StringPiece testString = "10Mx";
491  EXPECT_EQ(testString, "x");
492 }
493 
494 TEST(PrettyPrint, HexDump) {
495  std::string a("abc\x00\x02\xa0", 6); // embedded NUL
496  EXPECT_EQ(
497  "00000000 61 62 63 00 02 a0 "
498  "|abc... |\n",
499  hexDump(a.data(), a.size()));
500 
501  a = "abcdefghijklmnopqrstuvwxyz";
502  EXPECT_EQ(
503  "00000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 "
504  "|abcdefghijklmnop|\n"
505  "00000010 71 72 73 74 75 76 77 78 79 7a "
506  "|qrstuvwxyz |\n",
507  hexDump(a.data(), a.size()));
508 }
509 
510 TEST(System, errnoStr) {
511  errno = EACCES;
512  EXPECT_EQ(EACCES, errno);
513  EXPECT_EQ(EACCES, errno); // twice to make sure EXPECT_EQ doesn't change it
514 
515  fbstring expected = strerror(ENOENT);
516 
517  errno = EACCES;
518  EXPECT_EQ(expected, errnoStr(ENOENT));
519  // Ensure that errno isn't changed
520  EXPECT_EQ(EACCES, errno);
521 
522  // Per POSIX, all errno values are positive, so -1 is invalid
523  errnoStr(-1);
524 
525  // Ensure that errno isn't changed
526  EXPECT_EQ(EACCES, errno);
527 }
528 
529 namespace {
530 
531 template <template <class, class> class VectorType>
532 void splitTest() {
533  VectorType<string, std::allocator<string>> parts;
534 
535  folly::split(',', "a,b,c", parts);
536  EXPECT_EQ(parts.size(), 3);
537  EXPECT_EQ(parts[0], "a");
538  EXPECT_EQ(parts[1], "b");
539  EXPECT_EQ(parts[2], "c");
540  parts.clear();
541 
542  folly::split(',', StringPiece("a,b,c"), parts);
543  EXPECT_EQ(parts.size(), 3);
544  EXPECT_EQ(parts[0], "a");
545  EXPECT_EQ(parts[1], "b");
546  EXPECT_EQ(parts[2], "c");
547  parts.clear();
548 
549  folly::split(',', string("a,b,c"), parts);
550  EXPECT_EQ(parts.size(), 3);
551  EXPECT_EQ(parts[0], "a");
552  EXPECT_EQ(parts[1], "b");
553  EXPECT_EQ(parts[2], "c");
554  parts.clear();
555 
556  folly::split(',', "a,,c", parts);
557  EXPECT_EQ(parts.size(), 3);
558  EXPECT_EQ(parts[0], "a");
559  EXPECT_EQ(parts[1], "");
560  EXPECT_EQ(parts[2], "c");
561  parts.clear();
562 
563  folly::split(',', string("a,,c"), parts);
564  EXPECT_EQ(parts.size(), 3);
565  EXPECT_EQ(parts[0], "a");
566  EXPECT_EQ(parts[1], "");
567  EXPECT_EQ(parts[2], "c");
568  parts.clear();
569 
570  folly::split(',', "a,,c", parts, true);
571  EXPECT_EQ(parts.size(), 2);
572  EXPECT_EQ(parts[0], "a");
573  EXPECT_EQ(parts[1], "c");
574  parts.clear();
575 
576  folly::split(',', string("a,,c"), parts, true);
577  EXPECT_EQ(parts.size(), 2);
578  EXPECT_EQ(parts[0], "a");
579  EXPECT_EQ(parts[1], "c");
580  parts.clear();
581 
582  folly::split(',', string(",,a,,c,,,"), parts, true);
583  EXPECT_EQ(parts.size(), 2);
584  EXPECT_EQ(parts[0], "a");
585  EXPECT_EQ(parts[1], "c");
586  parts.clear();
587 
588  // test multiple split w/o clear
589  folly::split(',', ",,a,,c,,,", parts, true);
590  EXPECT_EQ(parts.size(), 2);
591  EXPECT_EQ(parts[0], "a");
592  EXPECT_EQ(parts[1], "c");
593  folly::split(',', ",,a,,c,,,", parts, true);
594  EXPECT_EQ(parts.size(), 4);
595  EXPECT_EQ(parts[2], "a");
596  EXPECT_EQ(parts[3], "c");
597  parts.clear();
598 
599  // test splits that with multi-line delimiter
600  folly::split("ab", "dabcabkdbkab", parts, true);
601  EXPECT_EQ(parts.size(), 3);
602  EXPECT_EQ(parts[0], "d");
603  EXPECT_EQ(parts[1], "c");
604  EXPECT_EQ(parts[2], "kdbk");
605  parts.clear();
606 
607  // test last part is shorter than the delimiter
608  folly::split("bc", "abcd", parts, true);
609  EXPECT_EQ(parts.size(), 2);
610  EXPECT_EQ(parts[0], "a");
611  EXPECT_EQ(parts[1], "d");
612  parts.clear();
613 
614  string orig = "ab2342asdfv~~!";
615  folly::split("", orig, parts, true);
616  EXPECT_EQ(parts.size(), 1);
617  EXPECT_EQ(parts[0], orig);
618  parts.clear();
619 
620  folly::split("452x;o38asfsajsdlfdf.j", "asfds", parts, true);
621  EXPECT_EQ(parts.size(), 1);
622  EXPECT_EQ(parts[0], "asfds");
623  parts.clear();
624 
625  folly::split("a", "", parts, true);
626  EXPECT_EQ(parts.size(), 0);
627  parts.clear();
628 
629  folly::split("a", "", parts);
630  EXPECT_EQ(parts.size(), 1);
631  EXPECT_EQ(parts[0], "");
632  parts.clear();
633 
634  folly::split("a", StringPiece(), parts, true);
635  EXPECT_EQ(parts.size(), 0);
636  parts.clear();
637 
638  folly::split("a", StringPiece(), parts);
639  EXPECT_EQ(parts.size(), 1);
640  EXPECT_EQ(parts[0], "");
641  parts.clear();
642 
643  folly::split("a", "abcdefg", parts, true);
644  EXPECT_EQ(parts.size(), 1);
645  EXPECT_EQ(parts[0], "bcdefg");
646  parts.clear();
647 
648  orig = "All, , your base, are , , belong to us";
649  folly::split(", ", orig, parts, true);
650  EXPECT_EQ(parts.size(), 4);
651  EXPECT_EQ(parts[0], "All");
652  EXPECT_EQ(parts[1], "your base");
653  EXPECT_EQ(parts[2], "are ");
654  EXPECT_EQ(parts[3], "belong to us");
655  parts.clear();
656  folly::split(", ", orig, parts);
657  EXPECT_EQ(parts.size(), 6);
658  EXPECT_EQ(parts[0], "All");
659  EXPECT_EQ(parts[1], "");
660  EXPECT_EQ(parts[2], "your base");
661  EXPECT_EQ(parts[3], "are ");
662  EXPECT_EQ(parts[4], "");
663  EXPECT_EQ(parts[5], "belong to us");
664  parts.clear();
665 
666  orig = ", Facebook, rul,es!, ";
667  folly::split(", ", orig, parts, true);
668  EXPECT_EQ(parts.size(), 2);
669  EXPECT_EQ(parts[0], "Facebook");
670  EXPECT_EQ(parts[1], "rul,es!");
671  parts.clear();
672  folly::split(", ", orig, parts);
673  EXPECT_EQ(parts.size(), 4);
674  EXPECT_EQ(parts[0], "");
675  EXPECT_EQ(parts[1], "Facebook");
676  EXPECT_EQ(parts[2], "rul,es!");
677  EXPECT_EQ(parts[3], "");
678 }
679 
680 template <template <class, class> class VectorType>
681 void piecesTest() {
682  VectorType<StringPiece, std::allocator<StringPiece>> pieces;
683  VectorType<StringPiece, std::allocator<StringPiece>> pieces2;
684 
685  folly::split(',', "a,b,c", pieces);
686  EXPECT_EQ(pieces.size(), 3);
687  EXPECT_EQ(pieces[0], "a");
688  EXPECT_EQ(pieces[1], "b");
689  EXPECT_EQ(pieces[2], "c");
690 
691  pieces.clear();
692 
693  folly::split(',', "a,,c", pieces);
694  EXPECT_EQ(pieces.size(), 3);
695  EXPECT_EQ(pieces[0], "a");
696  EXPECT_EQ(pieces[1], "");
697  EXPECT_EQ(pieces[2], "c");
698  pieces.clear();
699 
700  folly::split(',', "a,,c", pieces, true);
701  EXPECT_EQ(pieces.size(), 2);
702  EXPECT_EQ(pieces[0], "a");
703  EXPECT_EQ(pieces[1], "c");
704  pieces.clear();
705 
706  folly::split(',', ",,a,,c,,,", pieces, true);
707  EXPECT_EQ(pieces.size(), 2);
708  EXPECT_EQ(pieces[0], "a");
709  EXPECT_EQ(pieces[1], "c");
710  pieces.clear();
711 
712  // test multiple split w/o clear
713  folly::split(',', ",,a,,c,,,", pieces, true);
714  EXPECT_EQ(pieces.size(), 2);
715  EXPECT_EQ(pieces[0], "a");
716  EXPECT_EQ(pieces[1], "c");
717  folly::split(',', ",,a,,c,,,", pieces, true);
718  EXPECT_EQ(pieces.size(), 4);
719  EXPECT_EQ(pieces[2], "a");
720  EXPECT_EQ(pieces[3], "c");
721  pieces.clear();
722 
723  // test multiple split rounds
724  folly::split(",", "a_b,c_d", pieces);
725  EXPECT_EQ(pieces.size(), 2);
726  EXPECT_EQ(pieces[0], "a_b");
727  EXPECT_EQ(pieces[1], "c_d");
728  folly::split("_", pieces[0], pieces2);
729  EXPECT_EQ(pieces2.size(), 2);
730  EXPECT_EQ(pieces2[0], "a");
731  EXPECT_EQ(pieces2[1], "b");
732  pieces2.clear();
733  folly::split("_", pieces[1], pieces2);
734  EXPECT_EQ(pieces2.size(), 2);
735  EXPECT_EQ(pieces2[0], "c");
736  EXPECT_EQ(pieces2[1], "d");
737  pieces.clear();
738  pieces2.clear();
739 
740  // test splits that with multi-line delimiter
741  folly::split("ab", "dabcabkdbkab", pieces, true);
742  EXPECT_EQ(pieces.size(), 3);
743  EXPECT_EQ(pieces[0], "d");
744  EXPECT_EQ(pieces[1], "c");
745  EXPECT_EQ(pieces[2], "kdbk");
746  pieces.clear();
747 
748  string orig = "ab2342asdfv~~!";
749  folly::split("", orig.c_str(), pieces, true);
750  EXPECT_EQ(pieces.size(), 1);
751  EXPECT_EQ(pieces[0], orig);
752  pieces.clear();
753 
754  folly::split("452x;o38asfsajsdlfdf.j", "asfds", pieces, true);
755  EXPECT_EQ(pieces.size(), 1);
756  EXPECT_EQ(pieces[0], "asfds");
757  pieces.clear();
758 
759  folly::split("a", "", pieces, true);
760  EXPECT_EQ(pieces.size(), 0);
761  pieces.clear();
762 
763  folly::split("a", "", pieces);
764  EXPECT_EQ(pieces.size(), 1);
765  EXPECT_EQ(pieces[0], "");
766  pieces.clear();
767 
768  folly::split("a", "abcdefg", pieces, true);
769  EXPECT_EQ(pieces.size(), 1);
770  EXPECT_EQ(pieces[0], "bcdefg");
771  pieces.clear();
772 
773  orig = "All, , your base, are , , belong to us";
774  folly::split(", ", orig, pieces, true);
775  EXPECT_EQ(pieces.size(), 4);
776  EXPECT_EQ(pieces[0], "All");
777  EXPECT_EQ(pieces[1], "your base");
778  EXPECT_EQ(pieces[2], "are ");
779  EXPECT_EQ(pieces[3], "belong to us");
780  pieces.clear();
781  folly::split(", ", orig, pieces);
782  EXPECT_EQ(pieces.size(), 6);
783  EXPECT_EQ(pieces[0], "All");
784  EXPECT_EQ(pieces[1], "");
785  EXPECT_EQ(pieces[2], "your base");
786  EXPECT_EQ(pieces[3], "are ");
787  EXPECT_EQ(pieces[4], "");
788  EXPECT_EQ(pieces[5], "belong to us");
789  pieces.clear();
790 
791  orig = ", Facebook, rul,es!, ";
792  folly::split(", ", orig, pieces, true);
793  EXPECT_EQ(pieces.size(), 2);
794  EXPECT_EQ(pieces[0], "Facebook");
795  EXPECT_EQ(pieces[1], "rul,es!");
796  pieces.clear();
797  folly::split(", ", orig, pieces);
798  EXPECT_EQ(pieces.size(), 4);
799  EXPECT_EQ(pieces[0], "");
800  EXPECT_EQ(pieces[1], "Facebook");
801  EXPECT_EQ(pieces[2], "rul,es!");
802  EXPECT_EQ(pieces[3], "");
803  pieces.clear();
804 
805  const char* str = "a,b";
806  folly::split(',', StringPiece(str), pieces);
807  EXPECT_EQ(pieces.size(), 2);
808  EXPECT_EQ(pieces[0], "a");
809  EXPECT_EQ(pieces[1], "b");
810  EXPECT_EQ(pieces[0].start(), str);
811  EXPECT_EQ(pieces[1].start(), str + 2);
812 
813  std::set<StringPiece> unique;
814  folly::splitTo<StringPiece>(
815  ":",
816  "asd:bsd:asd:asd:bsd:csd::asd",
817  std::inserter(unique, unique.begin()),
818  true);
819  EXPECT_EQ(unique.size(), 3);
820  if (unique.size() == 3) {
821  EXPECT_EQ(*unique.begin(), "asd");
822  EXPECT_EQ(*--unique.end(), "csd");
823  }
824 
825  VectorType<fbstring, std::allocator<fbstring>> blah;
826  folly::split('-', "a-b-c-d-f-e", blah);
827  EXPECT_EQ(blah.size(), 6);
828 }
829 
830 } // namespace
831 
832 TEST(Split, split_vector) {
833  splitTest<std::vector>();
834 }
835 TEST(Split, split_fbvector) {
836  splitTest<folly::fbvector>();
837 }
838 TEST(Split, pieces_vector) {
839  piecesTest<std::vector>();
840 }
841 TEST(Split, pieces_fbvector) {
842  piecesTest<folly::fbvector>();
843 }
844 
845 TEST(Split, fixed) {
846  StringPiece a, b, c, d;
847 
848  EXPECT_TRUE(folly::split<false>('.', "a.b.c.d", a, b, c, d));
849  EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
850  EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
851  EXPECT_TRUE(folly::split<false>('.', "a", a));
852 
853  EXPECT_TRUE(folly::split('.', "a.b.c.d", a, b, c, d));
854  EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
855  EXPECT_TRUE(folly::split('.', "a.b", a, b));
856  EXPECT_TRUE(folly::split('.', "a", a));
857 
858  EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
859  EXPECT_EQ("a", a);
860  EXPECT_EQ("b", b);
861  EXPECT_EQ("c", c);
862  EXPECT_FALSE(folly::split<false>('.', "a.b", a, b, c));
863  EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b));
864  EXPECT_EQ("a", a);
865  EXPECT_EQ("b.c", b);
866 
867  EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
868  EXPECT_EQ("a", a);
869  EXPECT_EQ("b", b);
870  EXPECT_EQ("c", c);
871  EXPECT_FALSE(folly::split('.', "a.b.c", a, b));
872  EXPECT_FALSE(folly::split('.', "a.b", a, b, c));
873 
874  EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
875  EXPECT_EQ("a", a);
876  EXPECT_EQ("b", b);
877  EXPECT_FALSE(folly::split<false>('.', "a", a, b));
878  EXPECT_TRUE(folly::split<false>('.', "a.b", a));
879  EXPECT_EQ("a.b", a);
880 
881  EXPECT_TRUE(folly::split('.', "a.b", a, b));
882  EXPECT_EQ("a", a);
883  EXPECT_EQ("b", b);
884  EXPECT_FALSE(folly::split('.', "a", a, b));
885  EXPECT_FALSE(folly::split('.', "a.b", a));
886 }
887 
888 TEST(Split, std_string_fixed) {
889  std::string a, b, c, d;
890 
891  EXPECT_TRUE(folly::split<false>('.', "a.b.c.d", a, b, c, d));
892  EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
893  EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
894  EXPECT_TRUE(folly::split<false>('.', "a", a));
895 
896  EXPECT_TRUE(folly::split('.', "a.b.c.d", a, b, c, d));
897  EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
898  EXPECT_TRUE(folly::split('.', "a.b", a, b));
899  EXPECT_TRUE(folly::split('.', "a", a));
900 
901  EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
902  EXPECT_EQ("a", a);
903  EXPECT_EQ("b", b);
904  EXPECT_EQ("c", c);
905  EXPECT_FALSE(folly::split<false>('.', "a.b", a, b, c));
906  EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b));
907  EXPECT_EQ("a", a);
908  EXPECT_EQ("b.c", b);
909 
910  EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
911  EXPECT_EQ("a", a);
912  EXPECT_EQ("b", b);
913  EXPECT_EQ("c", c);
914  EXPECT_FALSE(folly::split('.', "a.b.c", a, b));
915  EXPECT_FALSE(folly::split('.', "a.b", a, b, c));
916 
917  EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
918  EXPECT_EQ("a", a);
919  EXPECT_EQ("b", b);
920  EXPECT_FALSE(folly::split<false>('.', "a", a, b));
921  EXPECT_TRUE(folly::split<false>('.', "a.b", a));
922  EXPECT_EQ("a.b", a);
923 
924  EXPECT_TRUE(folly::split('.', "a.b", a, b));
925  EXPECT_EQ("a", a);
926  EXPECT_EQ("b", b);
927  EXPECT_FALSE(folly::split('.', "a", a, b));
928  EXPECT_FALSE(folly::split('.', "a.b", a));
929 }
930 
931 TEST(Split, fixed_convert) {
932  StringPiece a, d;
933  int b;
934  double c = 0;
935 
936  EXPECT_TRUE(folly::split(':', "a:13:14.7:b", a, b, c, d));
937  EXPECT_EQ("a", a);
938  EXPECT_EQ(13, b);
939  EXPECT_NEAR(14.7, c, 1e-10);
940  EXPECT_EQ("b", d);
941 
942  EXPECT_TRUE(folly::split<false>(':', "b:14:15.3:c", a, b, c, d));
943  EXPECT_EQ("b", a);
944  EXPECT_EQ(14, b);
945  EXPECT_NEAR(15.3, c, 1e-10);
946  EXPECT_EQ("c", d);
947 
948  EXPECT_FALSE(folly::split(':', "a:13:14.7:b", a, b, d));
949 
950  EXPECT_TRUE(folly::split<false>(':', "a:13:14.7:b", a, b, d));
951  EXPECT_EQ("a", a);
952  EXPECT_EQ(13, b);
953  EXPECT_EQ("14.7:b", d);
954 
955  // Enable verifying that a line only contains one field
956  EXPECT_TRUE(folly::split(' ', "hello", a));
957  EXPECT_FALSE(folly::split(' ', "hello world", a));
958 
959  // Test cases with std::ignore.
960  EXPECT_TRUE(folly::split(':', "a:13:14.7:b", std::ignore, b, c, d));
961  EXPECT_EQ(13, b);
962  EXPECT_NEAR(14.7, c, 1e-10);
963  EXPECT_EQ("b", d);
964 
965  EXPECT_TRUE(folly::split(':', "a:13:14.7:b", std::ignore, b, c, std::ignore));
966  EXPECT_EQ(13, b);
967  EXPECT_NEAR(14.7, c, 1e-10);
968 
969  EXPECT_TRUE(folly::split<false>(':', "a:13:14.7:b", a, b, std::ignore));
970  EXPECT_EQ("a", a);
971  EXPECT_EQ(13, b);
972 
973  EXPECT_FALSE(folly::split<false>(':', "a:13", std::ignore, b, std::ignore));
974  EXPECT_TRUE(folly::split<false>(':', ":13:", std::ignore, b, std::ignore));
975  EXPECT_EQ(13, b);
976 }
977 
978 namespace my {
979 
980 enum class Color {
981  Red,
982  Blue,
983 };
984 
986 
987 struct ColorError : std::runtime_error {
988  using std::runtime_error::runtime_error;
989 };
990 
992  return ColorError("Invalid my::Color representation : " + sp.str());
993 }
994 
996  StringPiece in,
997  Color& out) noexcept {
998  if (in == "R") {
999  out = Color::Red;
1000  } else if (in == "B") {
1001  out = Color::Blue;
1002  } else {
1003  return makeUnexpected(ColorErrorCode::INVALID_COLOR);
1004  }
1005  return StringPiece(in.end(), in.end());
1006 }
1007 } // namespace my
1008 
1009 TEST(Split, fixed_convert_custom) {
1010  my::Color c1, c2;
1011 
1012  EXPECT_TRUE(folly::split(',', "R,B", c1, c2));
1015 
1016  EXPECT_THROW(folly::split(',', "B,G", c1, c2), my::ColorError);
1017 }
1018 
1019 TEST(String, join) {
1020  string output;
1021 
1022  std::vector<int> empty = {};
1023  join(":", empty, output);
1024  EXPECT_TRUE(output.empty());
1025 
1026  std::vector<std::string> input1 = {"1", "23", "456", ""};
1027  join(':', input1, output);
1028  EXPECT_EQ(output, "1:23:456:");
1029  output = join(':', input1);
1030  EXPECT_EQ(output, "1:23:456:");
1031 
1032  auto input2 = {1, 23, 456};
1033  join("-*-", input2, output);
1034  EXPECT_EQ(output, "1-*-23-*-456");
1035  output = join("-*-", input2);
1036  EXPECT_EQ(output, "1-*-23-*-456");
1037 
1038  auto input3 = {'f', 'a', 'c', 'e', 'b', 'o', 'o', 'k'};
1039  join("", input3, output);
1040  EXPECT_EQ(output, "facebook");
1041 
1042  join("_", {"", "f", "a", "c", "e", "b", "o", "o", "k", ""}, output);
1043  EXPECT_EQ(output, "_f_a_c_e_b_o_o_k_");
1044 
1045  output = join("", input3.begin(), input3.end());
1046  EXPECT_EQ(output, "facebook");
1047 
1048  std::multiset<char> input4(input3);
1049  output = join("", input4);
1050  EXPECT_EQ("abcefkoo", output);
1051  output = join("", input4.begin(), input4.end());
1052  EXPECT_EQ("abcefkoo", output);
1053 }
1054 
1055 TEST(String, hexlify) {
1056  string input1 = "0123";
1057  string output1;
1058  EXPECT_TRUE(hexlify(input1, output1));
1059  EXPECT_EQ("30313233", output1);
1060 
1061  fbstring input2 = "abcdefg";
1062  input2[1] = 0;
1063  input2[3] = 0xff;
1064  input2[5] = 0xb6;
1065  fbstring output2;
1066  EXPECT_TRUE(hexlify(input2, output2));
1067  EXPECT_EQ("610063ff65b667", output2);
1068 
1069  EXPECT_EQ("666f6f626172", hexlify("foobar"));
1070  auto bytes = folly::make_array<uint8_t>(1, 2, 3, 4);
1071  EXPECT_EQ("01020304", hexlify(ByteRange{bytes.data(), bytes.size()}));
1072 }
1073 
1074 TEST(String, unhexlify) {
1075  string input1 = "30313233";
1076  string output1;
1077  EXPECT_TRUE(unhexlify(input1, output1));
1078  EXPECT_EQ(output1, "0123");
1079 
1080  fbstring input2 = "610063ff65b667";
1081  fbstring output2;
1082  EXPECT_TRUE(unhexlify(input2, output2));
1083  EXPECT_EQ(output2.size(), 7);
1084  EXPECT_EQ(output2[0], 'a');
1085  EXPECT_EQ(output2[1], 0);
1086  EXPECT_EQ(output2[2], 'c');
1087  EXPECT_EQ(output2[3] & 0xff, 0xff);
1088  EXPECT_EQ(output2[4], 'e');
1089  EXPECT_EQ(output2[5] & 0xff, 0xb6);
1090  EXPECT_EQ(output2[6], 'g');
1091 
1092  string input3 = "x";
1093  string output3;
1094  EXPECT_FALSE(unhexlify(input3, output3));
1095 
1096  string input4 = "xy";
1097  string output4;
1098  EXPECT_FALSE(unhexlify(input4, output4));
1099 
1100  EXPECT_EQ("foobar", unhexlify("666f6f626172"));
1101  EXPECT_EQ(StringPiece("foo\0bar", 7), unhexlify("666f6f00626172"));
1102  EXPECT_THROW(unhexlify("666f6fzz626172"), std::domain_error);
1103 }
1104 
1105 TEST(String, backslashify) {
1106  EXPECT_EQ("abc", string("abc"));
1107  EXPECT_EQ("abc", backslashify(string("abc")));
1108  EXPECT_EQ("abc\\r", backslashify(string("abc\r")));
1109  EXPECT_EQ("abc\\x0d", backslashify(string("abc\r"), true));
1110  EXPECT_EQ("\\0\\0", backslashify(string(2, '\0')));
1111 
1112  StringPiece input1 = "abc\r";
1113  std::string output1 = backslashify(input1);
1114  EXPECT_EQ("abc\\r", output1);
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  // Mostly printable, so backslash! 80, 60, and 40% printable, respectively
1128  EXPECT_EQ("aaaa\\xff", humanify(string("aaaa\xff")));
1129  EXPECT_EQ("aaa\\xff\\xff", humanify(string("aaa\xff\xff")));
1130  EXPECT_EQ("aa\\xff\\xff\\xff", humanify(string("aa\xff\xff\xff")));
1131 
1132  // 20% printable, and the printable portion isn't the prefix; hexify!
1133  EXPECT_EQ(
1134  "0xff61ffffff",
1135  humanify(string("\xff"
1136  "a\xff\xff\xff")));
1137 
1138  // Same as previous, except swap first two chars; prefix is
1139  // printable and within the threshold, so backslashify.
1140  EXPECT_EQ("a\\xff\\xff\\xff\\xff", humanify(string("a\xff\xff\xff\xff")));
1141 
1142  // Just too much unprintable; hex, despite prefix.
1143  EXPECT_EQ("0x61ffffffffff", humanify(string("a\xff\xff\xff\xff\xff")));
1144 }
1145 
1146 namespace {
1147 
1155 char* copyWithSameAlignment(char* dst, const char* src, size_t length) {
1156  const char* originalDst = dst;
1157  size_t dstOffset = size_t(dst) & 0x7;
1158  size_t srcOffset = size_t(src) & 0x7;
1159  while (dstOffset != srcOffset) {
1160  dst++;
1161  dstOffset++;
1162  dstOffset &= 0x7;
1163  }
1164  CHECK(dst <= originalDst + 7);
1165  CHECK((size_t(dst) & 0x7) == (size_t(src) & 0x7));
1166  memcpy(dst, src, length);
1167  return dst;
1168 }
1169 
1170 void testToLowerAscii(Range<const char*> src) {
1171  // Allocate extra space so we can make copies that start at the
1172  // same alignment (byte, word, quadword, etc) as the source buffer.
1173  auto controlBuf = std::vector<char>(src.size() + 7);
1174  char* control =
1175  copyWithSameAlignment(controlBuf.data(), src.begin(), src.size());
1176 
1177  auto testBuf = std::vector<char>(src.size() + 7);
1178  char* test = copyWithSameAlignment(testBuf.data(), src.begin(), src.size());
1179 
1180  for (size_t i = 0; i < src.size(); i++) {
1181  control[i] = tolower(control[i]);
1182  }
1183  toLowerAscii(test, src.size());
1184  for (size_t i = 0; i < src.size(); i++) {
1185  EXPECT_EQ(control[i], test[i]);
1186  }
1187 }
1188 
1189 } // namespace
1190 
1191 TEST(String, toLowerAsciiAligned) {
1192  static const size_t kSize = 256;
1193  char input[kSize];
1194  for (size_t i = 0; i < kSize; i++) {
1195  input[i] = (char)(i & 0xff);
1196  }
1197  testToLowerAscii(Range<const char*>(input, kSize));
1198 }
1199 
1200 TEST(String, toLowerAsciiUnaligned) {
1201  static const size_t kSize = 256;
1202  char input[kSize];
1203  for (size_t i = 0; i < kSize; i++) {
1204  input[i] = (char)(i & 0xff);
1205  }
1206  // Test input buffers of several lengths to exercise all the
1207  // cases: buffer at the start/middle/end of an aligned block, plus
1208  // buffers that span multiple aligned blocks. The longest test input
1209  // is 3 unaligned bytes + 4 32-bit aligned bytes + 8 64-bit aligned
1210  // + 4 32-bit aligned + 3 unaligned = 22 bytes.
1211  for (size_t length = 1; length < 23; length++) {
1212  for (size_t offset = 0; offset + length <= kSize; offset++) {
1213  testToLowerAscii(Range<const char*>(input + offset, length));
1214  }
1215  }
1216 }
1217 
1218 TEST(String, whitespace) {
1219  // trimWhitespace:
1220  EXPECT_EQ("kavabanga", trimWhitespace("kavabanga"));
1221  EXPECT_EQ("kavabanga", trimWhitespace("kavabanga \t \n "));
1222  EXPECT_EQ("kavabanga", trimWhitespace(" \t \r \n \n kavabanga"));
1223  EXPECT_EQ("kavabanga", trimWhitespace("\t \r \n kavabanga \t \n "));
1224  EXPECT_EQ("kavabanga", trimWhitespace(" \t \r \n \n kavabanga"));
1225  EXPECT_EQ("kavabanga", trimWhitespace("\t \r \n kavabanga \t \n "));
1226  EXPECT_EQ(
1227  ltrimWhitespace(rtrimWhitespace("kavabanga")),
1228  rtrimWhitespace(ltrimWhitespace("kavabanga")));
1229  EXPECT_EQ(
1230  ltrimWhitespace(rtrimWhitespace("kavabanga \r\t\n")),
1231  rtrimWhitespace(ltrimWhitespace("kavabanga \r\t\n")));
1232  EXPECT_EQ("", trimWhitespace("\t \r \n \t \n "));
1233  EXPECT_EQ("", trimWhitespace(""));
1234  EXPECT_EQ("", trimWhitespace("\t"));
1235  EXPECT_EQ("", trimWhitespace("\r"));
1236  EXPECT_EQ("", trimWhitespace("\n"));
1237  EXPECT_EQ("", trimWhitespace("\t "));
1238  EXPECT_EQ("", trimWhitespace("\r "));
1239  EXPECT_EQ("", trimWhitespace("\n "));
1240  EXPECT_EQ("", trimWhitespace(" \t"));
1241  EXPECT_EQ("", trimWhitespace(" \r"));
1242  EXPECT_EQ("", trimWhitespace(" \n"));
1243 
1244  // ltrimWhitespace:
1245  EXPECT_EQ("kavabanga", ltrimWhitespace("\t kavabanga"));
1246  EXPECT_EQ("kavabanga \r\n", ltrimWhitespace("\t kavabanga \r\n"));
1247  EXPECT_EQ("", ltrimWhitespace("\r "));
1248  EXPECT_EQ("", ltrimWhitespace("\n "));
1249  EXPECT_EQ("", ltrimWhitespace("\r "));
1250 
1251  // rtrimWhitespace:
1252  EXPECT_EQ("\t kavabanga", rtrimWhitespace("\t kavabanga"));
1253  EXPECT_EQ("\t kavabanga", rtrimWhitespace("\t kavabanga \r\n"));
1254  EXPECT_EQ("", rtrimWhitespace("\r "));
1255  EXPECT_EQ("", rtrimWhitespace("\n "));
1256  EXPECT_EQ("", rtrimWhitespace("\r "));
1257 }
1258 
1259 TEST(String, stripLeftMargin_really_empty) {
1260  auto input = "";
1261  auto expected = "";
1262  EXPECT_EQ(expected, stripLeftMargin(input));
1263 }
1264 
1265 TEST(String, stripLeftMargin_empty) {
1266  auto input = R"TEXT(
1267  )TEXT";
1268  auto expected = "";
1269  EXPECT_EQ(expected, stripLeftMargin(input));
1270 }
1271 
1272 TEST(String, stripLeftMargin_only_whitespace) {
1273  // using ~ as a marker
1274  string input = R"TEXT(
1275  ~
1276  )TEXT";
1277  input = boost::regex_replace(input, boost::regex("~"), "");
1278  EXPECT_EQ("\n \n ", input);
1279  auto expected = "\n";
1280  EXPECT_EQ(expected, stripLeftMargin(input));
1281 }
1282 
1283 TEST(String, stripLeftMargin_only_uneven_whitespace) {
1284  // using ~ as a marker1
1285  string input = R"TEXT(
1286  ~
1287  ~
1288  )TEXT";
1289  input = boost::regex_replace(input, boost::regex("~"), "");
1290  EXPECT_EQ("\n \n \n ", input);
1291  auto expected = "\n\n";
1292 
1293  EXPECT_EQ(expected, stripLeftMargin(input));
1294 }
1295 
1296 TEST(String, stripLeftMargin_one_line) {
1297  auto input = R"TEXT(
1298  hi there bob!
1299  )TEXT";
1300  auto expected = "hi there bob!\n";
1301  EXPECT_EQ(expected, stripLeftMargin(input));
1302 }
1303 
1304 TEST(String, stripLeftMargin_two_lines) {
1305  auto input = R"TEXT(
1306  hi there bob!
1307  nice weather today!
1308  )TEXT";
1309  auto expected = "hi there bob!\nnice weather today!\n";
1310  EXPECT_EQ(expected, stripLeftMargin(input));
1311 }
1312 
1313 TEST(String, stripLeftMargin_three_lines_uneven) {
1314  auto input = R"TEXT(
1315  hi there bob!
1316  nice weather today!
1317  so long!
1318  )TEXT";
1319  auto expected = " hi there bob!\nnice weather today!\n so long!\n";
1320  EXPECT_EQ(expected, stripLeftMargin(input));
1321 }
1322 
1323 TEST(String, stripLeftMargin_preceding_blank_lines) {
1324  auto input = R"TEXT(
1325 
1326 
1327  hi there bob!
1328  )TEXT";
1329  auto expected = "\n\nhi there bob!\n";
1330  EXPECT_EQ(expected, stripLeftMargin(input));
1331 }
1332 
1333 TEST(String, stripLeftMargin_succeeding_blank_lines) {
1334  auto input = R"TEXT(
1335  hi there bob!
1336 
1337 
1338  )TEXT";
1339  auto expected = "hi there bob!\n\n\n";
1340  EXPECT_EQ(expected, stripLeftMargin(input));
1341 }
1342 
1343 TEST(String, stripLeftMargin_interstitial_undented_whiteline) {
1344  // using ~ as a marker
1345  string input = R"TEXT(
1346  hi there bob!
1347  ~
1348  so long!
1349  )TEXT";
1350  input = boost::regex_replace(input, boost::regex(" +~"), "");
1351  EXPECT_EQ("\n hi there bob!\n\n so long!\n ", input);
1352  auto expected = "hi there bob!\n\nso long!\n";
1353  EXPECT_EQ(expected, stripLeftMargin(input));
1354 }
1355 
1356 TEST(String, stripLeftMargin_interstitial_dedented_whiteline) {
1357  // using ~ as a marker
1358  string input = R"TEXT(
1359  hi there bob!
1360  ~
1361  so long!
1362  )TEXT";
1363  input = boost::regex_replace(input, boost::regex("~"), "");
1364  EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
1365  auto expected = "hi there bob!\n\nso long!\n";
1366  EXPECT_EQ(expected, stripLeftMargin(input));
1367 }
1368 
1369 TEST(String, stripLeftMargin_interstitial_equidented_whiteline) {
1370  // using ~ as a marker
1371  string input = R"TEXT(
1372  hi there bob!
1373  ~
1374  so long!
1375  )TEXT";
1376  input = boost::regex_replace(input, boost::regex("~"), "");
1377  EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
1378  auto expected = "hi there bob!\n\nso long!\n";
1379  EXPECT_EQ(expected, stripLeftMargin(input));
1380 }
1381 
1382 TEST(String, stripLeftMargin_interstitial_indented_whiteline) {
1383  // using ~ as a marker
1384  string input = R"TEXT(
1385  hi there bob!
1386  ~
1387  so long!
1388  )TEXT";
1389  input = boost::regex_replace(input, boost::regex("~"), "");
1390  EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
1391  auto expected = "hi there bob!\n \nso long!\n";
1392  EXPECT_EQ(expected, stripLeftMargin(input));
1393 }
1394 
1395 TEST(String, stripLeftMargin_no_pre_whitespace) {
1396  // using ~ as a marker
1397  string input = R"TEXT( hi there bob!
1398  ~
1399  so long!
1400  )TEXT";
1401  input = boost::regex_replace(input, boost::regex("~"), "");
1402  EXPECT_EQ(" hi there bob!\n \n so long!\n ", input);
1403  auto expected = "hi there bob!\n \nso long!\n";
1404  EXPECT_EQ(expected, stripLeftMargin(input));
1405 }
1406 
1407 TEST(String, stripLeftMargin_no_post_whitespace) {
1408  // using ~ as a marker
1409  string input = R"TEXT(
1410  hi there bob!
1411  ~
1412  so long! )TEXT";
1413  input = boost::regex_replace(input, boost::regex("~"), "");
1414  EXPECT_EQ("\n hi there bob!\n \n so long! ", input);
1415  auto expected = "hi there bob!\n \nso long! ";
1416  EXPECT_EQ(expected, stripLeftMargin(input));
1417 }
#define EXPECT_LE(val1, val2)
Definition: gtest.h:1928
StringPiece ltrimWhitespace(StringPiece sp)
Definition: String.cpp:131
Definition: InvokeTest.cpp:58
size_type size() const
Definition: FBString.h:1337
bool unhexlify(const InputString &input, OutputString &output)
Definition: String-inl.h:616
std::string str() const
Definition: Range.h:591
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
regex
Definition: CMakeCache.txt:563
char b
#define EXPECT_THROW_RE(statement, exceptionType, pattern)
Definition: TestUtils.h:119
void uriUnescape(StringPiece str, String &out, UriEscapeMode mode)
Definition: String-inl.h:201
void vprintfError(const char *fmt,...)
Definition: StringTest.cpp:107
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
fbstring exceptionStr(const std::exception &e)
const int x
std::string stringVPrintf(const char *format, va_list ap)
Definition: String.cpp:232
STL namespace.
constexpr size_type size() const
Definition: Range.h:431
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
std::string stringPrintf(const char *format,...)
Definition: String.cpp:223
std::string & stringVAppendf(std::string *output, const char *format, va_list ap)
Definition: String.cpp:250
void humanify(const String1 &input, String2 &output)
Definition: String-inl.h:552
FOLLY_NODISCARD std::enable_if< std::is_arithmetic< Tgt >::value, Expected< StringPiece, ConversionCode > >::type parseTo(StringPiece src, Tgt &out)
Definition: Conv.h:1182
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
bool prefix(Cursor &c, uint32_t expected)
#define EXPECT_GE(val1, val2)
Definition: gtest.h:1932
void split(const Delim &delimiter, const String &input, std::vector< OutputType > &out, bool ignoreEmpty)
Definition: String-inl.h:382
std::string prettyPrint(double val, PrettyType type, bool addSpace)
Definition: String.cpp:386
std::string stripLeftMargin(std::string s)
Definition: String.cpp:704
void vprintfCheck(const char *expected, const char *fmt,...)
Definition: StringTest.cpp:76
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
std::string prettyString
Definition: StringTest.cpp:308
constexpr Unexpected< typename std::decay< Error >::type > makeUnexpected(Error &&)
Definition: Expected.h:785
void uriEscape(StringPiece str, String &out, UriEscapeMode mode)
Definition: String-inl.h:166
constexpr Iter data() const
Definition: Range.h:446
void cUnescape(StringPiece str, String &out, bool strict)
Definition: String-inl.h:86
StringPiece rtrimWhitespace(StringPiece sp)
Definition: String.cpp:149
void hexDump(const void *ptr, size_t size, OutIt out)
Definition: String-inl.h:645
char a
auto start
std::string & stringAppendf(std::string *output, const char *format,...)
Definition: String.cpp:240
fbstring errnoStr(int err)
Definition: String.cpp:463
double prettyToDouble(folly::StringPiece *const prettyString, const PrettyType type)
Definition: String.cpp:416
#define EXPECT_NEAR(val1, val2, abs_error)
Definition: gtest.h:2043
constexpr Iter begin() const
Definition: Range.h:452
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define EXPECT_DOUBLE_EQ(val1, val2)
Definition: gtest.h:2031
void toLowerAscii(char *str, size_t length)
Definition: String.cpp:601
PrettyTestCase prettyTestCases[]
Definition: StringTest.cpp:313
void backslashify(folly::StringPiece input, OutputString &output, bool hex_style)
Definition: String-inl.h:507
const char * string
Definition: Conv.cpp:212
static set< string > s
StringPiece trimWhitespace(StringPiece sp)
Definition: String.h:568
PrettyType prettyType
Definition: StringTest.cpp:310
ColorErrorCode
Definition: StringTest.cpp:985
void join(const Delim &delimiter, Iterator begin, Iterator end, String &output)
Definition: String-inl.h:498
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
Range< const char * > StringPiece
bool hexlify(const InputString &input, OutputString &output, bool append_output)
Definition: String-inl.h:596
#define ADD_FAILURE()
Definition: gtest.h:1808
char c
TEST(SequencedExecutor, CPUThreadPoolExecutor)
void cEscape(StringPiece str, String &out)
Definition: String-inl.h:39
ConversionError makeConversionError(ConversionCode code, StringPiece input)
Definition: Conv.cpp:765