3 __| | __| | | | JSON for Modern C++ (test suite)
4 | | |__ | | | | | | version 3.10.5
5 |_____|_____|_____|_|___| https://github.com/nlohmann/json
7 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8 SPDX-License-Identifier: MIT
9 Copyright (c) 2013-2022 Niels Lohmann <http://nlohmann.me>.
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 #include "doctest_compatibility.h"
32 // for some reason including this after the json header leads to linker errors with VS 2017...
35 #include <nlohmann/json.hpp>
42 #include <test_data.hpp>
44 // this test suite uses static variables with non-trivial destructors
45 DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
46 DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
53 void check_utf8dump(bool success_expected
, int byte1
, int byte2
, int byte3
, int byte4
);
55 void check_utf8dump(bool success_expected
, int byte1
, int byte2
= -1, int byte3
= -1, int byte4
= -1)
57 static std::string json_string
;
65 json_string
+= std::string(1, static_cast<char>(byte1
));
69 json_string
+= std::string(1, static_cast<char>(byte2
));
74 json_string
+= std::string(1, static_cast<char>(byte3
));
79 json_string
+= std::string(1, static_cast<char>(byte4
));
84 // store the string in a JSON value
88 j2
= "abc" + json_string
+ "xyz";
90 static std::string s_ignored
;
91 static std::string s_ignored2
;
92 static std::string s_ignored_ascii
;
93 static std::string s_ignored2_ascii
;
94 static std::string s_replaced
;
95 static std::string s_replaced2
;
96 static std::string s_replaced_ascii
;
97 static std::string s_replaced2_ascii
;
99 // dumping with ignore/replace must not throw in any case
100 s_ignored
= j
.dump(-1, ' ', false, json::error_handler_t::ignore
);
101 s_ignored2
= j2
.dump(-1, ' ', false, json::error_handler_t::ignore
);
102 s_ignored_ascii
= j
.dump(-1, ' ', true, json::error_handler_t::ignore
);
103 s_ignored2_ascii
= j2
.dump(-1, ' ', true, json::error_handler_t::ignore
);
104 s_replaced
= j
.dump(-1, ' ', false, json::error_handler_t::replace
);
105 s_replaced2
= j2
.dump(-1, ' ', false, json::error_handler_t::replace
);
106 s_replaced_ascii
= j
.dump(-1, ' ', true, json::error_handler_t::replace
);
107 s_replaced2_ascii
= j2
.dump(-1, ' ', true, json::error_handler_t::replace
);
109 if (success_expected
)
111 static std::string s_strict
;
112 // strict mode must not throw if success is expected
114 // all dumps should agree on the string
115 CHECK(s_strict
== s_ignored
);
116 CHECK(s_strict
== s_replaced
);
120 // strict mode must throw if success is not expected
121 CHECK_THROWS_AS(j
.dump(), json::type_error
&);
122 // ignore and replace must create different dumps
123 CHECK(s_ignored
!= s_replaced
);
125 // check that replace string contains a replacement character
126 CHECK(s_replaced
.find("\xEF\xBF\xBD") != std::string::npos
);
129 // check that prefix and suffix are preserved
130 CHECK(s_ignored2
.substr(1, 3) == "abc");
131 CHECK(s_ignored2
.substr(s_ignored2
.size() - 4, 3) == "xyz");
132 CHECK(s_ignored2_ascii
.substr(1, 3) == "abc");
133 CHECK(s_ignored2_ascii
.substr(s_ignored2_ascii
.size() - 4, 3) == "xyz");
134 CHECK(s_replaced2
.substr(1, 3) == "abc");
135 CHECK(s_replaced2
.substr(s_replaced2
.size() - 4, 3) == "xyz");
136 CHECK(s_replaced2_ascii
.substr(1, 3) == "abc");
137 CHECK(s_replaced2_ascii
.substr(s_replaced2_ascii
.size() - 4, 3) == "xyz");
140 void check_utf8string(bool success_expected
, int byte1
, int byte2
, int byte3
, int byte4
);
142 // create and check a JSON string with up to four UTF-8 bytes
143 void check_utf8string(bool success_expected
, int byte1
, int byte2
= -1, int byte3
= -1, int byte4
= -1)
145 if (++calls
% 100000 == 0)
147 std::cout
<< calls
<< " of 1246225 UTF-8 strings checked" << std::endl
;
150 static std::string json_string
;
154 json_string
+= std::string(1, static_cast<char>(byte1
));
159 json_string
+= std::string(1, static_cast<char>(byte2
));
165 json_string
+= std::string(1, static_cast<char>(byte3
));
171 json_string
+= std::string(1, static_cast<char>(byte4
));
179 if (success_expected
)
181 CHECK_NOTHROW(_
= json::parse(json_string
));
185 CHECK_THROWS_AS(_
= json::parse(json_string
), json::parse_error
&);
190 TEST_CASE("Unicode (5/5)" * doctest::skip())
195 RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as
198 A UTF-8 string is a sequence of octets representing a sequence of UCS
199 characters. An octet sequence is valid UTF-8 only if it matches the
200 following syntax, which is derived from the rules for encoding UTF-8
201 and is expressed in the ABNF of [RFC2234].
203 UTF8-octets = *( UTF8-char )
204 UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
206 UTF8-2 = %xC2-DF UTF8-tail
207 UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
208 %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
209 UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
210 %xF4 %x80-8F 2( UTF8-tail )
214 SECTION("UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail)")
216 SECTION("well-formed")
218 for (int byte1
= 0xF4; byte1
<= 0xF4; ++byte1
)
220 for (int byte2
= 0x80; byte2
<= 0x8F; ++byte2
)
222 for (int byte3
= 0x80; byte3
<= 0xBF; ++byte3
)
224 for (int byte4
= 0x80; byte4
<= 0xBF; ++byte4
)
226 check_utf8string(true, byte1
, byte2
, byte3
, byte4
);
227 check_utf8dump(true, byte1
, byte2
, byte3
, byte4
);
234 SECTION("ill-formed: missing second byte")
236 for (int byte1
= 0xF4; byte1
<= 0xF4; ++byte1
)
238 check_utf8string(false, byte1
);
239 check_utf8dump(false, byte1
);
243 SECTION("ill-formed: missing third byte")
245 for (int byte1
= 0xF4; byte1
<= 0xF4; ++byte1
)
247 for (int byte2
= 0x80; byte2
<= 0x8F; ++byte2
)
249 check_utf8string(false, byte1
, byte2
);
250 check_utf8dump(false, byte1
, byte2
);
255 SECTION("ill-formed: missing fourth byte")
257 for (int byte1
= 0xF4; byte1
<= 0xF4; ++byte1
)
259 for (int byte2
= 0x80; byte2
<= 0x8F; ++byte2
)
261 for (int byte3
= 0x80; byte3
<= 0xBF; ++byte3
)
263 check_utf8string(false, byte1
, byte2
, byte3
);
264 check_utf8dump(false, byte1
, byte2
, byte3
);
270 SECTION("ill-formed: wrong second byte")
272 for (int byte1
= 0xF4; byte1
<= 0xF4; ++byte1
)
274 for (int byte2
= 0x00; byte2
<= 0xFF; ++byte2
)
276 // skip correct second byte
277 if (0x80 <= byte2
&& byte2
<= 0x8F)
282 for (int byte3
= 0x80; byte3
<= 0xBF; ++byte3
)
284 for (int byte4
= 0x80; byte4
<= 0xBF; ++byte4
)
286 check_utf8string(false, byte1
, byte2
, byte3
, byte4
);
287 check_utf8dump(false, byte1
, byte2
, byte3
, byte4
);
294 SECTION("ill-formed: wrong third byte")
296 for (int byte1
= 0xF4; byte1
<= 0xF4; ++byte1
)
298 for (int byte2
= 0x80; byte2
<= 0x8F; ++byte2
)
300 for (int byte3
= 0x00; byte3
<= 0xFF; ++byte3
)
302 // skip correct third byte
303 if (0x80 <= byte3
&& byte3
<= 0xBF)
308 for (int byte4
= 0x80; byte4
<= 0xBF; ++byte4
)
310 check_utf8string(false, byte1
, byte2
, byte3
, byte4
);
311 check_utf8dump(false, byte1
, byte2
, byte3
, byte4
);
318 SECTION("ill-formed: wrong fourth byte")
320 for (int byte1
= 0xF4; byte1
<= 0xF4; ++byte1
)
322 for (int byte2
= 0x80; byte2
<= 0x8F; ++byte2
)
324 for (int byte3
= 0x80; byte3
<= 0xBF; ++byte3
)
326 for (int byte4
= 0x00; byte4
<= 0xFF; ++byte4
)
328 // skip correct fourth byte
329 if (0x80 <= byte3
&& byte3
<= 0xBF)
334 check_utf8string(false, byte1
, byte2
, byte3
, byte4
);
335 check_utf8dump(false, byte1
, byte2
, byte3
, byte4
);
345 DOCTEST_CLANG_SUPPRESS_WARNING_POP