1//
2// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4//
5// Distributed under the Boost Software License, Version 1.0. (See accompanying
6// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7//
8// Official repository: https://github.com/boostorg/json
9//
10
11#include <boost/json/stream_parser.hpp>
12#include <boost/json/parse.hpp>
13#include <boost/json/serialize.hpp>
14
15#include <iostream>
16#include <random>
17#include <cinttypes>
18
19#include "parse-vectors.hpp"
20#include "test.hpp"
21#include "test_suite.hpp"
22
23namespace boost {
24namespace json {
25
26template<std::size_t N, class... Args>
27void
28sprintf(char (&buf)[N],
29 char const* format, Args&&... args)
30{
31#ifdef _MSC_VER
32 sprintf_s(buf, format,
33 std::forward<Args>(args)...);
34#else
35 std::snprintf(s: buf, maxlen: N, format: format,
36 std::forward<Args>(args)...);
37#endif
38}
39
40class double_test
41{
42public:
43 struct f_boost
44 {
45 static
46 string_view
47 name() noexcept
48 {
49 return "boost";
50 }
51
52 double
53 operator()(string_view s, parse_options const& po = {}) const
54 {
55 BOOST_TEST_CHECKPOINT();
56 system::error_code ec;
57 stream_parser p({}, po);
58 p.write(data: s.data(), size: s.size(), ec);
59 if(BOOST_TEST(! ec))
60 p.finish(ec);
61 if(! BOOST_TEST(! ec))
62 return 0;
63 auto const jv = p.release();
64 double const d = jv.as_double();
65 grind_double(s, v: d, po);
66 return d;
67 }
68 };
69
70 bool
71 within_1ulp(double x, double y)
72 {
73 std::uint64_t bx, by;
74 std::memcpy(dest: &bx, src: &x, n: sizeof(x));
75 std::memcpy(dest: &by, src: &y, n: sizeof(y));
76
77 auto diff = bx - by;
78 switch (diff)
79 {
80 case 0:
81 case 1:
82 case 0xffffffffffffffff:
83 return true;
84 default:
85 break;
86 }
87 return false;
88 }
89
90 static
91 value
92 from_string_test(
93 string_view s,
94 storage_ptr sp = {},
95 const parse_options& po = parse_options())
96 {
97 stream_parser p(storage_ptr(), po);
98 system::error_code ec;
99 p.reset(sp: std::move(sp));
100 p.write(data: s.data(), size: s.size(), ec);
101 if(BOOST_TEST(! ec))
102 p.finish(ec);
103 BOOST_TEST(! ec);
104 return p.release();
105 }
106
107 void
108 static
109 check_round_trip(value const& jv1,
110 const parse_options& po = parse_options())
111 {
112 auto const s2 =
113 //to_string_test(jv1); // use this if serializer is broken
114 serialize(t: jv1);
115 auto jv2 =
116 from_string_test(s: s2, sp: {}, po);
117 BOOST_TEST(equal(jv1, jv2));
118 }
119
120 template<class F>
121 void
122 static
123 grind_one(
124 string_view s,
125 storage_ptr sp,
126 F const& f,
127 const parse_options& po = parse_options())
128 {
129 auto const jv =
130 from_string_test(s, sp, po);
131 f(jv, po);
132 }
133
134 static
135 void
136 grind_one(string_view s)
137 {
138 auto const jv =
139 from_string_test(s);
140 check_round_trip(jv1: jv);
141 }
142
143 template<class F>
144 static
145 void
146 grind(string_view s, F const& f,
147 const parse_options& po = parse_options())
148 {
149 try
150 {
151 grind_one(s, {}, f, po);
152
153 fail_loop([&](storage_ptr const& sp)
154 {
155 grind_one(s, sp, f, po);
156 });
157
158 if(s.size() > 1)
159 {
160 // Destroy the stream_parser at every
161 // split point to check leaks.
162 for(std::size_t i = 1;
163 i < s.size(); ++i)
164 {
165 fail_resource mr;
166 mr.fail_max = 0;
167 stream_parser p(storage_ptr(), po);
168 system::error_code ec;
169 p.reset(sp: &mr);
170 p.write(data: s.data(), size: i, ec);
171 if(BOOST_TEST(! ec))
172 p.write(
173 data: s.data() + i,
174 size: s.size() - i, ec);
175 if(BOOST_TEST(! ec))
176 p.finish(ec);
177 if(BOOST_TEST(! ec))
178 f(p.release(), po);
179 }
180 }
181 }
182 catch(std::exception const&)
183 {
184 BOOST_TEST_FAIL();
185 }
186 }
187
188 static
189 void
190 grind(string_view s,
191 const parse_options& po = parse_options())
192 {
193 grind(s,
194 f: [](value const& jv, const parse_options& po)
195 {
196 check_round_trip(jv1: jv, po);
197 }, po);
198 }
199
200 static
201 void
202 grind_double(string_view s, double v, parse_options const& po = {})
203 {
204 grind(s,
205 f: [v](value const& jv, const parse_options&)
206 {
207 if(! BOOST_TEST(jv.is_double()))
208 return;
209 if( std::isnan(x: v) )
210 BOOST_TEST( std::isnan( jv.get_double() ) );
211 else
212 BOOST_TEST( jv.get_double() == v );
213 },
214 po);
215 }
216
217 // Verify that f converts to the
218 // same double produced by `strtod`.
219 // Requires `s` is not represented by an integral type.
220 template<class F>
221 void
222 fc(std::string const& s, F const& f)
223 {
224 char* str_end;
225 double const need =
226 std::strtod(nptr: s.c_str(), endptr: &str_end);
227 // BOOST_TEST(str_end == &s.back() + 1);
228 for (bool is_precise: {false, true})
229 {
230 parse_options po;
231 po.numbers = is_precise ?
232 number_precision::precise : number_precision::imprecise;
233 double const got = f(s, po);
234 auto same = got == need;
235 auto close = same ?
236 true : within_1ulp(x: got, y: need);
237
238 if( !BOOST_TEST(close) )
239 {
240 std::cerr << "Failure on '" << s << "' ("
241 << (is_precise? "precise" : "imprecise") << "): "
242 << got << " != " << need << "\n";
243 }
244 }
245
246 // test that number_precision::none works
247 parse_options po;
248 po.numbers = number_precision::none;
249 double const got = f(s, po);
250 (void)got;
251 }
252
253 void
254 fc(std::string const& s)
255 {
256 fc(s, f: f_boost{});
257 fc(s: s + std::string( 64, ' ' ), f: f_boost{});
258 }
259
260 void
261 testDouble()
262 {
263 grind_double(s: "-1.010", v: -1.01);
264 grind_double(s: "-0.010", v: -0.01);
265 grind_double(s: "-0.0", v: -0.0);
266 grind_double(s: "-0e0", v: -0.0);
267 grind_double( s: "18.4", v: 18.4);
268 grind_double(s: "-18.4", v: -18.4);
269 grind_double( s: "18446744073709551616", v: 1.8446744073709552e+19);
270 grind_double(s: "-18446744073709551616", v: -1.8446744073709552e+19);
271 grind_double( s: "18446744073709551616.0", v: 1.8446744073709552e+19);
272 grind_double( s: "18446744073709551616.00009", v: 1.8446744073709552e+19);
273 grind_double( s: "1844674407370955161600000", v: 1.8446744073709552e+24);
274 grind_double(s: "-1844674407370955161600000", v: -1.8446744073709552e+24);
275 grind_double( s: "1844674407370955161600000.0", v: 1.8446744073709552e+24);
276 grind_double( s: "1844674407370955161600000.00009", v: 1.8446744073709552e+24);
277 grind_double( s: "19700720435664.186294290058937593e13", v: 1.9700720435664185e+26);
278
279 grind_double( s: "1.0", v: 1.0);
280 grind_double( s: "1.1", v: 1.1);
281 grind_double( s: "1.11", v: 1.11);
282 grind_double( s: "1.11111", v: 1.11111);
283 grind_double( s: "11.1111", v: 11.1111);
284 grind_double( s: "111.111", v: 111.111);
285
286 fc(s: "-0.9999999999999999999999");
287 fc(s: "-0.9999999999999999");
288 fc(s: "-0.9007199254740991");
289 fc(s: "-0.999999999999999");
290 fc(s: "-0.99999999999999");
291 fc(s: "-0.9999999999999");
292 fc(s: "-0.999999999999");
293 fc(s: "-0.99999999999");
294 fc(s: "-0.9999999999");
295 fc(s: "-0.999999999");
296 fc(s: "-0.99999999");
297 fc(s: "-0.9999999");
298 fc(s: "-0.999999");
299 fc(s: "-0.99999");
300 fc(s: "-0.9999");
301 fc(s: "-0.8125");
302 fc(s: "-0.999");
303 fc(s: "-0.99");
304 fc(s: "-1.0");
305 fc(s: "-0.9");
306 fc(s: "-0.0");
307 fc(s: "0.0");
308 fc(s: "0.9");
309 fc(s: "0.99");
310 fc(s: "0.999");
311 fc(s: "0.8125");
312 fc(s: "0.9999");
313 fc(s: "0.99999");
314 fc(s: "0.999999");
315 fc(s: "0.9999999");
316 fc(s: "0.99999999");
317 fc(s: "0.999999999");
318 fc(s: "0.9999999999");
319 fc(s: "0.99999999999");
320 fc(s: "0.999999999999");
321 fc(s: "0.9999999999999");
322 fc(s: "0.99999999999999");
323 fc(s: "0.999999999999999");
324 fc(s: "0.9007199254740991");
325 fc(s: "0.9999999999999999");
326 fc(s: "0.9999999999999999999999");
327 fc(s: "0.999999999999999999999999999");
328
329 fc(s: "-1e308");
330 fc(s: "-1e-308");
331 fc(s: "-9999e300");
332 fc(s: "-999e100");
333 fc(s: "-99e10");
334 fc(s: "-9e1");
335 fc(s: "9e1");
336 fc(s: "99e10");
337 fc(s: "999e100");
338 fc(s: "9999e300");
339 fc(s: "999999999999999999.0");
340 fc(s: "999999999999999999999.0");
341 fc(s: "999999999999999999999e5");
342 fc(s: "999999999999999999999.0e5");
343
344 fc(s: "0.00000000000000001");
345
346 fc(s: "-1e-1");
347 fc(s: "-1e0");
348 fc(s: "-1e1");
349 fc(s: "0e0");
350 fc(s: "1e0");
351 fc(s: "1e10");
352
353 fc(s: "0."
354 "00000000000000000000000000000000000000000000000000" // 50 zeroes
355 "1e50");
356 fc(s: "-0."
357 "00000000000000000000000000000000000000000000000000" // 50 zeroes
358 "1e50");
359
360 fc(s: "0."
361 "00000000000000000000000000000000000000000000000000"
362 "00000000000000000000000000000000000000000000000000"
363 "00000000000000000000000000000000000000000000000000"
364 "00000000000000000000000000000000000000000000000000"
365 "00000000000000000000000000000000000000000000000000"
366 "00000000000000000000000000000000000000000000000000"
367 "00000000000000000000000000000000000000000000000000"
368 "00000000000000000000000000000000000000000000000000"
369 "00000000000000000000000000000000000000000000000000"
370 "00000000000000000000000000000000000000000000000000" // 500 zeroes
371 "1e600");
372 fc(s: "-0."
373 "00000000000000000000000000000000000000000000000000"
374 "00000000000000000000000000000000000000000000000000"
375 "00000000000000000000000000000000000000000000000000"
376 "00000000000000000000000000000000000000000000000000"
377 "00000000000000000000000000000000000000000000000000"
378 "00000000000000000000000000000000000000000000000000"
379 "00000000000000000000000000000000000000000000000000"
380 "00000000000000000000000000000000000000000000000000"
381 "00000000000000000000000000000000000000000000000000"
382 "00000000000000000000000000000000000000000000000000" // 500 zeroes
383 "1e600");
384
385 fc(s: "0e"
386 "00000000000000000000000000000000000000000000000000"
387 "00000000000000000000000000000000000000000000000000"
388 "00000000000000000000000000000000000000000000000000"
389 "00000000000000000000000000000000000000000000000000"
390 "00000000000000000000000000000000000000000000000000"
391 "00000000000000000000000000000000000000000000000000"
392 "00000000000000000000000000000000000000000000000000"
393 "00000000000000000000000000000000000000000000000000"
394 "00000000000000000000000000000000000000000000000000"
395 "00000000000000000000000000000000000000000000000000" // 500 zeroes
396 );
397 }
398
399 void checkAccuracy(
400 const char* nm, int max_ulp, parse_options const& opts = {})
401 {
402 double x = std::strtod( nptr: nm, endptr: 0 );
403 double y = boost::json::parse( s: nm, sp: {}, opt: opts ).as_double();
404 std::uint64_t bx, by;
405 std::memcpy( dest: &bx, src: &x, n: sizeof(x) );
406 std::memcpy( dest: &by, src: &y, n: sizeof(y) );
407 std::int64_t diff = bx - by;
408 if (!BOOST_TEST(std::abs( diff ) <= max_ulp))
409 std::fprintf(stderr,
410 format: "%s: difference %" PRId64 " ulp\n"
411 " strtod: %.13a %.16g\n"
412 " boost.json: %.13a %.16g\n\n",
413 nm, diff, x, x, y, y );
414 }
415
416 void
417 testWithinULP()
418 {
419 std::mt19937_64 rng;
420
421 checkAccuracy(nm: "10199214983525025199.13135016100190689227e-308", max_ulp: 2);
422
423 for( int i = 0; i < 1000000; ++i )
424 {
425 unsigned long long x1 = rng();
426 unsigned long long x2 = rng();
427 int x3 = std::uniform_int_distribution<>( -308, +308 )( rng );
428
429 char buffer[ 128 ];
430 sprintf( buf&: buffer, format: "%llu.%llue%d", args&: x1, args&: x2, args&: x3 );
431
432 parse_options precise;
433 precise.numbers = number_precision::precise;
434 checkAccuracy( nm: buffer, max_ulp: 2 );
435 checkAccuracy( nm: buffer, max_ulp: 0, opts: precise );
436 }
437
438 for( int i = -326; i <= +309; ++i )
439 {
440 char buffer[ 128 ];
441 sprintf( buf&: buffer, format: "1e%d", args&: i );
442
443 checkAccuracy( nm: buffer, max_ulp: 0 );
444 }
445 }
446
447 void
448 testExtraPrecision()
449 {
450 parse_options opts;
451 opts.numbers = number_precision::precise;
452 BOOST_TEST(
453 parse("1002.9111801605201", {}, opts) == 1002.9111801605201 );
454 BOOST_TEST(
455 parse("-1.0346132515963697", {}, opts) == -1.0346132515963697 );
456 BOOST_TEST(
457 parse("-1207.1290929173115", {}, opts) == -1207.1290929173115 );
458 BOOST_TEST(
459 parse("-0.90521880279912548", {}, opts) == -0.90521880279912548 );
460 BOOST_TEST(
461 parse("370.91535570754445", {}, opts) == 370.91535570754445 );
462 BOOST_TEST(
463 parse("-2578.5523049665962", {}, opts) == -2578.5523049665962 );
464
465 // test cases from https://www.icir.org/vern/papers/testbase-report.pdf
466 // (A Program for Testing IEEE Decimal–Binary Conversion by Vern Paxson)
467 BOOST_TEST(
468 parse("5e125", {}, opts) == 5e125 );
469 BOOST_TEST(
470 parse("69e267", {}, opts) == 69e267 );
471 BOOST_TEST(
472 parse("999e-026", {}, opts) == 999e-026 );
473 BOOST_TEST(
474 parse("7861e-034", {}, opts) == 7861e-034 );
475 BOOST_TEST(
476 parse("75569e-254", {}, opts) == 75569e-254 );
477 BOOST_TEST(
478 parse("928609e-261", {}, opts) == 928609e-261 );
479 BOOST_TEST(
480 parse("9210917e080", {}, opts) == 9210917e080 );
481 BOOST_TEST(
482 parse("84863171e114", {}, opts) == 84863171e114 );
483 BOOST_TEST(
484 parse("653777767e273", {}, opts) == 653777767e273 );
485 BOOST_TEST(
486 parse("5232604057e-298", {}, opts) == 5232604057e-298 );
487 BOOST_TEST(
488 parse("27235667517e-109", {}, opts) == 27235667517e-109 );
489 BOOST_TEST(
490 parse("653532977297e-123", {}, opts) == 653532977297e-123 );
491 BOOST_TEST(
492 parse("3142213164987e-294", {}, opts) == 3142213164987e-294 );
493 BOOST_TEST(
494 parse("46202199371337e-072", {}, opts) == 46202199371337e-072 );
495 BOOST_TEST(
496 parse("231010996856685e-073", {}, opts) == 231010996856685e-073 );
497 BOOST_TEST(
498 parse("9324754620109615e212", {}, opts) == 9324754620109615e212 );
499 BOOST_TEST(
500 parse("78459735791271921e049", {}, opts) == 78459735791271921e049 );
501 BOOST_TEST(
502 parse("272104041512242479e200", {}, opts) == 272104041512242479e200 );
503 BOOST_TEST(
504 parse("6802601037806061975e198", {}, opts) == 6802601037806061975e198 );
505 BOOST_TEST(
506 parse("20505426358836677347e-221", {}, opts) == 20505426358836677347e-221 );
507 BOOST_TEST(
508 parse("836168422905420598437e-234", {}, opts) == 836168422905420598437e-234 );
509 BOOST_TEST(
510 parse("4891559871276714924261e222", {}, opts) == 4891559871276714924261e222 );
511 BOOST_TEST(
512 parse("9e-265", {}, opts) == 9e-265 );
513 BOOST_TEST(
514 parse("85e-037", {}, opts) == 85e-037 );
515 BOOST_TEST(
516 parse("623e100", {}, opts) == 623e100 );
517 BOOST_TEST(
518 parse("3571e263", {}, opts) == 3571e263 );
519 BOOST_TEST(
520 parse("81661e153", {}, opts) == 81661e153 );
521 BOOST_TEST(
522 parse("920657e-023", {}, opts) == 920657e-023 );
523 BOOST_TEST(
524 parse("4603285e-024", {}, opts) == 4603285e-024 );
525 BOOST_TEST(
526 parse("87575437e-309", {}, opts) == 87575437e-309 );
527 BOOST_TEST(
528 parse("245540327e122", {}, opts) == 245540327e122 );
529 BOOST_TEST(
530 parse("6138508175e120", {}, opts) == 6138508175e120 );
531 BOOST_TEST(
532 parse("83356057653e193", {}, opts) == 83356057653e193 );
533 BOOST_TEST(
534 parse("619534293513e124", {}, opts) == 619534293513e124 );
535 BOOST_TEST(
536 parse("2335141086879e218", {}, opts) == 2335141086879e218 );
537 BOOST_TEST(
538 parse("36167929443327e-159", {}, opts) == 36167929443327e-159 );
539 BOOST_TEST(
540 parse("609610927149051e-255", {}, opts) == 609610927149051e-255 );
541 BOOST_TEST(
542 parse("3743626360493413e-165", {}, opts) == 3743626360493413e-165 );
543 BOOST_TEST(
544 parse("94080055902682397e-242", {}, opts) == 94080055902682397e-242 );
545 BOOST_TEST(
546 parse("899810892172646163e283", {}, opts) == 899810892172646163e283 );
547 BOOST_TEST(
548 parse("7120190517612959703e120", {}, opts) == 7120190517612959703e120 );
549 BOOST_TEST(
550 parse("25188282901709339043e-252", {}, opts) == 25188282901709339043e-252 );
551 BOOST_TEST(
552 parse("308984926168550152811e-052", {}, opts) == 308984926168550152811e-052 );
553 BOOST_TEST(
554 parse("6372891218502368041059e064", {}, opts) == 6372891218502368041059e064 );
555 }
556
557 void
558 testSpecialNumbers()
559 {
560 parse_options with_special_numbers;
561 with_special_numbers.allow_infinity_and_nan = true;
562
563 grind_double(
564 s: "Infinity",
565 v: std::numeric_limits<double>::infinity(),
566 po: with_special_numbers);
567
568 grind_double(
569 s: "-Infinity",
570 v: -std::numeric_limits<double>::infinity(),
571 po: with_special_numbers);
572
573 grind_double(
574 s: "NaN",
575 v: std::numeric_limits<double>::quiet_NaN(),
576 po: with_special_numbers);
577 }
578
579 void
580 run()
581 {
582 testDouble();
583 testWithinULP();
584 testExtraPrecision();
585 testSpecialNumbers();
586 }
587};
588
589TEST_SUITE(double_test, "boost.json.double");
590
591} // namespace json
592} // namespace boost
593

source code of boost/libs/json/test/double.cpp