1 | /* |
2 | * Copyright 2011-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 <boost/lexical_cast.hpp> |
22 | |
23 | #include <folly/Conv.h> |
24 | #include <folly/container/Foreach.h> |
25 | #include <folly/portability/GTest.h> |
26 | |
27 | #include <algorithm> |
28 | #include <cinttypes> |
29 | #include <limits> |
30 | #include <sstream> |
31 | #include <stdexcept> |
32 | #include <tuple> |
33 | |
34 | using namespace std; |
35 | using namespace folly; |
36 | |
37 | TEST(Conv, digits10) { |
38 | char buffer[100]; |
39 | uint64_t power; |
40 | |
41 | // first, some basic sniff tests |
42 | EXPECT_EQ(1, digits10(0)); |
43 | EXPECT_EQ(1, digits10(1)); |
44 | EXPECT_EQ(1, digits10(9)); |
45 | EXPECT_EQ(2, digits10(10)); |
46 | EXPECT_EQ(2, digits10(99)); |
47 | EXPECT_EQ(3, digits10(100)); |
48 | EXPECT_EQ(3, digits10(999)); |
49 | EXPECT_EQ(4, digits10(1000)); |
50 | EXPECT_EQ(4, digits10(9999)); |
51 | EXPECT_EQ(20, digits10(18446744073709551615ULL)); |
52 | |
53 | // try the first X nonnegatives. |
54 | // Covers some more cases of 2^p, 10^p |
55 | for (uint64_t i = 0; i < 100000; i++) { |
56 | snprintf(buffer, sizeof(buffer), "%" PRIu64, i); |
57 | EXPECT_EQ(strlen(buffer), digits10(i)); |
58 | } |
59 | |
60 | // try powers of 2 |
61 | power = 1; |
62 | for (int p = 0; p < 64; p++) { |
63 | snprintf(buffer, sizeof(buffer), "%" PRIu64, power); |
64 | EXPECT_EQ(strlen(buffer), digits10(power)); |
65 | snprintf(buffer, sizeof(buffer), "%" PRIu64, power - 1); |
66 | EXPECT_EQ(strlen(buffer), digits10(power - 1)); |
67 | snprintf(buffer, sizeof(buffer), "%" PRIu64, power + 1); |
68 | EXPECT_EQ(strlen(buffer), digits10(power + 1)); |
69 | power *= 2; |
70 | } |
71 | |
72 | // try powers of 10 |
73 | power = 1; |
74 | for (int p = 0; p < 20; p++) { |
75 | snprintf(buffer, sizeof(buffer), "%" PRIu64, power); |
76 | EXPECT_EQ(strlen(buffer), digits10(power)); |
77 | snprintf(buffer, sizeof(buffer), "%" PRIu64, power - 1); |
78 | EXPECT_EQ(strlen(buffer), digits10(power - 1)); |
79 | snprintf(buffer, sizeof(buffer), "%" PRIu64, power + 1); |
80 | EXPECT_EQ(strlen(buffer), digits10(power + 1)); |
81 | power *= 10; |
82 | } |
83 | } |
84 | |
85 | // Test to<T>(T) |
86 | TEST(Conv, Type2Type) { |
87 | bool boolV = true; |
88 | EXPECT_EQ(to<bool>(boolV), true); |
89 | |
90 | int intV = 42; |
91 | EXPECT_EQ(to<int>(intV), 42); |
92 | |
93 | float floatV = 4.2f; |
94 | EXPECT_EQ(to<float>(floatV), 4.2f); |
95 | |
96 | double doubleV = 0.42; |
97 | EXPECT_EQ(to<double>(doubleV), 0.42); |
98 | |
99 | std::string stringV = "StdString" ; |
100 | EXPECT_EQ(to<std::string>(stringV), "StdString" ); |
101 | |
102 | folly::fbstring fbStrV = "FBString" ; |
103 | EXPECT_EQ(to<folly::fbstring>(fbStrV), "FBString" ); |
104 | |
105 | folly::StringPiece spV("StringPiece" ); |
106 | EXPECT_EQ(to<folly::StringPiece>(spV), "StringPiece" ); |
107 | |
108 | // Rvalues |
109 | EXPECT_EQ(to<bool>(true), true); |
110 | EXPECT_EQ(to<int>(42), 42); |
111 | EXPECT_EQ(to<float>(4.2f), 4.2f); |
112 | EXPECT_EQ(to<double>(.42), .42); |
113 | EXPECT_EQ(to<std::string>(std::string("Hello" )), "Hello" ); |
114 | EXPECT_EQ(to<folly::fbstring>(folly::fbstring("hello" )), "hello" ); |
115 | EXPECT_EQ( |
116 | to<folly::StringPiece>(folly::StringPiece("Forty Two" )), "Forty Two" ); |
117 | } |
118 | |
119 | TEST(Conv, Integral2Integral) { |
120 | // Same size, different signs |
121 | int64_t s64 = numeric_limits<uint8_t>::max(); |
122 | EXPECT_EQ(to<uint8_t>(s64), s64); |
123 | |
124 | s64 = numeric_limits<int8_t>::max(); |
125 | EXPECT_EQ(to<int8_t>(s64), s64); |
126 | } |
127 | |
128 | TEST(Conv, Floating2Floating) { |
129 | float f1 = 1e3f; |
130 | double d1 = to<double>(f1); |
131 | EXPECT_EQ(f1, d1); |
132 | |
133 | double d2 = 23.0; |
134 | auto f2 = to<float>(d2); |
135 | EXPECT_EQ(double(f2), d2); |
136 | |
137 | double invalidFloat = std::numeric_limits<double>::max(); |
138 | EXPECT_ANY_THROW(to<float>(invalidFloat)); |
139 | invalidFloat = -std::numeric_limits<double>::max(); |
140 | EXPECT_ANY_THROW(to<float>(invalidFloat)); |
141 | |
142 | try { |
143 | auto shouldWork = to<float>(std::numeric_limits<double>::min()); |
144 | // The value of `shouldWork' is an implementation defined choice |
145 | // between the following two alternatives. |
146 | EXPECT_TRUE( |
147 | shouldWork == std::numeric_limits<float>::min() || shouldWork == 0.f); |
148 | } catch (...) { |
149 | ADD_FAILURE(); |
150 | } |
151 | } |
152 | |
153 | template <class String> |
154 | void testIntegral2String() {} |
155 | |
156 | template <class String, class Int, class... Ints> |
157 | void testIntegral2String() { |
158 | typedef typename make_unsigned<Int>::type Uint; |
159 | typedef typename make_signed<Int>::type Sint; |
160 | |
161 | Uint value = 123; |
162 | EXPECT_EQ(to<String>(value), "123" ); |
163 | Sint svalue = 123; |
164 | EXPECT_EQ(to<String>(svalue), "123" ); |
165 | svalue = -123; |
166 | EXPECT_EQ(to<String>(svalue), "-123" ); |
167 | |
168 | value = numeric_limits<Uint>::min(); |
169 | EXPECT_EQ(to<Uint>(to<String>(value)), value); |
170 | value = numeric_limits<Uint>::max(); |
171 | EXPECT_EQ(to<Uint>(to<String>(value)), value); |
172 | |
173 | svalue = numeric_limits<Sint>::min(); |
174 | EXPECT_EQ(to<Sint>(to<String>(svalue)), svalue); |
175 | value = numeric_limits<Sint>::max(); |
176 | EXPECT_EQ(to<Sint>(to<String>(svalue)), svalue); |
177 | |
178 | testIntegral2String<String, Ints...>(); |
179 | } |
180 | |
181 | #if FOLLY_HAVE_INT128_T |
182 | template <class String> |
183 | void test128Bit2String() { |
184 | typedef unsigned __int128 Uint; |
185 | typedef __int128 Sint; |
186 | |
187 | EXPECT_EQ(detail::digitsEnough<unsigned __int128>(), 39); |
188 | |
189 | Uint value = 123; |
190 | EXPECT_EQ(to<String>(value), "123" ); |
191 | Sint svalue = 123; |
192 | EXPECT_EQ(to<String>(svalue), "123" ); |
193 | svalue = -123; |
194 | EXPECT_EQ(to<String>(svalue), "-123" ); |
195 | |
196 | value = __int128(1) << 64; |
197 | EXPECT_EQ(to<String>(value), "18446744073709551616" ); |
198 | |
199 | svalue = -(__int128(1) << 64); |
200 | EXPECT_EQ(to<String>(svalue), "-18446744073709551616" ); |
201 | |
202 | value = 0; |
203 | EXPECT_EQ(to<String>(value), "0" ); |
204 | |
205 | svalue = 0; |
206 | EXPECT_EQ(to<String>(svalue), "0" ); |
207 | |
208 | value = ~__int128(0); |
209 | EXPECT_EQ(to<String>(value), "340282366920938463463374607431768211455" ); |
210 | |
211 | svalue = -(Uint(1) << 127); |
212 | EXPECT_EQ(to<String>(svalue), "-170141183460469231731687303715884105728" ); |
213 | |
214 | svalue = (Uint(1) << 127) - 1; |
215 | EXPECT_EQ(to<String>(svalue), "170141183460469231731687303715884105727" ); |
216 | |
217 | // TODO: the following do not compile to<__int128> ... |
218 | |
219 | #if 0 |
220 | value = numeric_limits<Uint>::min(); |
221 | EXPECT_EQ(to<Uint>(to<String>(value)), value); |
222 | value = numeric_limits<Uint>::max(); |
223 | EXPECT_EQ(to<Uint>(to<String>(value)), value); |
224 | |
225 | svalue = numeric_limits<Sint>::min(); |
226 | EXPECT_EQ(to<Sint>(to<String>(svalue)), svalue); |
227 | value = numeric_limits<Sint>::max(); |
228 | EXPECT_EQ(to<Sint>(to<String>(svalue)), svalue); |
229 | #endif |
230 | } |
231 | |
232 | #endif |
233 | |
234 | TEST(Conv, Integral2String) { |
235 | testIntegral2String<std::string, int8_t, int16_t, int32_t, int64_t>(); |
236 | testIntegral2String<fbstring, int8_t, int16_t, int32_t, int64_t>(); |
237 | |
238 | #if FOLLY_HAVE_INT128_T |
239 | test128Bit2String<std::string>(); |
240 | test128Bit2String<fbstring>(); |
241 | #endif |
242 | } |
243 | |
244 | template <class String> |
245 | void testString2Integral() {} |
246 | |
247 | template <class String, class Int, class... Ints> |
248 | void testString2Integral() { |
249 | typedef typename make_unsigned<Int>::type Uint; |
250 | typedef typename make_signed<Int>::type Sint; |
251 | |
252 | // Unsigned numbers small enough to fit in a signed type |
253 | static const String strings[] = { |
254 | "0" , |
255 | "00" , |
256 | "2 " , |
257 | " 84" , |
258 | " \n 123 \t\n" , |
259 | " 127" , |
260 | "0000000000000000000000000042" , |
261 | }; |
262 | static const Uint values[] = { |
263 | 0, |
264 | 0, |
265 | 2, |
266 | 84, |
267 | 123, |
268 | 127, |
269 | 42, |
270 | }; |
271 | FOR_EACH_RANGE (i, 0, sizeof(strings) / sizeof(*strings)) { |
272 | EXPECT_EQ(to<Uint>(strings[i]), values[i]); |
273 | EXPECT_EQ(to<Sint>(strings[i]), values[i]); |
274 | } |
275 | |
276 | // Unsigned numbers that won't fit in the signed variation |
277 | static const String uStrings[] = { |
278 | " 128" , |
279 | "213" , |
280 | "255" , |
281 | }; |
282 | static const Uint uValues[] = { |
283 | 128, |
284 | 213, |
285 | 255, |
286 | }; |
287 | FOR_EACH_RANGE (i, 0, sizeof(uStrings) / sizeof(*uStrings)) { |
288 | EXPECT_EQ(to<Uint>(uStrings[i]), uValues[i]); |
289 | if (sizeof(Int) == 1) { |
290 | EXPECT_THROW(to<Sint>(uStrings[i]), std::range_error); |
291 | } |
292 | } |
293 | |
294 | if (sizeof(Int) >= 4) { |
295 | static const String strings2[] = { |
296 | "256" , |
297 | "6324 " , |
298 | "63245675 " , |
299 | "2147483647" , |
300 | }; |
301 | static const Uint values2[] = { |
302 | (Uint)256, |
303 | (Uint)6324, |
304 | (Uint)63245675, |
305 | (Uint)2147483647, |
306 | }; |
307 | FOR_EACH_RANGE (i, 0, sizeof(strings2) / sizeof(*strings2)) { |
308 | EXPECT_EQ(to<Uint>(strings2[i]), values2[i]); |
309 | EXPECT_EQ(to<Sint>(strings2[i]), values2[i]); |
310 | } |
311 | |
312 | static const String uStrings2[] = { |
313 | "2147483648" , |
314 | "3147483648" , |
315 | "4147483648" , |
316 | "4000000000" , |
317 | }; |
318 | static const Uint uValues2[] = { |
319 | (Uint)2147483648U, |
320 | (Uint)3147483648U, |
321 | (Uint)4147483648U, |
322 | (Uint)4000000000U, |
323 | }; |
324 | FOR_EACH_RANGE (i, 0, sizeof(uStrings2) / sizeof(uStrings2)) { |
325 | EXPECT_EQ(to<Uint>(uStrings2[i]), uValues2[i]); |
326 | if (sizeof(Int) == 4) { |
327 | EXPECT_THROW(to<Sint>(uStrings2[i]), std::range_error); |
328 | } |
329 | } |
330 | } |
331 | |
332 | if (sizeof(Int) >= 8) { |
333 | static_assert(sizeof(Int) <= 8, "Now that would be interesting" ); |
334 | static const String strings3[] = { |
335 | "2147483648" , |
336 | "5000000001" , |
337 | "25687346509278435" , |
338 | "100000000000000000" , |
339 | "9223372036854775807" , |
340 | }; |
341 | static const Uint values3[] = { |
342 | (Uint)2147483648ULL, |
343 | (Uint)5000000001ULL, |
344 | (Uint)25687346509278435ULL, |
345 | (Uint)100000000000000000ULL, |
346 | (Uint)9223372036854775807ULL, |
347 | }; |
348 | FOR_EACH_RANGE (i, 0, sizeof(strings3) / sizeof(*strings3)) { |
349 | EXPECT_EQ(to<Uint>(strings3[i]), values3[i]); |
350 | EXPECT_EQ(to<Sint>(strings3[i]), values3[i]); |
351 | } |
352 | |
353 | static const String uStrings3[] = { |
354 | "9223372036854775808" , |
355 | "9987435987394857987" , |
356 | "17873648761234698740" , |
357 | "18446744073709551615" , |
358 | }; |
359 | static const Uint uValues3[] = { |
360 | (Uint)9223372036854775808ULL, |
361 | (Uint)9987435987394857987ULL, |
362 | (Uint)17873648761234698740ULL, |
363 | (Uint)18446744073709551615ULL, |
364 | }; |
365 | FOR_EACH_RANGE (i, 0, sizeof(uStrings3) / sizeof(*uStrings3)) { |
366 | EXPECT_EQ(to<Uint>(uStrings3[i]), uValues3[i]); |
367 | if (sizeof(Int) == 8) { |
368 | EXPECT_THROW(to<Sint>(uStrings3[i]), std::range_error); |
369 | } |
370 | } |
371 | } |
372 | |
373 | // Minimum possible negative values, and negative sign overflow |
374 | static const String strings4[] = { |
375 | "-128" , |
376 | "-32768" , |
377 | "-2147483648" , |
378 | "-9223372036854775808" , |
379 | }; |
380 | static const String strings5[] = { |
381 | "-129" , |
382 | "-32769" , |
383 | "-2147483649" , |
384 | "-9223372036854775809" , |
385 | }; |
386 | static const Sint values4[] = { |
387 | (Sint)-128LL, |
388 | (Sint)-32768LL, |
389 | (Sint)-2147483648LL, |
390 | (Sint)(-9223372036854775807LL - 1), |
391 | }; |
392 | FOR_EACH_RANGE (i, 0, sizeof(strings4) / sizeof(*strings4)) { |
393 | if (sizeof(Int) > std::pow(2, i)) { |
394 | EXPECT_EQ(values4[i], to<Sint>(strings4[i])); |
395 | EXPECT_EQ(values4[i] - 1, to<Sint>(strings5[i])); |
396 | } else if (sizeof(Int) == std::pow(2, i)) { |
397 | EXPECT_EQ(values4[i], to<Sint>(strings4[i])); |
398 | EXPECT_THROW(to<Sint>(strings5[i]), std::range_error); |
399 | } else { |
400 | EXPECT_THROW(to<Sint>(strings4[i]), std::range_error); |
401 | EXPECT_THROW(to<Sint>(strings5[i]), std::range_error); |
402 | } |
403 | } |
404 | |
405 | // Bogus string values |
406 | static const String bogusStrings[] = { |
407 | "" , |
408 | "0x1234" , |
409 | "123L" , |
410 | "123a" , |
411 | "x 123 " , |
412 | "234 y" , |
413 | "- 42" , // whitespace is not allowed between the sign and the value |
414 | " + 13 " , |
415 | "12345678901234567890123456789" , |
416 | }; |
417 | for (const auto& str : bogusStrings) { |
418 | EXPECT_THROW(to<Sint>(str), std::range_error); |
419 | EXPECT_THROW(to<Uint>(str), std::range_error); |
420 | } |
421 | |
422 | // A leading '+' character is only allowed when converting to signed types. |
423 | String posSign("+42" ); |
424 | EXPECT_EQ(42, to<Sint>(posSign)); |
425 | EXPECT_THROW(to<Uint>(posSign), std::range_error); |
426 | |
427 | testString2Integral<String, Ints...>(); |
428 | } |
429 | |
430 | TEST(Conv, String2Integral) { |
431 | testString2Integral<const char*, int8_t, int16_t, int32_t, int64_t>(); |
432 | testString2Integral<std::string, int8_t, int16_t, int32_t, int64_t>(); |
433 | testString2Integral<fbstring, int8_t, int16_t, int32_t, int64_t>(); |
434 | |
435 | // Testing the behavior of the StringPiece* API |
436 | // StringPiece* normally parses as much valid data as it can, |
437 | // and advances the StringPiece to the end of the valid data. |
438 | char buf1[] = "100foo" ; |
439 | StringPiece sp1(buf1); |
440 | EXPECT_EQ(100, to<uint8_t>(&sp1)); |
441 | EXPECT_EQ(buf1 + 3, sp1.begin()); |
442 | // However, if the next character would cause an overflow it throws a |
443 | // range_error rather than consuming only as much as it can without |
444 | // overflowing. |
445 | char buf2[] = "1002" ; |
446 | StringPiece sp2(buf2); |
447 | EXPECT_THROW(to<uint8_t>(&sp2), std::range_error); |
448 | EXPECT_EQ(buf2, sp2.begin()); |
449 | } |
450 | |
451 | TEST(Conv, StringPiece2Integral) { |
452 | string s = " +123 hello world " ; |
453 | StringPiece sp = s; |
454 | EXPECT_EQ(to<int>(&sp), 123); |
455 | EXPECT_EQ(sp, " hello world " ); |
456 | } |
457 | |
458 | TEST(Conv, StringPieceAppend) { |
459 | string s = "foobar" ; |
460 | { |
461 | StringPiece sp(s, 0, 3); |
462 | string result = to<string>(s, sp); |
463 | EXPECT_EQ(result, "foobarfoo" ); |
464 | } |
465 | { |
466 | StringPiece sp1(s, 0, 3); |
467 | StringPiece sp2(s, 3, 3); |
468 | string result = to<string>(sp1, sp2); |
469 | EXPECT_EQ(result, s); |
470 | } |
471 | } |
472 | |
473 | TEST(Conv, BadStringToIntegral) { |
474 | // Note that leading spaces (e.g. " 1") are valid. |
475 | vector<string> v = {"a" , "" , " " , "\n" , " a0" , "abcdef" , "1Z" , "!#" }; |
476 | for (auto& s : v) { |
477 | EXPECT_THROW(to<int>(s), std::range_error) << "s=" << s; |
478 | } |
479 | } |
480 | |
481 | template <class String> |
482 | void testIdenticalTo() { |
483 | String s("Yukkuri shiteitte ne!!!" ); |
484 | |
485 | String result = to<String>(s); |
486 | EXPECT_EQ(result, s); |
487 | } |
488 | |
489 | template <class String> |
490 | void testVariadicTo() { |
491 | String s; |
492 | toAppend(&s); |
493 | toAppend("Lorem ipsum " , 1234, String(" dolor amet " ), 567.89, '!', &s); |
494 | EXPECT_EQ(s, "Lorem ipsum 1234 dolor amet 567.89!" ); |
495 | |
496 | s = to<String>(); |
497 | EXPECT_TRUE(s.empty()); |
498 | |
499 | s = to<String>("Lorem ipsum " , nullptr, 1234, " dolor amet " , 567.89, '.'); |
500 | EXPECT_EQ(s, "Lorem ipsum 1234 dolor amet 567.89." ); |
501 | } |
502 | |
503 | template <class String> |
504 | void testIdenticalToDelim() { |
505 | String s("Yukkuri shiteitte ne!!!" ); |
506 | |
507 | String charDelim = toDelim<String>('$', s); |
508 | EXPECT_EQ(charDelim, s); |
509 | |
510 | String strDelim = toDelim<String>(String(">_<" ), s); |
511 | EXPECT_EQ(strDelim, s); |
512 | } |
513 | |
514 | template <class String> |
515 | void testVariadicToDelim() { |
516 | String s; |
517 | toAppendDelim(":" , &s); |
518 | toAppendDelim( |
519 | ":" , "Lorem ipsum " , 1234, String(" dolor amet " ), 567.89, '!', &s); |
520 | EXPECT_EQ(s, "Lorem ipsum :1234: dolor amet :567.89:!" ); |
521 | |
522 | s = toDelim<String>(':'); |
523 | EXPECT_TRUE(s.empty()); |
524 | |
525 | s = toDelim<String>( |
526 | ":" , "Lorem ipsum " , nullptr, 1234, " dolor amet " , 567.89, '.'); |
527 | EXPECT_EQ(s, "Lorem ipsum ::1234: dolor amet :567.89:." ); |
528 | } |
529 | |
530 | TEST(Conv, NullString) { |
531 | string s1 = to<string>((char*)nullptr); |
532 | EXPECT_TRUE(s1.empty()); |
533 | fbstring s2 = to<fbstring>((char*)nullptr); |
534 | EXPECT_TRUE(s2.empty()); |
535 | } |
536 | |
537 | TEST(Conv, VariadicTo) { |
538 | testIdenticalTo<string>(); |
539 | testIdenticalTo<fbstring>(); |
540 | testVariadicTo<string>(); |
541 | testVariadicTo<fbstring>(); |
542 | } |
543 | |
544 | TEST(Conv, VariadicToDelim) { |
545 | testIdenticalToDelim<string>(); |
546 | testIdenticalToDelim<fbstring>(); |
547 | testVariadicToDelim<string>(); |
548 | testVariadicToDelim<fbstring>(); |
549 | } |
550 | |
551 | template <class String> |
552 | void testDoubleToString() { |
553 | EXPECT_EQ(to<string>(0.0), "0" ); |
554 | EXPECT_EQ(to<string>(0.5), "0.5" ); |
555 | EXPECT_EQ(to<string>(10.25), "10.25" ); |
556 | EXPECT_EQ(to<string>(1.123e10), "11230000000" ); |
557 | } |
558 | |
559 | TEST(Conv, DoubleToString) { |
560 | testDoubleToString<string>(); |
561 | testDoubleToString<fbstring>(); |
562 | } |
563 | |
564 | TEST(Conv, FBStringToString) { |
565 | fbstring foo("foo" ); |
566 | string ret = to<string>(foo); |
567 | EXPECT_EQ(ret, "foo" ); |
568 | string ret2 = to<string>(foo, 2); |
569 | EXPECT_EQ(ret2, "foo2" ); |
570 | } |
571 | |
572 | TEST(Conv, StringPieceToDouble) { |
573 | vector<tuple<const char*, const char*, double>> strs{ |
574 | make_tuple("2134123.125 zorro" , " zorro" , 2134123.125), |
575 | make_tuple(" 2134123.125 zorro" , " zorro" , 2134123.125), |
576 | make_tuple(" 2134123.125 zorro" , " zorro" , 2134123.125), |
577 | make_tuple(" 2134123.125 zorro " , " zorro " , 2134123.125), |
578 | make_tuple("2134123.125zorro" , "zorro" , 2134123.125), |
579 | make_tuple("0 zorro" , " zorro" , 0.0), |
580 | make_tuple(" 0 zorro" , " zorro" , 0.0), |
581 | make_tuple(" 0 zorro" , " zorro" , 0.0), |
582 | make_tuple(" 0 zorro " , " zorro " , 0.0), |
583 | make_tuple("0zorro" , "zorro" , 0.0), |
584 | make_tuple("0.0 zorro" , " zorro" , 0.0), |
585 | make_tuple(" 0.0 zorro" , " zorro" , 0.0), |
586 | make_tuple(" 0.0 zorro" , " zorro" , 0.0), |
587 | make_tuple(" 0.0 zorro " , " zorro " , 0.0), |
588 | make_tuple("0.0zorro" , "zorro" , 0.0), |
589 | make_tuple("0.0eb" , "eb" , 0.0), |
590 | make_tuple("0.0EB" , "EB" , 0.0), |
591 | make_tuple("0eb" , "eb" , 0.0), |
592 | make_tuple("0EB" , "EB" , 0.0), |
593 | make_tuple("12e" , "e" , 12.0), |
594 | make_tuple("12e-" , "e-" , 12.0), |
595 | make_tuple("12e+" , "e+" , 12.0), |
596 | make_tuple("12e-f-g" , "e-f-g" , 12.0), |
597 | make_tuple("12e+f+g" , "e+f+g" , 12.0), |
598 | make_tuple("12euro" , "euro" , 12.0), |
599 | }; |
600 | for (const auto& s : strs) { |
601 | StringPiece pc(get<0>(s)); |
602 | EXPECT_EQ(get<2>(s), to<double>(&pc)) << "\"" << get<0>(s) << "\"" ; |
603 | EXPECT_EQ(get<1>(s), pc); |
604 | EXPECT_THROW(to<double>(StringPiece(get<0>(s))), std::range_error); |
605 | EXPECT_EQ(get<2>(s), to<double>(StringPiece(get<0>(s), pc.data()))); |
606 | } |
607 | |
608 | // Test NaN conversion |
609 | try { |
610 | to<double>("not a number" ); |
611 | ADD_FAILURE(); |
612 | } catch (const std::range_error&) { |
613 | } |
614 | |
615 | EXPECT_TRUE(std::isnan(to<double>("nan" ))); |
616 | EXPECT_TRUE(std::isnan(to<double>("NaN" ))); |
617 | EXPECT_TRUE(std::isnan(to<double>("NAN" ))); |
618 | EXPECT_TRUE(std::isnan(to<double>("-nan" ))); |
619 | EXPECT_TRUE(std::isnan(to<double>("-NaN" ))); |
620 | EXPECT_TRUE(std::isnan(to<double>("-NAN" ))); |
621 | |
622 | EXPECT_EQ(to<double>("inf" ), numeric_limits<double>::infinity()); |
623 | EXPECT_EQ(to<double>("Inf" ), numeric_limits<double>::infinity()); |
624 | EXPECT_EQ(to<double>("INF" ), numeric_limits<double>::infinity()); |
625 | EXPECT_EQ(to<double>("inF" ), numeric_limits<double>::infinity()); |
626 | EXPECT_EQ(to<double>("infinity" ), numeric_limits<double>::infinity()); |
627 | EXPECT_EQ(to<double>("Infinity" ), numeric_limits<double>::infinity()); |
628 | EXPECT_EQ(to<double>("INFINITY" ), numeric_limits<double>::infinity()); |
629 | EXPECT_EQ(to<double>("iNfInItY" ), numeric_limits<double>::infinity()); |
630 | EXPECT_THROW(to<double>("infinitX" ), std::range_error); |
631 | EXPECT_EQ(to<double>("-inf" ), -numeric_limits<double>::infinity()); |
632 | EXPECT_EQ(to<double>("-Inf" ), -numeric_limits<double>::infinity()); |
633 | EXPECT_EQ(to<double>("-INF" ), -numeric_limits<double>::infinity()); |
634 | EXPECT_EQ(to<double>("-inF" ), -numeric_limits<double>::infinity()); |
635 | EXPECT_EQ(to<double>("-infinity" ), -numeric_limits<double>::infinity()); |
636 | EXPECT_EQ(to<double>("-Infinity" ), -numeric_limits<double>::infinity()); |
637 | EXPECT_EQ(to<double>("-INFINITY" ), -numeric_limits<double>::infinity()); |
638 | EXPECT_EQ(to<double>("-iNfInItY" ), -numeric_limits<double>::infinity()); |
639 | EXPECT_THROW(to<double>("-infinitX" ), std::range_error); |
640 | } |
641 | |
642 | TEST(Conv, EmptyStringToInt) { |
643 | string s = "" ; |
644 | StringPiece pc(s); |
645 | |
646 | try { |
647 | to<int>(pc); |
648 | ADD_FAILURE(); |
649 | } catch (const std::range_error&) { |
650 | } |
651 | } |
652 | |
653 | TEST(Conv, CorruptedStringToInt) { |
654 | string s = "-1" ; |
655 | StringPiece pc(s.data(), s.data() + 1); // Only "-" |
656 | |
657 | try { |
658 | to<int64_t>(&pc); |
659 | ADD_FAILURE(); |
660 | } catch (const std::range_error&) { |
661 | } |
662 | } |
663 | |
664 | TEST(Conv, EmptyStringToDouble) { |
665 | string s = "" ; |
666 | StringPiece pc(s); |
667 | |
668 | try { |
669 | to<double>(pc); |
670 | ADD_FAILURE(); |
671 | } catch (const std::range_error&) { |
672 | } |
673 | } |
674 | |
675 | TEST(Conv, IntToDouble) { |
676 | auto d = to<double>(42); |
677 | EXPECT_EQ(d, 42); |
678 | /* This seems not work in ubuntu11.10, gcc 4.6.1 |
679 | try { |
680 | auto f = to<float>(957837589847); |
681 | ADD_FAILURE(); |
682 | } catch (std::range_error& e) { |
683 | //LOG(INFO) << e.what(); |
684 | } |
685 | */ |
686 | } |
687 | |
688 | TEST(Conv, DoubleToInt) { |
689 | auto i = to<int>(42.0); |
690 | EXPECT_EQ(i, 42); |
691 | try { |
692 | auto i2 = to<int>(42.1); |
693 | LOG(ERROR) << "to<int> returned " << i2 << " instead of throwing" ; |
694 | ADD_FAILURE(); |
695 | } catch (std::range_error&) { |
696 | // LOG(INFO) << e.what(); |
697 | } |
698 | } |
699 | |
700 | TEST(Conv, EnumToInt) { |
701 | enum A { x = 42, y = 420, z = 65 }; |
702 | auto i = to<int>(x); |
703 | EXPECT_EQ(i, 42); |
704 | auto j = to<char>(x); |
705 | EXPECT_EQ(j, 42); |
706 | try { |
707 | auto i2 = to<char>(y); |
708 | LOG(ERROR) << "to<char> returned " << static_cast<unsigned int>(i2) |
709 | << " instead of throwing" ; |
710 | ADD_FAILURE(); |
711 | } catch (std::range_error&) { |
712 | // LOG(INFO) << e.what(); |
713 | } |
714 | } |
715 | |
716 | TEST(Conv, EnumToString) { |
717 | // task 813959 |
718 | enum A { x = 4, y = 420, z = 65 }; |
719 | EXPECT_EQ("foo.4" , to<string>("foo." , x)); |
720 | EXPECT_EQ("foo.420" , to<string>("foo." , y)); |
721 | EXPECT_EQ("foo.65" , to<string>("foo." , z)); |
722 | } |
723 | |
724 | TEST(Conv, IntToEnum) { |
725 | enum A { x = 42, y = 420 }; |
726 | auto i = to<A>(42); |
727 | EXPECT_EQ(i, x); |
728 | auto j = to<A>(100); |
729 | EXPECT_EQ(j, 100); |
730 | try { |
731 | auto i2 = to<A>(5000000000L); |
732 | LOG(ERROR) << "to<A> returned " << static_cast<unsigned int>(i2) |
733 | << " instead of throwing" ; |
734 | ADD_FAILURE(); |
735 | } catch (std::range_error&) { |
736 | // LOG(INFO) << e.what(); |
737 | } |
738 | } |
739 | |
740 | TEST(Conv, UnsignedEnum) { |
741 | enum E : uint32_t { x = 3000000000U }; |
742 | auto u = to<uint32_t>(x); |
743 | EXPECT_EQ(u, 3000000000U); |
744 | auto s = to<string>(x); |
745 | EXPECT_EQ("3000000000" , s); |
746 | auto e = to<E>(3000000000U); |
747 | EXPECT_EQ(e, x); |
748 | try { |
749 | auto i = to<int32_t>(x); |
750 | LOG(ERROR) << "to<int32_t> returned " << i << " instead of throwing" ; |
751 | ADD_FAILURE(); |
752 | } catch (std::range_error&) { |
753 | } |
754 | } |
755 | |
756 | TEST(Conv, UnsignedEnumClass) { |
757 | enum class E : uint32_t { x = 3000000000U }; |
758 | auto u = to<uint32_t>(E::x); |
759 | EXPECT_GT(u, 0); |
760 | EXPECT_EQ(u, 3000000000U); |
761 | EXPECT_EQ("3000000000" , to<string>(E::x)); |
762 | EXPECT_EQ(E::x, to<E>(3000000000U)); |
763 | EXPECT_EQ(E::x, to<E>("3000000000" )); |
764 | E e; |
765 | EXPECT_TRUE(parseTo("3000000000" , e).hasValue()); |
766 | EXPECT_EQ(E::x, e); |
767 | EXPECT_THROW(to<int32_t>(E::x), std::range_error); |
768 | } |
769 | |
770 | // Multi-argument to<string> uses toAppend, a different code path than |
771 | // to<string>(enum). |
772 | TEST(Conv, EnumClassToString) { |
773 | enum class A { x = 4, y = 420, z = 65 }; |
774 | EXPECT_EQ("foo.4" , to<string>("foo." , A::x)); |
775 | EXPECT_EQ("foo.420" , to<string>("foo." , A::y)); |
776 | EXPECT_EQ("foo.65" , to<string>("foo." , A::z)); |
777 | } |
778 | |
779 | TEST(Conv, IntegralToBool) { |
780 | EXPECT_FALSE(to<bool>(0)); |
781 | EXPECT_FALSE(to<bool>(0ul)); |
782 | |
783 | EXPECT_TRUE(to<bool>(1)); |
784 | EXPECT_TRUE(to<bool>(1ul)); |
785 | |
786 | EXPECT_TRUE(to<bool>(-42)); |
787 | EXPECT_TRUE(to<bool>(42ul)); |
788 | } |
789 | |
790 | template <typename Src> |
791 | void testStr2Bool() { |
792 | EXPECT_FALSE(to<bool>(Src("0" ))); |
793 | EXPECT_FALSE(to<bool>(Src(" 000 " ))); |
794 | |
795 | EXPECT_FALSE(to<bool>(Src("n" ))); |
796 | EXPECT_FALSE(to<bool>(Src("no" ))); |
797 | EXPECT_FALSE(to<bool>(Src("false" ))); |
798 | EXPECT_FALSE(to<bool>(Src("False" ))); |
799 | EXPECT_FALSE(to<bool>(Src(" fAlSe " ))); |
800 | EXPECT_FALSE(to<bool>(Src("F" ))); |
801 | EXPECT_FALSE(to<bool>(Src("off" ))); |
802 | |
803 | EXPECT_TRUE(to<bool>(Src("1" ))); |
804 | EXPECT_TRUE(to<bool>(Src(" 001 " ))); |
805 | EXPECT_TRUE(to<bool>(Src("y" ))); |
806 | EXPECT_TRUE(to<bool>(Src("yes" ))); |
807 | EXPECT_TRUE(to<bool>(Src("\nyEs\t" ))); |
808 | EXPECT_TRUE(to<bool>(Src("true" ))); |
809 | EXPECT_TRUE(to<bool>(Src("True" ))); |
810 | EXPECT_TRUE(to<bool>(Src("T" ))); |
811 | EXPECT_TRUE(to<bool>(Src("on" ))); |
812 | |
813 | EXPECT_THROW(to<bool>(Src("" )), std::range_error); |
814 | EXPECT_THROW(to<bool>(Src("2" )), std::range_error); |
815 | EXPECT_THROW(to<bool>(Src("11" )), std::range_error); |
816 | EXPECT_THROW(to<bool>(Src("19" )), std::range_error); |
817 | EXPECT_THROW(to<bool>(Src("o" )), std::range_error); |
818 | EXPECT_THROW(to<bool>(Src("fal" )), std::range_error); |
819 | EXPECT_THROW(to<bool>(Src("tru" )), std::range_error); |
820 | EXPECT_THROW(to<bool>(Src("ye" )), std::range_error); |
821 | EXPECT_THROW(to<bool>(Src("yes foo" )), std::range_error); |
822 | EXPECT_THROW(to<bool>(Src("bar no" )), std::range_error); |
823 | EXPECT_THROW(to<bool>(Src("one" )), std::range_error); |
824 | EXPECT_THROW(to<bool>(Src("true_" )), std::range_error); |
825 | EXPECT_THROW(to<bool>(Src("bogus_token_that_is_too_long" )), std::range_error); |
826 | } |
827 | |
828 | TEST(Conv, StringToBool) { |
829 | // testStr2Bool<const char *>(); |
830 | testStr2Bool<std::string>(); |
831 | |
832 | // Test with strings that are not NUL terminated. |
833 | const char buf[] = "01234" ; |
834 | EXPECT_FALSE(to<bool>(StringPiece(buf, buf + 1))); // "0" |
835 | EXPECT_TRUE(to<bool>(StringPiece(buf + 1, buf + 2))); // "1" |
836 | const char buf2[] = "one two three" ; |
837 | EXPECT_TRUE(to<bool>(StringPiece(buf2, buf2 + 2))); // "on" |
838 | const char buf3[] = "false" ; |
839 | EXPECT_THROW( |
840 | to<bool>(StringPiece(buf3, buf3 + 3)), // "fal" |
841 | std::range_error); |
842 | |
843 | // Test the StringPiece* API |
844 | const char buf4[] = "001foo" ; |
845 | StringPiece sp4(buf4); |
846 | EXPECT_TRUE(to<bool>(&sp4)); |
847 | EXPECT_EQ(buf4 + 3, sp4.begin()); |
848 | const char buf5[] = "0012" ; |
849 | StringPiece sp5(buf5); |
850 | EXPECT_THROW(to<bool>(&sp5), std::range_error); |
851 | EXPECT_EQ(buf5, sp5.begin()); |
852 | } |
853 | |
854 | TEST(Conv, Transform) { |
855 | const std::vector<int64_t> in{1, 2, 3}; |
856 | std::vector<std::string> out(in.size()); |
857 | std::transform(in.begin(), in.end(), out.begin(), to<std::string, int64_t>); |
858 | const std::vector<std::string> ref{"1" , "2" , "3" }; |
859 | EXPECT_EQ(ref, out); |
860 | } |
861 | |
862 | TEST(Conv, FloatToInt) { |
863 | EXPECT_EQ(to<int>(42.0f), 42); |
864 | EXPECT_EQ(to<int8_t>(-128.0f), int8_t(-128)); |
865 | EXPECT_THROW(to<int8_t>(-129.0), std::range_error); |
866 | EXPECT_THROW(to<int8_t>(127.001), std::range_error); |
867 | EXPECT_THROW(to<uint8_t>(-0.0001), std::range_error); |
868 | EXPECT_THROW( |
869 | to<uint64_t>(static_cast<float>(std::numeric_limits<uint64_t>::max())), |
870 | std::range_error); |
871 | } |
872 | |
873 | TEST(Conv, IntToFloat) { |
874 | EXPECT_EQ(to<float>(42ULL), 42.0); |
875 | EXPECT_EQ(to<float>(int8_t(-128)), -128.0); |
876 | EXPECT_THROW( |
877 | to<float>(std::numeric_limits<uint64_t>::max()), std::range_error); |
878 | EXPECT_THROW( |
879 | to<float>(std::numeric_limits<int64_t>::max()), std::range_error); |
880 | EXPECT_THROW( |
881 | to<float>(std::numeric_limits<int64_t>::min() + 1), std::range_error); |
882 | #if FOLLY_HAVE_INT128_T |
883 | EXPECT_THROW( |
884 | to<double>(std::numeric_limits<unsigned __int128>::max()), |
885 | std::range_error); |
886 | EXPECT_THROW( |
887 | to<double>(std::numeric_limits<__int128>::max()), std::range_error); |
888 | EXPECT_THROW( |
889 | to<double>(std::numeric_limits<__int128>::min() + 1), std::range_error); |
890 | #endif |
891 | } |
892 | |
893 | TEST(Conv, BoolToFloat) { |
894 | EXPECT_EQ(to<double>(true), 1.0); |
895 | EXPECT_EQ(to<double>(false), 0.0); |
896 | } |
897 | |
898 | TEST(Conv, FloatToBool) { |
899 | EXPECT_EQ(to<bool>(1.0), true); |
900 | EXPECT_EQ(to<bool>(0.0), false); |
901 | EXPECT_EQ(to<bool>(2.7), true); |
902 | EXPECT_EQ(to<bool>(std::numeric_limits<double>::max()), true); |
903 | EXPECT_EQ(to<bool>(std::numeric_limits<double>::min()), true); |
904 | EXPECT_EQ(to<bool>(std::numeric_limits<double>::lowest()), true); |
905 | EXPECT_EQ(to<bool>(std::numeric_limits<double>::quiet_NaN()), true); |
906 | EXPECT_EQ(to<bool>(std::numeric_limits<double>::infinity()), true); |
907 | EXPECT_EQ(to<bool>(-std::numeric_limits<double>::infinity()), true); |
908 | } |
909 | |
910 | namespace { |
911 | |
912 | template <typename F> |
913 | void testConvError( |
914 | F&& expr, |
915 | const char* exprStr, |
916 | ConversionCode code, |
917 | const char* value, |
918 | bool quotedValue, |
919 | int line) { |
920 | std::string where = to<std::string>(__FILE__, "(" , line, "): " ); |
921 | try { |
922 | auto res = expr(); |
923 | ADD_FAILURE() << where << exprStr << " -> " << res; |
924 | } catch (const ConversionError& e) { |
925 | EXPECT_EQ(code, e.errorCode()) << where << exprStr; |
926 | std::string str(e.what()); |
927 | EXPECT_FALSE(str.empty()) << where << exprStr << " -> " << str; |
928 | auto pos = str.find(':'); |
929 | if (value) { |
930 | std::ostringstream exp; |
931 | exp << str.substr(0, pos) + ": " ; |
932 | if (quotedValue) { |
933 | exp << "\"" << value << "\"" ; |
934 | } else { |
935 | exp << value; |
936 | } |
937 | EXPECT_EQ(exp.str(), str) << where << exprStr << " -> " << str; |
938 | } else { |
939 | EXPECT_EQ(pos, std::string::npos) << where << exprStr << " -> " << str; |
940 | } |
941 | } |
942 | } |
943 | } // namespace |
944 | |
945 | #define EXPECT_CONV_ERROR_QUOTE(expr, code, value, quoted) \ |
946 | testConvError( \ |
947 | [&] { return expr; }, \ |
948 | #expr, \ |
949 | ConversionCode::code, \ |
950 | value, \ |
951 | quoted, \ |
952 | __LINE__) |
953 | |
954 | #define EXPECT_CONV_ERROR(expr, code, value) \ |
955 | EXPECT_CONV_ERROR_QUOTE(expr, code, value, true) |
956 | |
957 | #define EXPECT_CONV_ERROR_STR(type, str, code) \ |
958 | EXPECT_CONV_ERROR(to<type>(str), code, str) |
959 | |
960 | #define EXPECT_CONV_ERROR_STR_NOVAL(type, str, code) \ |
961 | EXPECT_CONV_ERROR(to<type>(str), code, nullptr) |
962 | |
963 | TEST(Conv, ConversionErrorStrToBool) { |
964 | EXPECT_CONV_ERROR_STR_NOVAL(bool, StringPiece(), EMPTY_INPUT_STRING); |
965 | EXPECT_CONV_ERROR_STR_NOVAL(bool, "" , EMPTY_INPUT_STRING); |
966 | EXPECT_CONV_ERROR_STR(bool, " " , EMPTY_INPUT_STRING); |
967 | EXPECT_CONV_ERROR_STR(bool, " 11 " , BOOL_OVERFLOW); |
968 | EXPECT_CONV_ERROR_STR(bool, "other " , BOOL_INVALID_VALUE); |
969 | EXPECT_CONV_ERROR_STR(bool, " bla" , BOOL_INVALID_VALUE); |
970 | EXPECT_CONV_ERROR(to<bool>(" offbla" ), NON_WHITESPACE_AFTER_END, "bla" ); |
971 | } |
972 | |
973 | TEST(Conv, ConversionErrorStrToFloat) { |
974 | EXPECT_CONV_ERROR_STR_NOVAL(float, StringPiece(), EMPTY_INPUT_STRING); |
975 | EXPECT_CONV_ERROR_STR_NOVAL(float, "" , EMPTY_INPUT_STRING); |
976 | EXPECT_CONV_ERROR_STR(float, " " , EMPTY_INPUT_STRING); |
977 | EXPECT_CONV_ERROR_STR(float, " junk" , STRING_TO_FLOAT_ERROR); |
978 | EXPECT_CONV_ERROR(to<float>(" 1bla" ), NON_WHITESPACE_AFTER_END, "bla" ); |
979 | } |
980 | |
981 | TEST(Conv, ConversionErrorStrToInt) { |
982 | // empty string handling |
983 | EXPECT_CONV_ERROR_STR_NOVAL(int, StringPiece(), EMPTY_INPUT_STRING); |
984 | EXPECT_CONV_ERROR_STR_NOVAL(int, "" , EMPTY_INPUT_STRING); |
985 | EXPECT_CONV_ERROR_STR(int, " " , EMPTY_INPUT_STRING); |
986 | |
987 | // signed integers |
988 | EXPECT_CONV_ERROR_STR(int, " *" , INVALID_LEADING_CHAR); |
989 | EXPECT_CONV_ERROR_STR(int, " +" , NO_DIGITS); |
990 | EXPECT_CONV_ERROR_STR(int, " +*" , NON_DIGIT_CHAR); |
991 | EXPECT_CONV_ERROR_STR(int8_t, " 128" , POSITIVE_OVERFLOW); |
992 | EXPECT_CONV_ERROR_STR(int8_t, " -129" , NEGATIVE_OVERFLOW); |
993 | EXPECT_CONV_ERROR_STR(int8_t, " 1000" , POSITIVE_OVERFLOW); |
994 | EXPECT_CONV_ERROR_STR(int8_t, "-1000" , NEGATIVE_OVERFLOW); |
995 | EXPECT_CONV_ERROR(to<int>(" -13bla" ), NON_WHITESPACE_AFTER_END, "bla" ); |
996 | |
997 | // unsigned integers |
998 | EXPECT_CONV_ERROR_STR(unsigned, " -" , NON_DIGIT_CHAR); |
999 | EXPECT_CONV_ERROR_STR(uint8_t, " 256" , POSITIVE_OVERFLOW); |
1000 | EXPECT_CONV_ERROR(to<unsigned>("42bla" ), NON_WHITESPACE_AFTER_END, "bla" ); |
1001 | } |
1002 | |
1003 | #define EXPECT_CONV_ERROR_PP_VAL(type, str, code, val) \ |
1004 | do { \ |
1005 | StringPiece input(str); \ |
1006 | EXPECT_CONV_ERROR(to<type>(input.begin(), input.end()), code, val); \ |
1007 | } while (0) |
1008 | |
1009 | #define EXPECT_CONV_ERROR_PP(type, str, code) \ |
1010 | EXPECT_CONV_ERROR_PP_VAL(type, str, code, str) |
1011 | |
1012 | TEST(Conv, ConversionErrorPtrPairToInt) { |
1013 | // signed integers |
1014 | EXPECT_CONV_ERROR_PP(int, "" , INVALID_LEADING_CHAR); |
1015 | EXPECT_CONV_ERROR_PP(int, " " , INVALID_LEADING_CHAR); |
1016 | EXPECT_CONV_ERROR_PP(int, "*" , INVALID_LEADING_CHAR); |
1017 | EXPECT_CONV_ERROR_PP(int, "+" , NO_DIGITS); |
1018 | EXPECT_CONV_ERROR_PP(int8_t, "128" , POSITIVE_OVERFLOW); |
1019 | EXPECT_CONV_ERROR_PP(int8_t, "-129" , NEGATIVE_OVERFLOW); |
1020 | EXPECT_CONV_ERROR_PP(int8_t, "1000" , POSITIVE_OVERFLOW); |
1021 | EXPECT_CONV_ERROR_PP(int8_t, "-1000" , NEGATIVE_OVERFLOW); |
1022 | EXPECT_CONV_ERROR_PP(int, "-junk" , NON_DIGIT_CHAR); |
1023 | |
1024 | // unsigned integers |
1025 | EXPECT_CONV_ERROR_PP(unsigned, "" , NO_DIGITS); |
1026 | EXPECT_CONV_ERROR_PP(uint8_t, "256" , POSITIVE_OVERFLOW); |
1027 | EXPECT_CONV_ERROR_PP(unsigned, "junk" , NON_DIGIT_CHAR); |
1028 | } |
1029 | |
1030 | namespace { |
1031 | |
1032 | template <typename T, typename V> |
1033 | std::string prefixWithType(V value) { |
1034 | std::ostringstream oss; |
1035 | #ifdef FOLLY_HAS_RTTI |
1036 | oss << "(" << demangle(typeid(T)) << ") " ; |
1037 | #endif |
1038 | oss << to<std::string>(value); |
1039 | return oss.str(); |
1040 | } |
1041 | } // namespace |
1042 | |
1043 | #define EXPECT_CONV_ERROR_ARITH(type, val, code) \ |
1044 | EXPECT_CONV_ERROR_QUOTE( \ |
1045 | to<type>(val), code, prefixWithType<type>(val).c_str(), false) |
1046 | |
1047 | TEST(Conv, ConversionErrorIntToInt) { |
1048 | EXPECT_CONV_ERROR_ARITH(signed char, 128, ARITH_POSITIVE_OVERFLOW); |
1049 | EXPECT_CONV_ERROR_ARITH(unsigned char, -1, ARITH_NEGATIVE_OVERFLOW); |
1050 | } |
1051 | |
1052 | TEST(Conv, ConversionErrorFloatToFloat) { |
1053 | EXPECT_CONV_ERROR_ARITH( |
1054 | float, std::numeric_limits<double>::max(), ARITH_POSITIVE_OVERFLOW); |
1055 | EXPECT_CONV_ERROR_ARITH( |
1056 | float, std::numeric_limits<double>::lowest(), ARITH_NEGATIVE_OVERFLOW); |
1057 | } |
1058 | |
1059 | TEST(Conv, ConversionErrorIntToFloat) { |
1060 | EXPECT_CONV_ERROR_ARITH( |
1061 | float, std::numeric_limits<long long>::max(), ARITH_LOSS_OF_PRECISION); |
1062 | } |
1063 | |
1064 | TEST(Conv, ConversionErrorFloatToInt) { |
1065 | EXPECT_CONV_ERROR_ARITH(int8_t, 65.5, ARITH_LOSS_OF_PRECISION); |
1066 | } |
1067 | |
1068 | TEST(Conv, TryStringToBool) { |
1069 | auto rv1 = folly::tryTo<bool>("xxxx" ); |
1070 | EXPECT_FALSE(rv1.hasValue()); |
1071 | auto rv2 = folly::tryTo<bool>("false" ); |
1072 | EXPECT_TRUE(rv2.hasValue()); |
1073 | EXPECT_FALSE(rv2.value()); |
1074 | auto rv3 = folly::tryTo<bool>("yes" ); |
1075 | EXPECT_TRUE(rv3.hasValue()); |
1076 | EXPECT_TRUE(rv3.value()); |
1077 | } |
1078 | |
1079 | TEST(Conv, TryStringToInt) { |
1080 | auto rv1 = folly::tryTo<int>("1000000000000000000000000000000" ); |
1081 | EXPECT_FALSE(rv1.hasValue()); |
1082 | auto rv2 = folly::tryTo<int>("4711" ); |
1083 | EXPECT_TRUE(rv2.hasValue()); |
1084 | EXPECT_EQ(rv2.value(), 4711); |
1085 | } |
1086 | |
1087 | TEST(Conv, TryStringToEnum) { |
1088 | enum class A { x = 42, y = 420, z = 65 }; |
1089 | auto rv1 = folly::tryTo<A>("1000000000000000000000000000000" ); |
1090 | EXPECT_FALSE(rv1.hasValue()); |
1091 | auto rv2 = folly::tryTo<A>("42" ); |
1092 | EXPECT_TRUE(rv2.hasValue()); |
1093 | EXPECT_EQ(A::x, rv2.value()); |
1094 | auto rv3 = folly::tryTo<A>("50" ); |
1095 | EXPECT_TRUE(rv3.hasValue()); |
1096 | EXPECT_EQ(static_cast<A>(50), rv3.value()); |
1097 | } |
1098 | |
1099 | TEST(Conv, TryStringToFloat) { |
1100 | auto rv1 = folly::tryTo<float>("" ); |
1101 | EXPECT_FALSE(rv1.hasValue()); |
1102 | auto rv2 = folly::tryTo<float>("3.14" ); |
1103 | EXPECT_TRUE(rv2.hasValue()); |
1104 | EXPECT_NEAR(rv2.value(), 3.14, 1e-5); |
1105 | } |
1106 | |
1107 | TEST(Conv, TryStringToDouble) { |
1108 | auto rv1 = folly::tryTo<double>("" ); |
1109 | EXPECT_FALSE(rv1.hasValue()); |
1110 | auto rv2 = folly::tryTo<double>("3.14" ); |
1111 | EXPECT_TRUE(rv2.hasValue()); |
1112 | EXPECT_NEAR(rv2.value(), 3.14, 1e-10); |
1113 | } |
1114 | |
1115 | TEST(Conv, TryIntToInt) { |
1116 | auto rv1 = folly::tryTo<uint8_t>(256); |
1117 | EXPECT_FALSE(rv1.hasValue()); |
1118 | auto rv2 = folly::tryTo<uint8_t>(255); |
1119 | EXPECT_TRUE(rv2.hasValue()); |
1120 | EXPECT_EQ(rv2.value(), 255); |
1121 | } |
1122 | |
1123 | TEST(Conv, TryFloatToFloat) { |
1124 | auto rv1 = folly::tryTo<float>(1e100); |
1125 | EXPECT_FALSE(rv1.hasValue()); |
1126 | auto rv2 = folly::tryTo<double>(25.5f); |
1127 | EXPECT_TRUE(rv2.hasValue()); |
1128 | EXPECT_NEAR(rv2.value(), 25.5, 1e-10); |
1129 | } |
1130 | |
1131 | TEST(Conv, TryFloatToInt) { |
1132 | auto rv1 = folly::tryTo<int>(100.001); |
1133 | EXPECT_FALSE(rv1.hasValue()); |
1134 | auto rv2 = folly::tryTo<int>(100.0); |
1135 | EXPECT_TRUE(rv2.hasValue()); |
1136 | EXPECT_EQ(rv2.value(), 100); |
1137 | } |
1138 | |
1139 | TEST(Conv, TryIntToFloat) { |
1140 | auto rv1 = folly::tryTo<float>(std::numeric_limits<uint64_t>::max()); |
1141 | EXPECT_FALSE(rv1.hasValue()); |
1142 | auto rv2 = folly::tryTo<float>(1000ULL); |
1143 | EXPECT_TRUE(rv2.hasValue()); |
1144 | EXPECT_EQ(rv2.value(), 1000.0f); |
1145 | } |
1146 | |
1147 | TEST(Conv, TryPtrPairToInt) { |
1148 | StringPiece sp1("1000000000000000000000000000000" ); |
1149 | auto rv1 = folly::tryTo<int>(sp1.begin(), sp1.end()); |
1150 | EXPECT_FALSE(rv1.hasValue()); |
1151 | StringPiece sp2("4711" ); |
1152 | auto rv2 = folly::tryTo<int>(sp2.begin(), sp2.end()); |
1153 | EXPECT_TRUE(rv2.hasValue()); |
1154 | EXPECT_EQ(rv2.value(), 4711); |
1155 | StringPiece sp3("-4711" ); |
1156 | auto rv3 = folly::tryTo<int>(sp3.begin(), sp3.end()); |
1157 | EXPECT_TRUE(rv3.hasValue()); |
1158 | EXPECT_EQ(rv3.value(), -4711); |
1159 | StringPiece sp4("4711" ); |
1160 | auto rv4 = folly::tryTo<uint16_t>(sp4.begin(), sp4.end()); |
1161 | EXPECT_TRUE(rv4.hasValue()); |
1162 | EXPECT_EQ(rv4.value(), 4711); |
1163 | } |
1164 | |
1165 | TEST(Conv, NewUint64ToString) { |
1166 | char buf[21]; |
1167 | |
1168 | #define THE_GREAT_EXPECTATIONS(n, len) \ |
1169 | do { \ |
1170 | EXPECT_EQ((len), uint64ToBufferUnsafe((n), buf)); \ |
1171 | buf[(len)] = 0; \ |
1172 | auto s = string(#n); \ |
1173 | s = s.substr(0, s.size() - 2); \ |
1174 | EXPECT_EQ(s, buf); \ |
1175 | } while (0) |
1176 | |
1177 | THE_GREAT_EXPECTATIONS(0UL, 1); |
1178 | THE_GREAT_EXPECTATIONS(1UL, 1); |
1179 | THE_GREAT_EXPECTATIONS(12UL, 2); |
1180 | THE_GREAT_EXPECTATIONS(123UL, 3); |
1181 | THE_GREAT_EXPECTATIONS(1234UL, 4); |
1182 | THE_GREAT_EXPECTATIONS(12345UL, 5); |
1183 | THE_GREAT_EXPECTATIONS(123456UL, 6); |
1184 | THE_GREAT_EXPECTATIONS(1234567UL, 7); |
1185 | THE_GREAT_EXPECTATIONS(12345678UL, 8); |
1186 | THE_GREAT_EXPECTATIONS(123456789UL, 9); |
1187 | THE_GREAT_EXPECTATIONS(1234567890UL, 10); |
1188 | THE_GREAT_EXPECTATIONS(12345678901UL, 11); |
1189 | THE_GREAT_EXPECTATIONS(123456789012UL, 12); |
1190 | THE_GREAT_EXPECTATIONS(1234567890123UL, 13); |
1191 | THE_GREAT_EXPECTATIONS(12345678901234UL, 14); |
1192 | THE_GREAT_EXPECTATIONS(123456789012345UL, 15); |
1193 | THE_GREAT_EXPECTATIONS(1234567890123456UL, 16); |
1194 | THE_GREAT_EXPECTATIONS(12345678901234567UL, 17); |
1195 | THE_GREAT_EXPECTATIONS(123456789012345678UL, 18); |
1196 | THE_GREAT_EXPECTATIONS(1234567890123456789UL, 19); |
1197 | THE_GREAT_EXPECTATIONS(18446744073709551614UL, 20); |
1198 | THE_GREAT_EXPECTATIONS(18446744073709551615UL, 20); |
1199 | |
1200 | #undef THE_GREAT_EXPECTATIONS |
1201 | } |
1202 | |
1203 | TEST(Conv, allocate_size) { |
1204 | std::string str1 = "meh meh meh" ; |
1205 | std::string str2 = "zdech zdech zdech" ; |
1206 | |
1207 | auto res1 = folly::to<std::string>(str1, "." , str2); |
1208 | EXPECT_EQ(res1, str1 + "." + str2); |
1209 | |
1210 | std::string res2; // empty |
1211 | toAppendFit(str1, str2, 1, &res2); |
1212 | EXPECT_EQ(res2, str1 + str2 + "1" ); |
1213 | |
1214 | std::string res3; |
1215 | toAppendDelimFit("," , str1, str2, &res3); |
1216 | EXPECT_EQ(res3, str1 + "," + str2); |
1217 | } |
1218 | |
1219 | namespace my { |
1220 | struct Dimensions { |
1221 | int w, h; |
1222 | std::tuple<const int&, const int&> tuple_view() const { |
1223 | return tie(w, h); |
1224 | } |
1225 | bool operator==(const Dimensions& other) const { |
1226 | return this->tuple_view() == other.tuple_view(); |
1227 | } |
1228 | }; |
1229 | |
1230 | Expected<StringPiece, ConversionCode> parseTo( |
1231 | folly::StringPiece in, |
1232 | Dimensions& out) { |
1233 | return parseTo(in, out.w) |
1234 | .then([](StringPiece sp) { return sp.removePrefix("x" ), sp; }) |
1235 | .then([&](StringPiece sp) { return parseTo(sp, out.h); }); |
1236 | } |
1237 | |
1238 | template <class String> |
1239 | void toAppend(const Dimensions& in, String* result) { |
1240 | folly::toAppend(in.w, 'x', in.h, result); |
1241 | } |
1242 | |
1243 | size_t estimateSpaceNeeded(const Dimensions& in) { |
1244 | return 2000 + folly::estimateSpaceNeeded(in.w) + |
1245 | folly::estimateSpaceNeeded(in.h); |
1246 | } |
1247 | |
1248 | enum class SmallEnum {}; |
1249 | |
1250 | Expected<StringPiece, ConversionCode> parseTo(StringPiece in, SmallEnum& out) { |
1251 | out = {}; |
1252 | if (in == "SmallEnum" ) { |
1253 | return in.removePrefix(in), in; |
1254 | } else { |
1255 | return makeUnexpected(ConversionCode::STRING_TO_FLOAT_ERROR); |
1256 | } |
1257 | } |
1258 | |
1259 | template <class String> |
1260 | void toAppend(SmallEnum, String* result) { |
1261 | folly::toAppend("SmallEnum" , result); |
1262 | } |
1263 | } // namespace my |
1264 | |
1265 | TEST(Conv, custom_kkproviders) { |
1266 | my::Dimensions expected{7, 8}; |
1267 | EXPECT_EQ(expected, folly::to<my::Dimensions>("7x8" )); |
1268 | auto str = folly::to<std::string>(expected); |
1269 | EXPECT_EQ("7x8" , str); |
1270 | // make sure above implementation of estimateSpaceNeeded() is used. |
1271 | EXPECT_GT(str.capacity(), 2000); |
1272 | EXPECT_LT(str.capacity(), 2500); |
1273 | // toAppend with other arguments |
1274 | toAppend("|" , expected, &str); |
1275 | EXPECT_EQ("7x8|7x8" , str); |
1276 | } |
1277 | |
1278 | TEST(conv, custom_enumclass) { |
1279 | EXPECT_EQ(my::SmallEnum{}, folly::to<my::SmallEnum>("SmallEnum" )); |
1280 | EXPECT_EQ(my::SmallEnum{}, folly::tryTo<my::SmallEnum>("SmallEnum" ).value()); |
1281 | auto str = to<string>(my::SmallEnum{}); |
1282 | toAppend("|" , my::SmallEnum{}, &str); |
1283 | EXPECT_EQ("SmallEnum|SmallEnum" , str); |
1284 | } |
1285 | |
1286 | TEST(Conv, TryToThenWithVoid) { |
1287 | auto x = tryTo<int>("42" ).then([](int) {}); |
1288 | EXPECT_TRUE(x.hasValue()); |
1289 | Unit u = x.value(); |
1290 | (void)u; |
1291 | } |
1292 | |
1293 | TEST(conv, TryIntToUnscopedEnumAndBack) { |
1294 | enum UnscopedEnum { |
1295 | First = 0, |
1296 | Second = 1, |
1297 | }; |
1298 | EXPECT_EQ(UnscopedEnum::Second, folly::tryTo<UnscopedEnum>(1).value()); |
1299 | EXPECT_EQ(1, folly::tryTo<int>(UnscopedEnum::Second).value()); |
1300 | } |
1301 | |
1302 | TEST(conv, TryIntToScopedEnumAndBack) { |
1303 | enum class ScopedEnum { |
1304 | First = 0, |
1305 | Second = 1, |
1306 | }; |
1307 | EXPECT_EQ(ScopedEnum::Second, folly::tryTo<ScopedEnum>(1).value()); |
1308 | EXPECT_EQ(1, folly::tryTo<int>(ScopedEnum::Second).value()); |
1309 | } |
1310 | |