2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef __STDC_FORMAT_MACROS
18 #define __STDC_FORMAT_MACROS 1
21 #include <folly/String.h>
25 #include <boost/regex.hpp>
27 #include <folly/Array.h>
28 #include <folly/portability/GTest.h>
30 using namespace folly;
33 TEST(StringPrintf, BasicTest) {
34 EXPECT_EQ("abc", stringPrintf("%s", "abc"));
35 EXPECT_EQ("abc", stringPrintf("%sbc", "a"));
36 EXPECT_EQ("abc", stringPrintf("a%sc", "b"));
37 EXPECT_EQ("abc", stringPrintf("ab%s", "c"));
39 EXPECT_EQ("abc", stringPrintf("abc"));
42 TEST(StringPrintf, NumericFormats) {
43 EXPECT_EQ("12", stringPrintf("%d", 12));
44 EXPECT_EQ("2000000000", stringPrintf("%ld", 2000000000UL));
45 EXPECT_EQ("2000000000", stringPrintf("%ld", 2000000000L));
46 EXPECT_EQ("-2000000000", stringPrintf("%ld", -2000000000L));
47 EXPECT_EQ("5000000000", stringPrintf("%lld", 5000000000ULL));
48 EXPECT_EQ("5000000000", stringPrintf("%lld", 5000000000LL));
49 EXPECT_EQ("-5000000000", stringPrintf("%lld", -5000000000LL));
50 EXPECT_EQ("-1", stringPrintf("%d", 0xffffffff));
51 EXPECT_EQ("-1", stringPrintf("%" PRId64, 0xffffffffffffffff));
52 EXPECT_EQ("-1", stringPrintf("%" PRId64, 0xffffffffffffffffUL));
54 EXPECT_EQ("7.7", stringPrintf("%1.1f", 7.7));
55 EXPECT_EQ("7.7", stringPrintf("%1.1lf", 7.7));
56 EXPECT_EQ("7.70000000000000018",
57 stringPrintf("%.17f", 7.7));
58 EXPECT_EQ("7.70000000000000018",
59 stringPrintf("%.17lf", 7.7));
62 TEST(StringPrintf, Appending) {
64 stringAppendf(&s, "a%s", "b");
65 stringAppendf(&s, "%c", 'c');
67 stringAppendf(&s, " %d", 123);
68 EXPECT_EQ(s, "abc 123");
71 void vprintfCheck(const char* expected, const char* fmt, ...) {
73 va_start(apOrig, fmt);
83 // Check both APIs for calling stringVPrintf()
84 EXPECT_EQ(expected, stringVPrintf(fmt, ap));
89 stringVPrintf(&out, fmt, ap);
92 EXPECT_EQ(expected, out);
94 // Check stringVAppendf() as well
95 std::string prefix = "foobar";
97 EXPECT_EQ(prefix + expected, stringVAppendf(&out, fmt, ap));
102 void vprintfError(const char* fmt, ...) {
109 // OSX's sprintf family does not return a negative number on a bad format
110 // string, but Linux does. It's unclear to me which behavior is more
112 #ifdef HAVE_VSNPRINTF_ERRORS
113 EXPECT_THROW({stringVPrintf(fmt, ap);},
118 TEST(StringPrintf, VPrintf) {
119 vprintfCheck("foo", "%s", "foo");
120 vprintfCheck("long string requiring reallocation 1 2 3 0x12345678",
121 "%s %s %d %d %d %#x",
122 "long string", "requiring reallocation", 1, 2, 3, 0x12345678);
123 vprintfError("bogus%", "foo");
126 TEST(StringPrintf, VariousSizes) {
127 // Test a wide variety of output sizes, making sure to cross the
128 // vsnprintf buffer boundary implementation detail.
129 for (int i = 0; i < 4096; ++i) {
130 string expected(i + 1, 'a');
131 expected = "X" + expected + "X";
132 string result = stringPrintf("%s", expected.c_str());
133 EXPECT_EQ(expected.size(), result.size());
134 EXPECT_EQ(expected, result);
137 EXPECT_EQ("abc12345678910111213141516171819202122232425xyz",
138 stringPrintf("abc%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
139 "%d%d%d%d%d%d%d%d%d%d%dxyz",
140 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
141 17, 18, 19, 20, 21, 22, 23, 24, 25));
144 TEST(StringPrintf, oldStringPrintfTests) {
145 EXPECT_EQ(string("a/b/c/d"),
146 stringPrintf("%s/%s/%s/%s", "a", "b", "c", "d"));
148 EXPECT_EQ(string(" 5 10"),
149 stringPrintf("%5d %5d", 5, 10));
151 // check printing w/ a big buffer
152 for (int size = (1 << 8); size <= (1 << 15); size <<= 1) {
154 string b = stringPrintf("%s", a.c_str());
155 EXPECT_EQ(a.size(), b.size());
159 TEST(StringPrintf, oldStringAppendf) {
161 stringAppendf(&s, "%s/%s/%s/%s", "a", "b", "c", "d");
162 EXPECT_EQ(string("helloa/b/c/d"), s);
165 TEST(Escape, cEscape) {
166 EXPECT_EQ("hello world", cEscape<std::string>("hello world"));
167 EXPECT_EQ("hello \\\\world\\\" goodbye",
168 cEscape<std::string>("hello \\world\" goodbye"));
169 EXPECT_EQ("hello\\nworld", cEscape<std::string>("hello\nworld"));
170 EXPECT_EQ("hello\\377\\376", cEscape<std::string>("hello\xff\xfe"));
173 TEST(Escape, cUnescape) {
174 EXPECT_EQ("hello world", cUnescape<std::string>("hello world"));
175 EXPECT_EQ("hello \\world\" goodbye",
176 cUnescape<std::string>("hello \\\\world\\\" goodbye"));
177 EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\nworld"));
178 EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\012world"));
179 EXPECT_EQ("hello\nworld", cUnescape<std::string>("hello\\x0aworld"));
180 EXPECT_EQ("hello\xff\xfe", cUnescape<std::string>("hello\\377\\376"));
181 EXPECT_EQ("hello\xff\xfe", cUnescape<std::string>("hello\\xff\\xfe"));
183 EXPECT_THROW({cUnescape<std::string>("hello\\");},
184 std::invalid_argument);
185 EXPECT_THROW({cUnescape<std::string>("hello\\x");},
186 std::invalid_argument);
187 EXPECT_THROW({cUnescape<std::string>("hello\\q");},
188 std::invalid_argument);
191 TEST(Escape, uriEscape) {
192 EXPECT_EQ("hello%2c%20%2fworld", uriEscape<std::string>("hello, /world"));
193 EXPECT_EQ("hello%2c%20/world", uriEscape<std::string>("hello, /world",
194 UriEscapeMode::PATH));
195 EXPECT_EQ("hello%2c+%2fworld", uriEscape<std::string>("hello, /world",
196 UriEscapeMode::QUERY));
198 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~",
199 uriEscape<std::string>(
200 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~")
204 TEST(Escape, uriUnescape) {
205 EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello, /world"));
206 EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello%2c%20%2fworld"));
207 EXPECT_EQ("hello,+/world", uriUnescape<std::string>("hello%2c+%2fworld"));
208 EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello%2c+%2fworld",
209 UriEscapeMode::QUERY));
210 EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2f"));
211 EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2F"));
212 EXPECT_THROW({uriUnescape<std::string>("hello%");},
213 std::invalid_argument);
214 EXPECT_THROW({uriUnescape<std::string>("hello%2");},
215 std::invalid_argument);
216 EXPECT_THROW({uriUnescape<std::string>("hello%2g");},
217 std::invalid_argument);
221 void expectPrintable(StringPiece s) {
229 TEST(Escape, uriEscapeAllCombinations) {
232 StringPiece in(c, 2);
235 for (int i = 0; i < 256; ++i) {
237 for (int j = 0; j < 256; ++j) {
242 expectPrintable(tmp);
243 uriUnescape(tmp, out);
251 return ((v >= '0' && v <= '9') ||
252 (v >= 'A' && v <= 'F') ||
253 (v >= 'a' && v <= 'f'));
257 TEST(Escape, uriUnescapePercentDecoding) {
258 char c[4] = {'%', '\0', '\0', '\0'};
259 StringPiece in(c, 3);
261 unsigned int expected = 0;
262 for (int i = 0; i < 256; ++i) {
264 for (int j = 0; j < 256; ++j) {
266 if (isHex(i) && isHex(j)) {
268 uriUnescape(in, out);
269 EXPECT_EQ(1, out.size());
270 EXPECT_EQ(1, sscanf(c + 1, "%x", &expected));
271 unsigned char v = out[0];
272 EXPECT_EQ(expected, v);
274 EXPECT_THROW({uriUnescape(in, out);}, std::invalid_argument);
282 double pow2(int exponent) {
283 return double(int64_t(1) << exponent);
287 struct PrettyTestCase{
288 std::string prettyString;
290 PrettyType prettyType;
293 PrettyTestCase prettyTestCases[] =
295 {string("8.53e+07 s "), 85.3e6, PRETTY_TIME},
296 {string("8.53e+07 s "), 85.3e6, PRETTY_TIME},
297 {string("85.3 ms"), 85.3e-3, PRETTY_TIME},
298 {string("85.3 us"), 85.3e-6, PRETTY_TIME},
299 {string("85.3 ns"), 85.3e-9, PRETTY_TIME},
300 {string("85.3 ps"), 85.3e-12, PRETTY_TIME},
301 {string("8.53e-14 s "), 85.3e-15, PRETTY_TIME},
303 {string("0 s "), 0, PRETTY_TIME},
304 {string("1 s "), 1.0, PRETTY_TIME},
305 {string("1 ms"), 1.0e-3, PRETTY_TIME},
306 {string("1 us"), 1.0e-6, PRETTY_TIME},
307 {string("1 ns"), 1.0e-9, PRETTY_TIME},
308 {string("1 ps"), 1.0e-12, PRETTY_TIME},
310 // check bytes printing
311 {string("853 B "), 853., PRETTY_BYTES},
312 {string("833 kB"), 853.e3, PRETTY_BYTES},
313 {string("813.5 MB"), 853.e6, PRETTY_BYTES},
314 {string("7.944 GB"), 8.53e9, PRETTY_BYTES},
315 {string("794.4 GB"), 853.e9, PRETTY_BYTES},
316 {string("775.8 TB"), 853.e12, PRETTY_BYTES},
318 {string("0 B "), 0, PRETTY_BYTES},
319 {string("1 B "), pow2(0), PRETTY_BYTES},
320 {string("1 kB"), pow2(10), PRETTY_BYTES},
321 {string("1 MB"), pow2(20), PRETTY_BYTES},
322 {string("1 GB"), pow2(30), PRETTY_BYTES},
323 {string("1 TB"), pow2(40), PRETTY_BYTES},
325 {string("853 B "), 853., PRETTY_BYTES_IEC},
326 {string("833 KiB"), 853.e3, PRETTY_BYTES_IEC},
327 {string("813.5 MiB"), 853.e6, PRETTY_BYTES_IEC},
328 {string("7.944 GiB"), 8.53e9, PRETTY_BYTES_IEC},
329 {string("794.4 GiB"), 853.e9, PRETTY_BYTES_IEC},
330 {string("775.8 TiB"), 853.e12, PRETTY_BYTES_IEC},
332 {string("0 B "), 0, PRETTY_BYTES_IEC},
333 {string("1 B "), pow2(0), PRETTY_BYTES_IEC},
334 {string("1 KiB"), pow2(10), PRETTY_BYTES_IEC},
335 {string("1 MiB"), pow2(20), PRETTY_BYTES_IEC},
336 {string("1 GiB"), pow2(30), PRETTY_BYTES_IEC},
337 {string("1 TiB"), pow2(40), PRETTY_BYTES_IEC},
339 // check bytes metric printing
340 {string("853 B "), 853., PRETTY_BYTES_METRIC},
341 {string("853 kB"), 853.e3, PRETTY_BYTES_METRIC},
342 {string("853 MB"), 853.e6, PRETTY_BYTES_METRIC},
343 {string("8.53 GB"), 8.53e9, PRETTY_BYTES_METRIC},
344 {string("853 GB"), 853.e9, PRETTY_BYTES_METRIC},
345 {string("853 TB"), 853.e12, PRETTY_BYTES_METRIC},
347 {string("0 B "), 0, PRETTY_BYTES_METRIC},
348 {string("1 B "), 1.0, PRETTY_BYTES_METRIC},
349 {string("1 kB"), 1.0e+3, PRETTY_BYTES_METRIC},
350 {string("1 MB"), 1.0e+6, PRETTY_BYTES_METRIC},
352 {string("1 GB"), 1.0e+9, PRETTY_BYTES_METRIC},
353 {string("1 TB"), 1.0e+12, PRETTY_BYTES_METRIC},
355 // check metric-units (powers of 1000) printing
356 {string("853 "), 853., PRETTY_UNITS_METRIC},
357 {string("853 k"), 853.e3, PRETTY_UNITS_METRIC},
358 {string("853 M"), 853.e6, PRETTY_UNITS_METRIC},
359 {string("8.53 bil"), 8.53e9, PRETTY_UNITS_METRIC},
360 {string("853 bil"), 853.e9, PRETTY_UNITS_METRIC},
361 {string("853 tril"), 853.e12, PRETTY_UNITS_METRIC},
363 // check binary-units (powers of 1024) printing
364 {string("0 "), 0, PRETTY_UNITS_BINARY},
365 {string("1 "), pow2(0), PRETTY_UNITS_BINARY},
366 {string("1 k"), pow2(10), PRETTY_UNITS_BINARY},
367 {string("1 M"), pow2(20), PRETTY_UNITS_BINARY},
368 {string("1 G"), pow2(30), PRETTY_UNITS_BINARY},
369 {string("1 T"), pow2(40), PRETTY_UNITS_BINARY},
371 {string("1023 "), pow2(10) - 1, PRETTY_UNITS_BINARY},
372 {string("1024 k"), pow2(20) - 1, PRETTY_UNITS_BINARY},
373 {string("1024 M"), pow2(30) - 1, PRETTY_UNITS_BINARY},
374 {string("1024 G"), pow2(40) - 1, PRETTY_UNITS_BINARY},
376 {string("0 "), 0, PRETTY_UNITS_BINARY_IEC},
377 {string("1 "), pow2(0), PRETTY_UNITS_BINARY_IEC},
378 {string("1 Ki"), pow2(10), PRETTY_UNITS_BINARY_IEC},
379 {string("1 Mi"), pow2(20), PRETTY_UNITS_BINARY_IEC},
380 {string("1 Gi"), pow2(30), PRETTY_UNITS_BINARY_IEC},
381 {string("1 Ti"), pow2(40), PRETTY_UNITS_BINARY_IEC},
383 {string("1023 "), pow2(10) - 1, PRETTY_UNITS_BINARY_IEC},
384 {string("1024 Ki"), pow2(20) - 1, PRETTY_UNITS_BINARY_IEC},
385 {string("1024 Mi"), pow2(30) - 1, PRETTY_UNITS_BINARY_IEC},
386 {string("1024 Gi"), pow2(40) - 1, PRETTY_UNITS_BINARY_IEC},
388 //check border SI cases
390 {string("1 Y"), 1e24, PRETTY_SI},
391 {string("10 Y"), 1e25, PRETTY_SI},
392 {string("1 y"), 1e-24, PRETTY_SI},
393 {string("10 y"), 1e-23, PRETTY_SI},
395 // check that negative values work
396 {string("-85.3 s "), -85.3, PRETTY_TIME},
397 {string("-85.3 ms"), -85.3e-3, PRETTY_TIME},
398 {string("-85.3 us"), -85.3e-6, PRETTY_TIME},
399 {string("-85.3 ns"), -85.3e-9, PRETTY_TIME},
401 {string("endoftest"), 0, PRETTY_NUM_TYPES}
404 TEST(PrettyPrint, Basic) {
405 for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i){
406 const PrettyTestCase& prettyTest = prettyTestCases[i];
407 EXPECT_EQ(prettyTest.prettyString,
408 prettyPrint(prettyTest.realValue, prettyTest.prettyType));
412 TEST(PrettyToDouble, Basic) {
413 // check manually created tests
414 for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i){
415 PrettyTestCase testCase = prettyTestCases[i];
416 PrettyType formatType = testCase.prettyType;
417 double x = testCase.realValue;
418 std::string testString = testCase.prettyString;
419 double recoveredX = 0;
421 recoveredX = prettyToDouble(testString, formatType);
422 } catch (const std::range_error& ex) {
423 EXPECT_TRUE(false) << testCase.prettyString << " -> " << ex.what();
425 double relativeError = fabs(x) < 1e-5 ? (x-recoveredX) :
426 (x - recoveredX) / x;
427 EXPECT_NEAR(0, relativeError, 1e-3);
430 // checks for compatibility with prettyPrint over the whole parameter space
431 for (int i = 0 ; i < PRETTY_NUM_TYPES; ++i){
432 PrettyType formatType = static_cast<PrettyType>(i);
433 for (double x = 1e-18; x < 1e40; x *= 1.9){
434 bool addSpace = static_cast<PrettyType> (i) == PRETTY_SI;
435 for (int it = 0; it < 2; ++it, addSpace = true){
436 double recoveredX = 0;
438 recoveredX = prettyToDouble(prettyPrint(x, formatType, addSpace),
440 } catch (std::range_error&) {
443 double relativeError = (x - recoveredX) / x;
444 EXPECT_NEAR(0, relativeError, 1e-3);
449 // check for incorrect values
450 EXPECT_THROW(prettyToDouble("10Mx", PRETTY_SI), std::range_error);
451 EXPECT_THROW(prettyToDouble("10 Mx", PRETTY_SI), std::range_error);
452 EXPECT_THROW(prettyToDouble("10 M x", PRETTY_SI), std::range_error);
454 StringPiece testString = "10Mx";
455 EXPECT_DOUBLE_EQ(prettyToDouble(&testString, PRETTY_UNITS_METRIC), 10e6);
456 EXPECT_EQ(testString, "x");
459 TEST(PrettyPrint, HexDump) {
460 std::string a("abc\x00\x02\xa0", 6); // embedded NUL
462 "00000000 61 62 63 00 02 a0 "
464 hexDump(a.data(), a.size()));
466 a = "abcdefghijklmnopqrstuvwxyz";
468 "00000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 "
469 "|abcdefghijklmnop|\n"
470 "00000010 71 72 73 74 75 76 77 78 79 7a "
472 hexDump(a.data(), a.size()));
475 TEST(System, errnoStr) {
477 EXPECT_EQ(EACCES, errno);
478 EXPECT_EQ(EACCES, errno); // twice to make sure EXPECT_EQ doesn't change it
480 fbstring expected = strerror(ENOENT);
483 EXPECT_EQ(expected, errnoStr(ENOENT));
484 // Ensure that errno isn't changed
485 EXPECT_EQ(EACCES, errno);
487 // Per POSIX, all errno values are positive, so -1 is invalid
490 // Ensure that errno isn't changed
491 EXPECT_EQ(EACCES, errno);
496 template<template<class,class> class VectorType>
498 VectorType<string,std::allocator<string> > parts;
500 folly::split(',', "a,b,c", parts);
501 EXPECT_EQ(parts.size(), 3);
502 EXPECT_EQ(parts[0], "a");
503 EXPECT_EQ(parts[1], "b");
504 EXPECT_EQ(parts[2], "c");
507 folly::split(',', StringPiece("a,b,c"), parts);
508 EXPECT_EQ(parts.size(), 3);
509 EXPECT_EQ(parts[0], "a");
510 EXPECT_EQ(parts[1], "b");
511 EXPECT_EQ(parts[2], "c");
514 folly::split(',', string("a,b,c"), parts);
515 EXPECT_EQ(parts.size(), 3);
516 EXPECT_EQ(parts[0], "a");
517 EXPECT_EQ(parts[1], "b");
518 EXPECT_EQ(parts[2], "c");
521 folly::split(',', "a,,c", parts);
522 EXPECT_EQ(parts.size(), 3);
523 EXPECT_EQ(parts[0], "a");
524 EXPECT_EQ(parts[1], "");
525 EXPECT_EQ(parts[2], "c");
528 folly::split(',', string("a,,c"), parts);
529 EXPECT_EQ(parts.size(), 3);
530 EXPECT_EQ(parts[0], "a");
531 EXPECT_EQ(parts[1], "");
532 EXPECT_EQ(parts[2], "c");
535 folly::split(',', "a,,c", parts, true);
536 EXPECT_EQ(parts.size(), 2);
537 EXPECT_EQ(parts[0], "a");
538 EXPECT_EQ(parts[1], "c");
541 folly::split(',', string("a,,c"), parts, true);
542 EXPECT_EQ(parts.size(), 2);
543 EXPECT_EQ(parts[0], "a");
544 EXPECT_EQ(parts[1], "c");
547 folly::split(',', string(",,a,,c,,,"), parts, true);
548 EXPECT_EQ(parts.size(), 2);
549 EXPECT_EQ(parts[0], "a");
550 EXPECT_EQ(parts[1], "c");
553 // test multiple split w/o clear
554 folly::split(',', ",,a,,c,,,", parts, true);
555 EXPECT_EQ(parts.size(), 2);
556 EXPECT_EQ(parts[0], "a");
557 EXPECT_EQ(parts[1], "c");
558 folly::split(',', ",,a,,c,,,", parts, true);
559 EXPECT_EQ(parts.size(), 4);
560 EXPECT_EQ(parts[2], "a");
561 EXPECT_EQ(parts[3], "c");
564 // test splits that with multi-line delimiter
565 folly::split("ab", "dabcabkdbkab", parts, true);
566 EXPECT_EQ(parts.size(), 3);
567 EXPECT_EQ(parts[0], "d");
568 EXPECT_EQ(parts[1], "c");
569 EXPECT_EQ(parts[2], "kdbk");
572 // test last part is shorter than the delimiter
573 folly::split("bc", "abcd", parts, true);
574 EXPECT_EQ(parts.size(), 2);
575 EXPECT_EQ(parts[0], "a");
576 EXPECT_EQ(parts[1], "d");
579 string orig = "ab2342asdfv~~!";
580 folly::split("", orig, parts, true);
581 EXPECT_EQ(parts.size(), 1);
582 EXPECT_EQ(parts[0], orig);
585 folly::split("452x;o38asfsajsdlfdf.j", "asfds", parts, true);
586 EXPECT_EQ(parts.size(), 1);
587 EXPECT_EQ(parts[0], "asfds");
590 folly::split("a", "", parts, true);
591 EXPECT_EQ(parts.size(), 0);
594 folly::split("a", "", parts);
595 EXPECT_EQ(parts.size(), 1);
596 EXPECT_EQ(parts[0], "");
599 folly::split("a", StringPiece(), parts, true);
600 EXPECT_EQ(parts.size(), 0);
603 folly::split("a", StringPiece(), parts);
604 EXPECT_EQ(parts.size(), 1);
605 EXPECT_EQ(parts[0], "");
608 folly::split("a", "abcdefg", parts, true);
609 EXPECT_EQ(parts.size(), 1);
610 EXPECT_EQ(parts[0], "bcdefg");
613 orig = "All, , your base, are , , belong to us";
614 folly::split(", ", orig, parts, true);
615 EXPECT_EQ(parts.size(), 4);
616 EXPECT_EQ(parts[0], "All");
617 EXPECT_EQ(parts[1], "your base");
618 EXPECT_EQ(parts[2], "are ");
619 EXPECT_EQ(parts[3], "belong to us");
621 folly::split(", ", orig, parts);
622 EXPECT_EQ(parts.size(), 6);
623 EXPECT_EQ(parts[0], "All");
624 EXPECT_EQ(parts[1], "");
625 EXPECT_EQ(parts[2], "your base");
626 EXPECT_EQ(parts[3], "are ");
627 EXPECT_EQ(parts[4], "");
628 EXPECT_EQ(parts[5], "belong to us");
631 orig = ", Facebook, rul,es!, ";
632 folly::split(", ", orig, parts, true);
633 EXPECT_EQ(parts.size(), 2);
634 EXPECT_EQ(parts[0], "Facebook");
635 EXPECT_EQ(parts[1], "rul,es!");
637 folly::split(", ", orig, parts);
638 EXPECT_EQ(parts.size(), 4);
639 EXPECT_EQ(parts[0], "");
640 EXPECT_EQ(parts[1], "Facebook");
641 EXPECT_EQ(parts[2], "rul,es!");
642 EXPECT_EQ(parts[3], "");
645 template<template<class,class> class VectorType>
647 VectorType<StringPiece,std::allocator<StringPiece> > pieces;
648 VectorType<StringPiece,std::allocator<StringPiece> > pieces2;
650 folly::split(',', "a,b,c", pieces);
651 EXPECT_EQ(pieces.size(), 3);
652 EXPECT_EQ(pieces[0], "a");
653 EXPECT_EQ(pieces[1], "b");
654 EXPECT_EQ(pieces[2], "c");
658 folly::split(',', "a,,c", pieces);
659 EXPECT_EQ(pieces.size(), 3);
660 EXPECT_EQ(pieces[0], "a");
661 EXPECT_EQ(pieces[1], "");
662 EXPECT_EQ(pieces[2], "c");
665 folly::split(',', "a,,c", pieces, true);
666 EXPECT_EQ(pieces.size(), 2);
667 EXPECT_EQ(pieces[0], "a");
668 EXPECT_EQ(pieces[1], "c");
671 folly::split(',', ",,a,,c,,,", pieces, true);
672 EXPECT_EQ(pieces.size(), 2);
673 EXPECT_EQ(pieces[0], "a");
674 EXPECT_EQ(pieces[1], "c");
677 // test multiple split w/o clear
678 folly::split(',', ",,a,,c,,,", pieces, true);
679 EXPECT_EQ(pieces.size(), 2);
680 EXPECT_EQ(pieces[0], "a");
681 EXPECT_EQ(pieces[1], "c");
682 folly::split(',', ",,a,,c,,,", pieces, true);
683 EXPECT_EQ(pieces.size(), 4);
684 EXPECT_EQ(pieces[2], "a");
685 EXPECT_EQ(pieces[3], "c");
688 // test multiple split rounds
689 folly::split(",", "a_b,c_d", pieces);
690 EXPECT_EQ(pieces.size(), 2);
691 EXPECT_EQ(pieces[0], "a_b");
692 EXPECT_EQ(pieces[1], "c_d");
693 folly::split("_", pieces[0], pieces2);
694 EXPECT_EQ(pieces2.size(), 2);
695 EXPECT_EQ(pieces2[0], "a");
696 EXPECT_EQ(pieces2[1], "b");
698 folly::split("_", pieces[1], pieces2);
699 EXPECT_EQ(pieces2.size(), 2);
700 EXPECT_EQ(pieces2[0], "c");
701 EXPECT_EQ(pieces2[1], "d");
705 // test splits that with multi-line delimiter
706 folly::split("ab", "dabcabkdbkab", pieces, true);
707 EXPECT_EQ(pieces.size(), 3);
708 EXPECT_EQ(pieces[0], "d");
709 EXPECT_EQ(pieces[1], "c");
710 EXPECT_EQ(pieces[2], "kdbk");
713 string orig = "ab2342asdfv~~!";
714 folly::split("", orig.c_str(), pieces, true);
715 EXPECT_EQ(pieces.size(), 1);
716 EXPECT_EQ(pieces[0], orig);
719 folly::split("452x;o38asfsajsdlfdf.j", "asfds", pieces, true);
720 EXPECT_EQ(pieces.size(), 1);
721 EXPECT_EQ(pieces[0], "asfds");
724 folly::split("a", "", pieces, true);
725 EXPECT_EQ(pieces.size(), 0);
728 folly::split("a", "", pieces);
729 EXPECT_EQ(pieces.size(), 1);
730 EXPECT_EQ(pieces[0], "");
733 folly::split("a", "abcdefg", pieces, true);
734 EXPECT_EQ(pieces.size(), 1);
735 EXPECT_EQ(pieces[0], "bcdefg");
738 orig = "All, , your base, are , , belong to us";
739 folly::split(", ", orig, pieces, true);
740 EXPECT_EQ(pieces.size(), 4);
741 EXPECT_EQ(pieces[0], "All");
742 EXPECT_EQ(pieces[1], "your base");
743 EXPECT_EQ(pieces[2], "are ");
744 EXPECT_EQ(pieces[3], "belong to us");
746 folly::split(", ", orig, pieces);
747 EXPECT_EQ(pieces.size(), 6);
748 EXPECT_EQ(pieces[0], "All");
749 EXPECT_EQ(pieces[1], "");
750 EXPECT_EQ(pieces[2], "your base");
751 EXPECT_EQ(pieces[3], "are ");
752 EXPECT_EQ(pieces[4], "");
753 EXPECT_EQ(pieces[5], "belong to us");
756 orig = ", Facebook, rul,es!, ";
757 folly::split(", ", orig, pieces, true);
758 EXPECT_EQ(pieces.size(), 2);
759 EXPECT_EQ(pieces[0], "Facebook");
760 EXPECT_EQ(pieces[1], "rul,es!");
762 folly::split(", ", orig, pieces);
763 EXPECT_EQ(pieces.size(), 4);
764 EXPECT_EQ(pieces[0], "");
765 EXPECT_EQ(pieces[1], "Facebook");
766 EXPECT_EQ(pieces[2], "rul,es!");
767 EXPECT_EQ(pieces[3], "");
770 const char* str = "a,b";
771 folly::split(',', StringPiece(str), pieces);
772 EXPECT_EQ(pieces.size(), 2);
773 EXPECT_EQ(pieces[0], "a");
774 EXPECT_EQ(pieces[1], "b");
775 EXPECT_EQ(pieces[0].start(), str);
776 EXPECT_EQ(pieces[1].start(), str + 2);
778 std::set<StringPiece> unique;
779 folly::splitTo<StringPiece>(":", "asd:bsd:asd:asd:bsd:csd::asd",
780 std::inserter(unique, unique.begin()), true);
781 EXPECT_EQ(unique.size(), 3);
782 if (unique.size() == 3) {
783 EXPECT_EQ(*unique.begin(), "asd");
784 EXPECT_EQ(*--unique.end(), "csd");
787 VectorType<fbstring,std::allocator<fbstring> > blah;
788 folly::split('-', "a-b-c-d-f-e", blah);
789 EXPECT_EQ(blah.size(), 6);
794 TEST(Split, split_vector) {
795 splitTest<std::vector>();
797 TEST(Split, split_fbvector) {
798 splitTest<folly::fbvector>();
800 TEST(Split, pieces_vector) {
801 piecesTest<std::vector>();
803 TEST(Split, pieces_fbvector) {
804 piecesTest<folly::fbvector>();
808 StringPiece a, b, c, d;
810 EXPECT_TRUE(folly::split<false>('.', "a.b.c.d", a, b, c, d));
811 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
812 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
813 EXPECT_TRUE(folly::split<false>('.', "a", a));
815 EXPECT_TRUE(folly::split('.', "a.b.c.d", a, b, c, d));
816 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
817 EXPECT_TRUE(folly::split('.', "a.b", a, b));
818 EXPECT_TRUE(folly::split('.', "a", a));
820 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
824 EXPECT_FALSE(folly::split<false>('.', "a.b", a, b, c));
825 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b));
829 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
833 EXPECT_FALSE(folly::split('.', "a.b.c", a, b));
834 EXPECT_FALSE(folly::split('.', "a.b", a, b, c));
836 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
839 EXPECT_FALSE(folly::split<false>('.', "a", a, b));
840 EXPECT_TRUE(folly::split<false>('.', "a.b", a));
843 EXPECT_TRUE(folly::split('.', "a.b", a, b));
846 EXPECT_FALSE(folly::split('.', "a", a, b));
847 EXPECT_FALSE(folly::split('.', "a.b", a));
850 TEST(Split, std_string_fixed) {
851 std::string a, b, c, d;
853 EXPECT_TRUE(folly::split<false>('.', "a.b.c.d", a, b, c, d));
854 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
855 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
856 EXPECT_TRUE(folly::split<false>('.', "a", a));
858 EXPECT_TRUE(folly::split('.', "a.b.c.d", a, b, c, d));
859 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
860 EXPECT_TRUE(folly::split('.', "a.b", a, b));
861 EXPECT_TRUE(folly::split('.', "a", a));
863 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b, c));
867 EXPECT_FALSE(folly::split<false>('.', "a.b", a, b, c));
868 EXPECT_TRUE(folly::split<false>('.', "a.b.c", a, b));
872 EXPECT_TRUE(folly::split('.', "a.b.c", a, b, c));
876 EXPECT_FALSE(folly::split('.', "a.b.c", a, b));
877 EXPECT_FALSE(folly::split('.', "a.b", a, b, c));
879 EXPECT_TRUE(folly::split<false>('.', "a.b", a, b));
882 EXPECT_FALSE(folly::split<false>('.', "a", a, b));
883 EXPECT_TRUE(folly::split<false>('.', "a.b", a));
886 EXPECT_TRUE(folly::split('.', "a.b", a, b));
889 EXPECT_FALSE(folly::split('.', "a", a, b));
890 EXPECT_FALSE(folly::split('.', "a.b", a));
893 TEST(Split, fixed_convert) {
898 EXPECT_TRUE(folly::split(':', "a:13:14.7:b", a, b, c, d));
901 EXPECT_NEAR(14.7, c, 1e-10);
904 EXPECT_TRUE(folly::split<false>(':', "b:14:15.3:c", a, b, c, d));
907 EXPECT_NEAR(15.3, c, 1e-10);
910 EXPECT_FALSE(folly::split(':', "a:13:14.7:b", a, b, d));
912 EXPECT_TRUE(folly::split<false>(':', "a:13:14.7:b", a, b, d));
915 EXPECT_EQ("14.7:b", d);
918 // Enable verifying that a line only contains one field
919 EXPECT_TRUE(folly::split(' ', "hello", a));
920 EXPECT_FALSE(folly::split(' ', "hello world", a));
930 enum class ColorErrorCode { INVALID_COLOR };
932 struct ColorError : std::runtime_error {
933 using std::runtime_error::runtime_error;
936 ColorError makeConversionError(ColorErrorCode, StringPiece sp) {
937 return ColorError("Invalid my::Color representation : " + sp.str());
940 Expected<StringPiece, ColorErrorCode> parseTo(
942 Color& out) noexcept {
945 } else if (in == "B") {
948 return makeUnexpected(ColorErrorCode::INVALID_COLOR);
950 return StringPiece(in.end(), in.end());
954 TEST(Split, fixed_convert_custom) {
957 EXPECT_TRUE(folly::split(',', "R,B", c1, c2));
958 EXPECT_EQ(c1, my::Color::Red);
959 EXPECT_EQ(c2, my::Color::Blue);
961 EXPECT_THROW(folly::split(',', "B,G", c1, c2), my::ColorError);
967 std::vector<int> empty = { };
968 join(":", empty, output);
969 EXPECT_TRUE(output.empty());
971 std::vector<std::string> input1 = { "1", "23", "456", "" };
972 join(':', input1, output);
973 EXPECT_EQ(output, "1:23:456:");
974 output = join(':', input1);
975 EXPECT_EQ(output, "1:23:456:");
977 auto input2 = { 1, 23, 456 };
978 join("-*-", input2, output);
979 EXPECT_EQ(output, "1-*-23-*-456");
980 output = join("-*-", input2);
981 EXPECT_EQ(output, "1-*-23-*-456");
983 auto input3 = { 'f', 'a', 'c', 'e', 'b', 'o', 'o', 'k' };
984 join("", input3, output);
985 EXPECT_EQ(output, "facebook");
987 join("_", { "", "f", "a", "c", "e", "b", "o", "o", "k", "" }, output);
988 EXPECT_EQ(output, "_f_a_c_e_b_o_o_k_");
990 output = join("", input3.begin(), input3.end());
991 EXPECT_EQ(output, "facebook");
994 TEST(String, hexlify) {
995 string input1 = "0123";
997 EXPECT_TRUE(hexlify(input1, output1));
998 EXPECT_EQ("30313233", output1);
1000 fbstring input2 = "abcdefg";
1005 EXPECT_TRUE(hexlify(input2, output2));
1006 EXPECT_EQ("610063ff65b667", output2);
1008 EXPECT_EQ("666f6f626172", hexlify("foobar"));
1009 auto bytes = folly::make_array<uint8_t>(1, 2, 3, 4);
1010 EXPECT_EQ("01020304", hexlify(ByteRange{bytes.data(), bytes.size()}));
1013 TEST(String, unhexlify) {
1014 string input1 = "30313233";
1016 EXPECT_TRUE(unhexlify(input1, output1));
1017 EXPECT_EQ(output1, "0123");
1019 fbstring input2 = "610063ff65b667";
1021 EXPECT_TRUE(unhexlify(input2, output2));
1022 EXPECT_EQ(output2.size(), 7);
1023 EXPECT_EQ(output2[0], 'a');
1024 EXPECT_EQ(output2[1], 0);
1025 EXPECT_EQ(output2[2], 'c');
1026 EXPECT_EQ(output2[3] & 0xff, 0xff);
1027 EXPECT_EQ(output2[4], 'e');
1028 EXPECT_EQ(output2[5] & 0xff, 0xb6);
1029 EXPECT_EQ(output2[6], 'g');
1031 string input3 = "x";
1033 EXPECT_FALSE(unhexlify(input3, output3));
1035 string input4 = "xy";
1037 EXPECT_FALSE(unhexlify(input4, output4));
1039 EXPECT_EQ("foobar", unhexlify("666f6f626172"));
1040 EXPECT_EQ(StringPiece("foo\0bar", 7), unhexlify("666f6f00626172"));
1041 EXPECT_THROW(unhexlify("666f6fzz626172"), std::domain_error);
1044 TEST(String, backslashify) {
1045 EXPECT_EQ("abc", string("abc"));
1046 EXPECT_EQ("abc", backslashify(string("abc")));
1047 EXPECT_EQ("abc\\r", backslashify(string("abc\r")));
1048 EXPECT_EQ("abc\\x0d", backslashify(string("abc\r"), true));
1049 EXPECT_EQ("\\0\\0", backslashify(string(2, '\0')));
1052 TEST(String, humanify) {
1053 // Simple cases; output is obvious.
1054 EXPECT_EQ("abc", humanify(string("abc")));
1055 EXPECT_EQ("abc\\\\r", humanify(string("abc\\r")));
1056 EXPECT_EQ("0xff", humanify(string("\xff")));
1057 EXPECT_EQ("abc\\xff", humanify(string("abc\xff")));
1058 EXPECT_EQ("abc\\b", humanify(string("abc\b")));
1059 EXPECT_EQ("0x00", humanify(string(1, '\0')));
1060 EXPECT_EQ("0x0000", humanify(string(2, '\0')));
1063 // Mostly printable, so backslash! 80, 60, and 40% printable, respectively
1064 EXPECT_EQ("aaaa\\xff", humanify(string("aaaa\xff")));
1065 EXPECT_EQ("aaa\\xff\\xff", humanify(string("aaa\xff\xff")));
1066 EXPECT_EQ("aa\\xff\\xff\\xff", humanify(string("aa\xff\xff\xff")));
1068 // 20% printable, and the printable portion isn't the prefix; hexify!
1069 EXPECT_EQ("0xff61ffffff", humanify(string("\xff" "a\xff\xff\xff")));
1071 // Same as previous, except swap first two chars; prefix is
1072 // printable and within the threshold, so backslashify.
1073 EXPECT_EQ("a\\xff\\xff\\xff\\xff", humanify(string("a\xff\xff\xff\xff")));
1075 // Just too much unprintable; hex, despite prefix.
1076 EXPECT_EQ("0x61ffffffffff", humanify(string("a\xff\xff\xff\xff\xff")));
1082 * Copy bytes from src to somewhere in the buffer referenced by dst. The
1083 * actual starting position of the copy will be the first address in the
1084 * destination buffer whose address mod 8 is equal to the src address mod 8.
1085 * The caller is responsible for ensuring that the destination buffer has
1086 * enough extra space to accommodate the shifted copy.
1088 char* copyWithSameAlignment(char* dst, const char* src, size_t length) {
1089 const char* originalDst = dst;
1090 size_t dstOffset = size_t(dst) & 0x7;
1091 size_t srcOffset = size_t(src) & 0x7;
1092 while (dstOffset != srcOffset) {
1097 CHECK(dst <= originalDst + 7);
1098 CHECK((size_t(dst) & 0x7) == (size_t(src) & 0x7));
1099 memcpy(dst, src, length);
1103 void testToLowerAscii(Range<const char*> src) {
1104 // Allocate extra space so we can make copies that start at the
1105 // same alignment (byte, word, quadword, etc) as the source buffer.
1106 auto controlBuf = std::vector<char>(src.size() + 7);
1108 copyWithSameAlignment(controlBuf.data(), src.begin(), src.size());
1110 auto testBuf = std::vector<char>(src.size() + 7);
1111 char* test = copyWithSameAlignment(testBuf.data(), src.begin(), src.size());
1113 for (size_t i = 0; i < src.size(); i++) {
1114 control[i] = tolower(control[i]);
1116 toLowerAscii(test, src.size());
1117 for (size_t i = 0; i < src.size(); i++) {
1118 EXPECT_EQ(control[i], test[i]);
1124 TEST(String, toLowerAsciiAligned) {
1125 static const size_t kSize = 256;
1127 for (size_t i = 0; i < kSize; i++) {
1128 input[i] = (char)(i & 0xff);
1130 testToLowerAscii(Range<const char*>(input, kSize));
1133 TEST(String, toLowerAsciiUnaligned) {
1134 static const size_t kSize = 256;
1136 for (size_t i = 0; i < kSize; i++) {
1137 input[i] = (char)(i & 0xff);
1139 // Test input buffers of several lengths to exercise all the
1140 // cases: buffer at the start/middle/end of an aligned block, plus
1141 // buffers that span multiple aligned blocks. The longest test input
1142 // is 3 unaligned bytes + 4 32-bit aligned bytes + 8 64-bit aligned
1143 // + 4 32-bit aligned + 3 unaligned = 22 bytes.
1144 for (size_t length = 1; length < 23; length++) {
1145 for (size_t offset = 0; offset + length <= kSize; offset++) {
1146 testToLowerAscii(Range<const char*>(input + offset, length));
1151 TEST(String, whitespace) {
1153 EXPECT_EQ("kavabanga",
1154 trimWhitespace("kavabanga"));
1155 EXPECT_EQ("kavabanga",
1156 trimWhitespace("kavabanga \t \n "));
1157 EXPECT_EQ("kavabanga",
1158 trimWhitespace(" \t \r \n \n kavabanga"));
1159 EXPECT_EQ("kavabanga",
1160 trimWhitespace("\t \r \n kavabanga \t \n "));
1161 EXPECT_EQ("kavabanga",
1162 trimWhitespace(" \t \r \n \n kavabanga"));
1163 EXPECT_EQ("kavabanga",
1164 trimWhitespace("\t \r \n kavabanga \t \n "));
1166 ltrimWhitespace(rtrimWhitespace("kavabanga")),
1167 rtrimWhitespace(ltrimWhitespace("kavabanga")));
1169 ltrimWhitespace(rtrimWhitespace("kavabanga \r\t\n")),
1170 rtrimWhitespace(ltrimWhitespace("kavabanga \r\t\n")));
1171 EXPECT_EQ("", trimWhitespace("\t \r \n \t \n "));
1172 EXPECT_EQ("", trimWhitespace(""));
1173 EXPECT_EQ("", trimWhitespace("\t"));
1174 EXPECT_EQ("", trimWhitespace("\r"));
1175 EXPECT_EQ("", trimWhitespace("\n"));
1176 EXPECT_EQ("", trimWhitespace("\t "));
1177 EXPECT_EQ("", trimWhitespace("\r "));
1178 EXPECT_EQ("", trimWhitespace("\n "));
1179 EXPECT_EQ("", trimWhitespace(" \t"));
1180 EXPECT_EQ("", trimWhitespace(" \r"));
1181 EXPECT_EQ("", trimWhitespace(" \n"));
1184 EXPECT_EQ("kavabanga", ltrimWhitespace("\t kavabanga"));
1185 EXPECT_EQ("kavabanga \r\n", ltrimWhitespace("\t kavabanga \r\n"));
1186 EXPECT_EQ("", ltrimWhitespace("\r "));
1187 EXPECT_EQ("", ltrimWhitespace("\n "));
1188 EXPECT_EQ("", ltrimWhitespace("\r "));
1191 EXPECT_EQ("\t kavabanga", rtrimWhitespace("\t kavabanga"));
1192 EXPECT_EQ("\t kavabanga", rtrimWhitespace("\t kavabanga \r\n"));
1193 EXPECT_EQ("", rtrimWhitespace("\r "));
1194 EXPECT_EQ("", rtrimWhitespace("\n "));
1195 EXPECT_EQ("", rtrimWhitespace("\r "));
1198 TEST(String, stripLeftMargin_really_empty) {
1201 EXPECT_EQ(expected, stripLeftMargin(input));
1204 TEST(String, stripLeftMargin_empty) {
1205 auto input = R"TEXT(
1208 EXPECT_EQ(expected, stripLeftMargin(input));
1211 TEST(String, stripLeftMargin_only_whitespace) {
1212 // using ~ as a marker
1213 string input = R"TEXT(
1216 input = boost::regex_replace(input, boost::regex("~"), "");
1217 EXPECT_EQ("\n \n ", input);
1218 auto expected = "\n";
1219 EXPECT_EQ(expected, stripLeftMargin(input));
1222 TEST(String, stripLeftMargin_only_uneven_whitespace) {
1223 // using ~ as a marker1
1224 string input = R"TEXT(
1228 input = boost::regex_replace(input, boost::regex("~"), "");
1229 EXPECT_EQ("\n \n \n ", input);
1230 auto expected = "\n\n";
1232 EXPECT_EQ(expected, stripLeftMargin(input));
1235 TEST(String, stripLeftMargin_one_line) {
1236 auto input = R"TEXT(
1239 auto expected = "hi there bob!\n";
1240 EXPECT_EQ(expected, stripLeftMargin(input));
1243 TEST(String, stripLeftMargin_two_lines) {
1244 auto input = R"TEXT(
1248 auto expected = "hi there bob!\nnice weather today!\n";
1249 EXPECT_EQ(expected, stripLeftMargin(input));
1252 TEST(String, stripLeftMargin_three_lines_uneven) {
1253 auto input = R"TEXT(
1258 auto expected = " hi there bob!\nnice weather today!\n so long!\n";
1259 EXPECT_EQ(expected, stripLeftMargin(input));
1262 TEST(String, stripLeftMargin_preceding_blank_lines) {
1263 auto input = R"TEXT(
1268 auto expected = "\n\nhi there bob!\n";
1269 EXPECT_EQ(expected, stripLeftMargin(input));
1272 TEST(String, stripLeftMargin_succeeding_blank_lines) {
1273 auto input = R"TEXT(
1278 auto expected = "hi there bob!\n\n\n";
1279 EXPECT_EQ(expected, stripLeftMargin(input));
1282 TEST(String, stripLeftMargin_interstitial_undented_whiteline) {
1283 // using ~ as a marker
1284 string input = R"TEXT(
1289 input = boost::regex_replace(input, boost::regex(" +~"), "");
1290 EXPECT_EQ("\n hi there bob!\n\n so long!\n ", input);
1291 auto expected = "hi there bob!\n\nso long!\n";
1292 EXPECT_EQ(expected, stripLeftMargin(input));
1295 TEST(String, stripLeftMargin_interstitial_dedented_whiteline) {
1296 // using ~ as a marker
1297 string input = R"TEXT(
1302 input = boost::regex_replace(input, boost::regex("~"), "");
1303 EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
1304 auto expected = "hi there bob!\n\nso long!\n";
1305 EXPECT_EQ(expected, stripLeftMargin(input));
1308 TEST(String, stripLeftMargin_interstitial_equidented_whiteline) {
1309 // using ~ as a marker
1310 string input = R"TEXT(
1315 input = boost::regex_replace(input, boost::regex("~"), "");
1316 EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
1317 auto expected = "hi there bob!\n\nso long!\n";
1318 EXPECT_EQ(expected, stripLeftMargin(input));
1321 TEST(String, stripLeftMargin_interstitial_indented_whiteline) {
1322 // using ~ as a marker
1323 string input = R"TEXT(
1328 input = boost::regex_replace(input, boost::regex("~"), "");
1329 EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
1330 auto expected = "hi there bob!\n \nso long!\n";
1331 EXPECT_EQ(expected, stripLeftMargin(input));
1334 TEST(String, stripLeftMargin_no_pre_whitespace) {
1335 // using ~ as a marker
1336 string input = R"TEXT( hi there bob!
1340 input = boost::regex_replace(input, boost::regex("~"), "");
1341 EXPECT_EQ(" hi there bob!\n \n so long!\n ", input);
1342 auto expected = "hi there bob!\n \nso long!\n";
1343 EXPECT_EQ(expected, stripLeftMargin(input));
1346 TEST(String, stripLeftMargin_no_post_whitespace) {
1347 // using ~ as a marker
1348 string input = R"TEXT(
1352 input = boost::regex_replace(input, boost::regex("~"), "");
1353 EXPECT_EQ("\n hi there bob!\n \n so long! ", input);
1354 auto expected = "hi there bob!\n \nso long! ";
1355 EXPECT_EQ(expected, stripLeftMargin(input));
1358 const folly::StringPiece kTestUTF8 = u8"This is \U0001F602 stuff!";
1360 TEST(UTF8StringPiece, valid_utf8) {
1361 folly::StringPiece sp = kTestUTF8;
1362 UTF8StringPiece utf8 = sp;
1363 // utf8.size() not available since it's not a random-access range
1364 EXPECT_EQ(16, utf8.walk_size());
1367 TEST(UTF8StringPiece, valid_suffix) {
1368 UTF8StringPiece utf8 = kTestUTF8.subpiece(8);
1369 EXPECT_EQ(8, utf8.walk_size());
1372 TEST(UTF8StringPiece, empty_mid_codepoint) {
1373 UTF8StringPiece utf8 = kTestUTF8.subpiece(9, 0); // okay since it's empty
1374 EXPECT_EQ(0, utf8.walk_size());
1377 TEST(UTF8StringPiece, invalid_mid_codepoint) {
1378 EXPECT_THROW(UTF8StringPiece(kTestUTF8.subpiece(9, 1)), std::out_of_range);
1381 TEST(UTF8StringPiece, valid_implicit_conversion) {
1382 std::string input = u8"\U0001F602\U0001F602\U0001F602";
1383 auto checkImplicitCtor = [](UTF8StringPiece implicitCtor) {
1384 return implicitCtor.walk_size();
1386 EXPECT_EQ(3, checkImplicitCtor(input));