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