• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //     __ _____ _____ _____
2 //  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3 // |  |  |__   |  |  | | | |  version 3.11.2
4 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8 
9 #include "doctest_compatibility.h"
10 
11 // for some reason including this after the json header leads to linker errors with VS 2017...
12 #include <locale>
13 
14 #include <nlohmann/json.hpp>
15 using nlohmann::json;
16 
17 #include <fstream>
18 #include <sstream>
19 #include <iostream>
20 #include <iomanip>
21 #include "make_test_data_available.hpp"
22 
23 // this test suite uses static variables with non-trivial destructors
24 DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
25 DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
26 
27 namespace
28 {
29 extern size_t calls;
30 size_t calls = 0;
31 
32 void check_utf8dump(bool success_expected, int byte1, int byte2, int byte3, int byte4);
33 
check_utf8dump(bool success_expected,int byte1,int byte2=-1,int byte3=-1,int byte4=-1)34 void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1)
35 {
36     static std::string json_string;
37     json_string.clear();
38 
39     CAPTURE(byte1)
40     CAPTURE(byte2)
41     CAPTURE(byte3)
42     CAPTURE(byte4)
43 
44     json_string += std::string(1, static_cast<char>(byte1));
45 
46     if (byte2 != -1)
47     {
48         json_string += std::string(1, static_cast<char>(byte2));
49     }
50 
51     if (byte3 != -1)
52     {
53         json_string += std::string(1, static_cast<char>(byte3));
54     }
55 
56     if (byte4 != -1)
57     {
58         json_string += std::string(1, static_cast<char>(byte4));
59     }
60 
61     CAPTURE(json_string)
62 
63     // store the string in a JSON value
64     static json j;
65     static json j2;
66     j = json_string;
67     j2 = "abc" + json_string + "xyz";
68 
69     static std::string s_ignored;
70     static std::string s_ignored2;
71     static std::string s_ignored_ascii;
72     static std::string s_ignored2_ascii;
73     static std::string s_replaced;
74     static std::string s_replaced2;
75     static std::string s_replaced_ascii;
76     static std::string s_replaced2_ascii;
77 
78     // dumping with ignore/replace must not throw in any case
79     s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore);
80     s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore);
81     s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore);
82     s_ignored2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::ignore);
83     s_replaced = j.dump(-1, ' ', false, json::error_handler_t::replace);
84     s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace);
85     s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace);
86     s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace);
87 
88     if (success_expected)
89     {
90         static std::string s_strict;
91         // strict mode must not throw if success is expected
92         s_strict = j.dump();
93         // all dumps should agree on the string
94         CHECK(s_strict == s_ignored);
95         CHECK(s_strict == s_replaced);
96     }
97     else
98     {
99         // strict mode must throw if success is not expected
100         CHECK_THROWS_AS(j.dump(), json::type_error&);
101         // ignore and replace must create different dumps
102         CHECK(s_ignored != s_replaced);
103 
104         // check that replace string contains a replacement character
105         CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos);
106     }
107 
108     // check that prefix and suffix are preserved
109     CHECK(s_ignored2.substr(1, 3) == "abc");
110     CHECK(s_ignored2.substr(s_ignored2.size() - 4, 3) == "xyz");
111     CHECK(s_ignored2_ascii.substr(1, 3) == "abc");
112     CHECK(s_ignored2_ascii.substr(s_ignored2_ascii.size() - 4, 3) == "xyz");
113     CHECK(s_replaced2.substr(1, 3) == "abc");
114     CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz");
115     CHECK(s_replaced2_ascii.substr(1, 3) == "abc");
116     CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz");
117 }
118 
119 void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4);
120 
121 // create and check a JSON string with up to four UTF-8 bytes
check_utf8string(bool success_expected,int byte1,int byte2=-1,int byte3=-1,int byte4=-1)122 void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1)
123 {
124     if (++calls % 100000 == 0)
125     {
126         std::cout << calls << " of 455355 UTF-8 strings checked" << std::endl;
127     }
128 
129     static std::string json_string;
130     json_string = "\"";
131 
132     CAPTURE(byte1)
133     json_string += std::string(1, static_cast<char>(byte1));
134 
135     if (byte2 != -1)
136     {
137         CAPTURE(byte2)
138         json_string += std::string(1, static_cast<char>(byte2));
139     }
140 
141     if (byte3 != -1)
142     {
143         CAPTURE(byte3)
144         json_string += std::string(1, static_cast<char>(byte3));
145     }
146 
147     if (byte4 != -1)
148     {
149         CAPTURE(byte4)
150         json_string += std::string(1, static_cast<char>(byte4));
151     }
152 
153     json_string += "\"";
154 
155     CAPTURE(json_string)
156 
157     json _;
158     if (success_expected)
159     {
160         CHECK_NOTHROW(_ = json::parse(json_string));
161     }
162     else
163     {
164         CHECK_THROWS_AS(_ = json::parse(json_string), json::parse_error&);
165     }
166 }
167 } // namespace
168 
skip()169 TEST_CASE("Unicode (2/5)" * doctest::skip())
170 {
171     SECTION("RFC 3629")
172     {
173         /*
174         RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as
175         follows:
176 
177             A UTF-8 string is a sequence of octets representing a sequence of UCS
178             characters.  An octet sequence is valid UTF-8 only if it matches the
179             following syntax, which is derived from the rules for encoding UTF-8
180             and is expressed in the ABNF of [RFC2234].
181 
182             UTF8-octets = *( UTF8-char )
183             UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
184             UTF8-1      = %x00-7F
185             UTF8-2      = %xC2-DF UTF8-tail
186             UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
187                           %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
188             UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
189                           %xF4 %x80-8F 2( UTF8-tail )
190             UTF8-tail   = %x80-BF
191         */
192 
193         SECTION("ill-formed first byte")
194         {
195             for (int byte1 = 0x80; byte1 <= 0xC1; ++byte1)
196             {
197                 check_utf8string(false, byte1);
198                 check_utf8dump(false, byte1);
199             }
200 
201             for (int byte1 = 0xF5; byte1 <= 0xFF; ++byte1)
202             {
203                 check_utf8string(false, byte1);
204                 check_utf8dump(false, byte1);
205             }
206         }
207 
208         SECTION("UTF8-1 (x00-x7F)")
209         {
210             SECTION("well-formed")
211             {
212                 for (int byte1 = 0x00; byte1 <= 0x7F; ++byte1)
213                 {
214                     // unescaped control characters are parse errors in JSON
215                     if (0x00 <= byte1 && byte1 <= 0x1F)
216                     {
217                         check_utf8string(false, byte1);
218                         continue;
219                     }
220 
221                     // a single quote is a parse error in JSON
222                     if (byte1 == 0x22)
223                     {
224                         check_utf8string(false, byte1);
225                         continue;
226                     }
227 
228                     // a single backslash is a parse error in JSON
229                     if (byte1 == 0x5C)
230                     {
231                         check_utf8string(false, byte1);
232                         continue;
233                     }
234 
235                     // all other characters are OK
236                     check_utf8string(true, byte1);
237                     check_utf8dump(true, byte1);
238                 }
239             }
240         }
241 
242         SECTION("UTF8-2 (xC2-xDF UTF8-tail)")
243         {
244             SECTION("well-formed")
245             {
246                 for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1)
247                 {
248                     for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
249                     {
250                         check_utf8string(true, byte1, byte2);
251                         check_utf8dump(true, byte1, byte2);
252                     }
253                 }
254             }
255 
256             SECTION("ill-formed: missing second byte")
257             {
258                 for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1)
259                 {
260                     check_utf8string(false, byte1);
261                     check_utf8dump(false, byte1);
262                 }
263             }
264 
265             SECTION("ill-formed: wrong second byte")
266             {
267                 for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1)
268                 {
269                     for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
270                     {
271                         // skip correct second byte
272                         if (0x80 <= byte2 && byte2 <= 0xBF)
273                         {
274                             continue;
275                         }
276 
277                         check_utf8string(false, byte1, byte2);
278                         check_utf8dump(false, byte1, byte2);
279                     }
280                 }
281             }
282         }
283 
284         SECTION("UTF8-3 (xE0 xA0-BF UTF8-tail)")
285         {
286             SECTION("well-formed")
287             {
288                 for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
289                 {
290                     for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2)
291                     {
292                         for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
293                         {
294                             check_utf8string(true, byte1, byte2, byte3);
295                             check_utf8dump(true, byte1, byte2, byte3);
296                         }
297                     }
298                 }
299             }
300 
301             SECTION("ill-formed: missing second byte")
302             {
303                 for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
304                 {
305                     check_utf8string(false, byte1);
306                     check_utf8dump(false, byte1);
307                 }
308             }
309 
310             SECTION("ill-formed: missing third byte")
311             {
312                 for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
313                 {
314                     for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2)
315                     {
316                         check_utf8string(false, byte1, byte2);
317                         check_utf8dump(false, byte1, byte2);
318                     }
319                 }
320             }
321 
322             SECTION("ill-formed: wrong second byte")
323             {
324                 for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
325                 {
326                     for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
327                     {
328                         // skip correct second byte
329                         if (0xA0 <= byte2 && byte2 <= 0xBF)
330                         {
331                             continue;
332                         }
333 
334                         for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
335                         {
336                             check_utf8string(false, byte1, byte2, byte3);
337                             check_utf8dump(false, byte1, byte2, byte3);
338                         }
339                     }
340                 }
341             }
342 
343             SECTION("ill-formed: wrong third byte")
344             {
345                 for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
346                 {
347                     for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2)
348                     {
349                         for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
350                         {
351                             // skip correct third byte
352                             if (0x80 <= byte3 && byte3 <= 0xBF)
353                             {
354                                 continue;
355                             }
356 
357                             check_utf8string(false, byte1, byte2, byte3);
358                             check_utf8dump(false, byte1, byte2, byte3);
359                         }
360                     }
361                 }
362             }
363         }
364 
365         SECTION("UTF8-3 (xE1-xEC UTF8-tail UTF8-tail)")
366         {
367             SECTION("well-formed")
368             {
369                 for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
370                 {
371                     for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
372                     {
373                         for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
374                         {
375                             check_utf8string(true, byte1, byte2, byte3);
376                             check_utf8dump(true, byte1, byte2, byte3);
377                         }
378                     }
379                 }
380             }
381 
382             SECTION("ill-formed: missing second byte")
383             {
384                 for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
385                 {
386                     check_utf8string(false, byte1);
387                     check_utf8dump(false, byte1);
388                 }
389             }
390 
391             SECTION("ill-formed: missing third byte")
392             {
393                 for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
394                 {
395                     for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
396                     {
397                         check_utf8string(false, byte1, byte2);
398                         check_utf8dump(false, byte1, byte2);
399                     }
400                 }
401             }
402 
403             SECTION("ill-formed: wrong second byte")
404             {
405                 for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
406                 {
407                     for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
408                     {
409                         // skip correct second byte
410                         if (0x80 <= byte2 && byte2 <= 0xBF)
411                         {
412                             continue;
413                         }
414 
415                         for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
416                         {
417                             check_utf8string(false, byte1, byte2, byte3);
418                             check_utf8dump(false, byte1, byte2, byte3);
419                         }
420                     }
421                 }
422             }
423 
424             SECTION("ill-formed: wrong third byte")
425             {
426                 for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
427                 {
428                     for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
429                     {
430                         for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
431                         {
432                             // skip correct third byte
433                             if (0x80 <= byte3 && byte3 <= 0xBF)
434                             {
435                                 continue;
436                             }
437 
438                             check_utf8string(false, byte1, byte2, byte3);
439                             check_utf8dump(false, byte1, byte2, byte3);
440                         }
441                     }
442                 }
443             }
444         }
445 
446         SECTION("UTF8-3 (xED x80-9F UTF8-tail)")
447         {
448             SECTION("well-formed")
449             {
450                 for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
451                 {
452                     for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2)
453                     {
454                         for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
455                         {
456                             check_utf8string(true, byte1, byte2, byte3);
457                             check_utf8dump(true, byte1, byte2, byte3);
458                         }
459                     }
460                 }
461             }
462 
463             SECTION("ill-formed: missing second byte")
464             {
465                 for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
466                 {
467                     check_utf8string(false, byte1);
468                     check_utf8dump(false, byte1);
469                 }
470             }
471 
472             SECTION("ill-formed: missing third byte")
473             {
474                 for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
475                 {
476                     for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2)
477                     {
478                         check_utf8string(false, byte1, byte2);
479                         check_utf8dump(false, byte1, byte2);
480                     }
481                 }
482             }
483 
484             SECTION("ill-formed: wrong second byte")
485             {
486                 for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
487                 {
488                     for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
489                     {
490                         // skip correct second byte
491                         if (0x80 <= byte2 && byte2 <= 0x9F)
492                         {
493                             continue;
494                         }
495 
496                         for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
497                         {
498                             check_utf8string(false, byte1, byte2, byte3);
499                             check_utf8dump(false, byte1, byte2, byte3);
500                         }
501                     }
502                 }
503             }
504 
505             SECTION("ill-formed: wrong third byte")
506             {
507                 for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
508                 {
509                     for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2)
510                     {
511                         for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
512                         {
513                             // skip correct third byte
514                             if (0x80 <= byte3 && byte3 <= 0xBF)
515                             {
516                                 continue;
517                             }
518 
519                             check_utf8string(false, byte1, byte2, byte3);
520                             check_utf8dump(false, byte1, byte2, byte3);
521                         }
522                     }
523                 }
524             }
525         }
526 
527         SECTION("UTF8-3 (xEE-xEF UTF8-tail UTF8-tail)")
528         {
529             SECTION("well-formed")
530             {
531                 for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
532                 {
533                     for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
534                     {
535                         for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
536                         {
537                             check_utf8string(true, byte1, byte2, byte3);
538                             check_utf8dump(true, byte1, byte2, byte3);
539                         }
540                     }
541                 }
542             }
543 
544             SECTION("ill-formed: missing second byte")
545             {
546                 for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
547                 {
548                     check_utf8string(false, byte1);
549                     check_utf8dump(false, byte1);
550                 }
551             }
552 
553             SECTION("ill-formed: missing third byte")
554             {
555                 for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
556                 {
557                     for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
558                     {
559                         check_utf8string(false, byte1, byte2);
560                         check_utf8dump(false, byte1, byte2);
561                     }
562                 }
563             }
564 
565             SECTION("ill-formed: wrong second byte")
566             {
567                 for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
568                 {
569                     for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
570                     {
571                         // skip correct second byte
572                         if (0x80 <= byte2 && byte2 <= 0xBF)
573                         {
574                             continue;
575                         }
576 
577                         for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
578                         {
579                             check_utf8string(false, byte1, byte2, byte3);
580                             check_utf8dump(false, byte1, byte2, byte3);
581                         }
582                     }
583                 }
584             }
585 
586             SECTION("ill-formed: wrong third byte")
587             {
588                 for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
589                 {
590                     for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
591                     {
592                         for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
593                         {
594                             // skip correct third byte
595                             if (0x80 <= byte3 && byte3 <= 0xBF)
596                             {
597                                 continue;
598                             }
599 
600                             check_utf8string(false, byte1, byte2, byte3);
601                             check_utf8dump(false, byte1, byte2, byte3);
602                         }
603                     }
604                 }
605             }
606         }
607     }
608 }
609 
610 DOCTEST_CLANG_SUPPRESS_WARNING_POP
611