1c5f01b2fSopenharmony_ci// __ _____ _____ _____ 2c5f01b2fSopenharmony_ci// __| | __| | | | JSON for Modern C++ (supporting code) 3c5f01b2fSopenharmony_ci// | | |__ | | | | | | version 3.11.2 4c5f01b2fSopenharmony_ci// |_____|_____|_____|_|___| https://github.com/nlohmann/json 5c5f01b2fSopenharmony_ci// 6c5f01b2fSopenharmony_ci// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> 7c5f01b2fSopenharmony_ci// SPDX-License-Identifier: MIT 8c5f01b2fSopenharmony_ci 9c5f01b2fSopenharmony_ci#include "doctest_compatibility.h" 10c5f01b2fSopenharmony_ci 11c5f01b2fSopenharmony_ci// for some reason including this after the json header leads to linker errors with VS 2017... 12c5f01b2fSopenharmony_ci#include <locale> 13c5f01b2fSopenharmony_ci 14c5f01b2fSopenharmony_ci#include <nlohmann/json.hpp> 15c5f01b2fSopenharmony_ciusing nlohmann::json; 16c5f01b2fSopenharmony_ci 17c5f01b2fSopenharmony_ci#include <fstream> 18c5f01b2fSopenharmony_ci#include <sstream> 19c5f01b2fSopenharmony_ci#include <iostream> 20c5f01b2fSopenharmony_ci#include <iomanip> 21c5f01b2fSopenharmony_ci#include "make_test_data_available.hpp" 22c5f01b2fSopenharmony_ci 23c5f01b2fSopenharmony_ci// this test suite uses static variables with non-trivial destructors 24c5f01b2fSopenharmony_ciDOCTEST_CLANG_SUPPRESS_WARNING_PUSH 25c5f01b2fSopenharmony_ciDOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") 26c5f01b2fSopenharmony_ci 27c5f01b2fSopenharmony_cinamespace 28c5f01b2fSopenharmony_ci{ 29c5f01b2fSopenharmony_ciextern size_t calls; 30c5f01b2fSopenharmony_cisize_t calls = 0; 31c5f01b2fSopenharmony_ci 32c5f01b2fSopenharmony_civoid check_utf8dump(bool success_expected, int byte1, int byte2, int byte3, int byte4); 33c5f01b2fSopenharmony_ci 34c5f01b2fSopenharmony_civoid check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) 35c5f01b2fSopenharmony_ci{ 36c5f01b2fSopenharmony_ci static std::string json_string; 37c5f01b2fSopenharmony_ci json_string.clear(); 38c5f01b2fSopenharmony_ci 39c5f01b2fSopenharmony_ci CAPTURE(byte1) 40c5f01b2fSopenharmony_ci CAPTURE(byte2) 41c5f01b2fSopenharmony_ci CAPTURE(byte3) 42c5f01b2fSopenharmony_ci CAPTURE(byte4) 43c5f01b2fSopenharmony_ci 44c5f01b2fSopenharmony_ci json_string += std::string(1, static_cast<char>(byte1)); 45c5f01b2fSopenharmony_ci 46c5f01b2fSopenharmony_ci if (byte2 != -1) 47c5f01b2fSopenharmony_ci { 48c5f01b2fSopenharmony_ci json_string += std::string(1, static_cast<char>(byte2)); 49c5f01b2fSopenharmony_ci } 50c5f01b2fSopenharmony_ci 51c5f01b2fSopenharmony_ci if (byte3 != -1) 52c5f01b2fSopenharmony_ci { 53c5f01b2fSopenharmony_ci json_string += std::string(1, static_cast<char>(byte3)); 54c5f01b2fSopenharmony_ci } 55c5f01b2fSopenharmony_ci 56c5f01b2fSopenharmony_ci if (byte4 != -1) 57c5f01b2fSopenharmony_ci { 58c5f01b2fSopenharmony_ci json_string += std::string(1, static_cast<char>(byte4)); 59c5f01b2fSopenharmony_ci } 60c5f01b2fSopenharmony_ci 61c5f01b2fSopenharmony_ci CAPTURE(json_string) 62c5f01b2fSopenharmony_ci 63c5f01b2fSopenharmony_ci // store the string in a JSON value 64c5f01b2fSopenharmony_ci static json j; 65c5f01b2fSopenharmony_ci static json j2; 66c5f01b2fSopenharmony_ci j = json_string; 67c5f01b2fSopenharmony_ci j2 = "abc" + json_string + "xyz"; 68c5f01b2fSopenharmony_ci 69c5f01b2fSopenharmony_ci static std::string s_ignored; 70c5f01b2fSopenharmony_ci static std::string s_ignored2; 71c5f01b2fSopenharmony_ci static std::string s_ignored_ascii; 72c5f01b2fSopenharmony_ci static std::string s_ignored2_ascii; 73c5f01b2fSopenharmony_ci static std::string s_replaced; 74c5f01b2fSopenharmony_ci static std::string s_replaced2; 75c5f01b2fSopenharmony_ci static std::string s_replaced_ascii; 76c5f01b2fSopenharmony_ci static std::string s_replaced2_ascii; 77c5f01b2fSopenharmony_ci 78c5f01b2fSopenharmony_ci // dumping with ignore/replace must not throw in any case 79c5f01b2fSopenharmony_ci s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore); 80c5f01b2fSopenharmony_ci s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore); 81c5f01b2fSopenharmony_ci s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore); 82c5f01b2fSopenharmony_ci s_ignored2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::ignore); 83c5f01b2fSopenharmony_ci s_replaced = j.dump(-1, ' ', false, json::error_handler_t::replace); 84c5f01b2fSopenharmony_ci s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace); 85c5f01b2fSopenharmony_ci s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace); 86c5f01b2fSopenharmony_ci s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace); 87c5f01b2fSopenharmony_ci 88c5f01b2fSopenharmony_ci if (success_expected) 89c5f01b2fSopenharmony_ci { 90c5f01b2fSopenharmony_ci static std::string s_strict; 91c5f01b2fSopenharmony_ci // strict mode must not throw if success is expected 92c5f01b2fSopenharmony_ci s_strict = j.dump(); 93c5f01b2fSopenharmony_ci // all dumps should agree on the string 94c5f01b2fSopenharmony_ci CHECK(s_strict == s_ignored); 95c5f01b2fSopenharmony_ci CHECK(s_strict == s_replaced); 96c5f01b2fSopenharmony_ci } 97c5f01b2fSopenharmony_ci else 98c5f01b2fSopenharmony_ci { 99c5f01b2fSopenharmony_ci // strict mode must throw if success is not expected 100c5f01b2fSopenharmony_ci CHECK_THROWS_AS(j.dump(), json::type_error&); 101c5f01b2fSopenharmony_ci // ignore and replace must create different dumps 102c5f01b2fSopenharmony_ci CHECK(s_ignored != s_replaced); 103c5f01b2fSopenharmony_ci 104c5f01b2fSopenharmony_ci // check that replace string contains a replacement character 105c5f01b2fSopenharmony_ci CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos); 106c5f01b2fSopenharmony_ci } 107c5f01b2fSopenharmony_ci 108c5f01b2fSopenharmony_ci // check that prefix and suffix are preserved 109c5f01b2fSopenharmony_ci CHECK(s_ignored2.substr(1, 3) == "abc"); 110c5f01b2fSopenharmony_ci CHECK(s_ignored2.substr(s_ignored2.size() - 4, 3) == "xyz"); 111c5f01b2fSopenharmony_ci CHECK(s_ignored2_ascii.substr(1, 3) == "abc"); 112c5f01b2fSopenharmony_ci CHECK(s_ignored2_ascii.substr(s_ignored2_ascii.size() - 4, 3) == "xyz"); 113c5f01b2fSopenharmony_ci CHECK(s_replaced2.substr(1, 3) == "abc"); 114c5f01b2fSopenharmony_ci CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz"); 115c5f01b2fSopenharmony_ci CHECK(s_replaced2_ascii.substr(1, 3) == "abc"); 116c5f01b2fSopenharmony_ci CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz"); 117c5f01b2fSopenharmony_ci} 118c5f01b2fSopenharmony_ci 119c5f01b2fSopenharmony_civoid check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4); 120c5f01b2fSopenharmony_ci 121c5f01b2fSopenharmony_ci// create and check a JSON string with up to four UTF-8 bytes 122c5f01b2fSopenharmony_civoid check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) 123c5f01b2fSopenharmony_ci{ 124c5f01b2fSopenharmony_ci if (++calls % 100000 == 0) 125c5f01b2fSopenharmony_ci { 126c5f01b2fSopenharmony_ci std::cout << calls << " of 1246225 UTF-8 strings checked" << std::endl; 127c5f01b2fSopenharmony_ci } 128c5f01b2fSopenharmony_ci 129c5f01b2fSopenharmony_ci static std::string json_string; 130c5f01b2fSopenharmony_ci json_string = "\""; 131c5f01b2fSopenharmony_ci 132c5f01b2fSopenharmony_ci CAPTURE(byte1) 133c5f01b2fSopenharmony_ci json_string += std::string(1, static_cast<char>(byte1)); 134c5f01b2fSopenharmony_ci 135c5f01b2fSopenharmony_ci if (byte2 != -1) 136c5f01b2fSopenharmony_ci { 137c5f01b2fSopenharmony_ci CAPTURE(byte2) 138c5f01b2fSopenharmony_ci json_string += std::string(1, static_cast<char>(byte2)); 139c5f01b2fSopenharmony_ci } 140c5f01b2fSopenharmony_ci 141c5f01b2fSopenharmony_ci if (byte3 != -1) 142c5f01b2fSopenharmony_ci { 143c5f01b2fSopenharmony_ci CAPTURE(byte3) 144c5f01b2fSopenharmony_ci json_string += std::string(1, static_cast<char>(byte3)); 145c5f01b2fSopenharmony_ci } 146c5f01b2fSopenharmony_ci 147c5f01b2fSopenharmony_ci if (byte4 != -1) 148c5f01b2fSopenharmony_ci { 149c5f01b2fSopenharmony_ci CAPTURE(byte4) 150c5f01b2fSopenharmony_ci json_string += std::string(1, static_cast<char>(byte4)); 151c5f01b2fSopenharmony_ci } 152c5f01b2fSopenharmony_ci 153c5f01b2fSopenharmony_ci json_string += "\""; 154c5f01b2fSopenharmony_ci 155c5f01b2fSopenharmony_ci CAPTURE(json_string) 156c5f01b2fSopenharmony_ci 157c5f01b2fSopenharmony_ci json _; 158c5f01b2fSopenharmony_ci if (success_expected) 159c5f01b2fSopenharmony_ci { 160c5f01b2fSopenharmony_ci CHECK_NOTHROW(_ = json::parse(json_string)); 161c5f01b2fSopenharmony_ci } 162c5f01b2fSopenharmony_ci else 163c5f01b2fSopenharmony_ci { 164c5f01b2fSopenharmony_ci CHECK_THROWS_AS(_ = json::parse(json_string), json::parse_error&); 165c5f01b2fSopenharmony_ci } 166c5f01b2fSopenharmony_ci} 167c5f01b2fSopenharmony_ci} // namespace 168c5f01b2fSopenharmony_ci 169c5f01b2fSopenharmony_ciTEST_CASE("Unicode (5/5)" * doctest::skip()) 170c5f01b2fSopenharmony_ci{ 171c5f01b2fSopenharmony_ci SECTION("RFC 3629") 172c5f01b2fSopenharmony_ci { 173c5f01b2fSopenharmony_ci /* 174c5f01b2fSopenharmony_ci RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as 175c5f01b2fSopenharmony_ci follows: 176c5f01b2fSopenharmony_ci 177c5f01b2fSopenharmony_ci A UTF-8 string is a sequence of octets representing a sequence of UCS 178c5f01b2fSopenharmony_ci characters. An octet sequence is valid UTF-8 only if it matches the 179c5f01b2fSopenharmony_ci following syntax, which is derived from the rules for encoding UTF-8 180c5f01b2fSopenharmony_ci and is expressed in the ABNF of [RFC2234]. 181c5f01b2fSopenharmony_ci 182c5f01b2fSopenharmony_ci UTF8-octets = *( UTF8-char ) 183c5f01b2fSopenharmony_ci UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 184c5f01b2fSopenharmony_ci UTF8-1 = %x00-7F 185c5f01b2fSopenharmony_ci UTF8-2 = %xC2-DF UTF8-tail 186c5f01b2fSopenharmony_ci UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / 187c5f01b2fSopenharmony_ci %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) 188c5f01b2fSopenharmony_ci UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / 189c5f01b2fSopenharmony_ci %xF4 %x80-8F 2( UTF8-tail ) 190c5f01b2fSopenharmony_ci UTF8-tail = %x80-BF 191c5f01b2fSopenharmony_ci */ 192c5f01b2fSopenharmony_ci 193c5f01b2fSopenharmony_ci SECTION("UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail)") 194c5f01b2fSopenharmony_ci { 195c5f01b2fSopenharmony_ci SECTION("well-formed") 196c5f01b2fSopenharmony_ci { 197c5f01b2fSopenharmony_ci for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) 198c5f01b2fSopenharmony_ci { 199c5f01b2fSopenharmony_ci for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) 200c5f01b2fSopenharmony_ci { 201c5f01b2fSopenharmony_ci for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) 202c5f01b2fSopenharmony_ci { 203c5f01b2fSopenharmony_ci for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) 204c5f01b2fSopenharmony_ci { 205c5f01b2fSopenharmony_ci check_utf8string(true, byte1, byte2, byte3, byte4); 206c5f01b2fSopenharmony_ci check_utf8dump(true, byte1, byte2, byte3, byte4); 207c5f01b2fSopenharmony_ci } 208c5f01b2fSopenharmony_ci } 209c5f01b2fSopenharmony_ci } 210c5f01b2fSopenharmony_ci } 211c5f01b2fSopenharmony_ci } 212c5f01b2fSopenharmony_ci 213c5f01b2fSopenharmony_ci SECTION("ill-formed: missing second byte") 214c5f01b2fSopenharmony_ci { 215c5f01b2fSopenharmony_ci for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) 216c5f01b2fSopenharmony_ci { 217c5f01b2fSopenharmony_ci check_utf8string(false, byte1); 218c5f01b2fSopenharmony_ci check_utf8dump(false, byte1); 219c5f01b2fSopenharmony_ci } 220c5f01b2fSopenharmony_ci } 221c5f01b2fSopenharmony_ci 222c5f01b2fSopenharmony_ci SECTION("ill-formed: missing third byte") 223c5f01b2fSopenharmony_ci { 224c5f01b2fSopenharmony_ci for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) 225c5f01b2fSopenharmony_ci { 226c5f01b2fSopenharmony_ci for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) 227c5f01b2fSopenharmony_ci { 228c5f01b2fSopenharmony_ci check_utf8string(false, byte1, byte2); 229c5f01b2fSopenharmony_ci check_utf8dump(false, byte1, byte2); 230c5f01b2fSopenharmony_ci } 231c5f01b2fSopenharmony_ci } 232c5f01b2fSopenharmony_ci } 233c5f01b2fSopenharmony_ci 234c5f01b2fSopenharmony_ci SECTION("ill-formed: missing fourth byte") 235c5f01b2fSopenharmony_ci { 236c5f01b2fSopenharmony_ci for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) 237c5f01b2fSopenharmony_ci { 238c5f01b2fSopenharmony_ci for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) 239c5f01b2fSopenharmony_ci { 240c5f01b2fSopenharmony_ci for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) 241c5f01b2fSopenharmony_ci { 242c5f01b2fSopenharmony_ci check_utf8string(false, byte1, byte2, byte3); 243c5f01b2fSopenharmony_ci check_utf8dump(false, byte1, byte2, byte3); 244c5f01b2fSopenharmony_ci } 245c5f01b2fSopenharmony_ci } 246c5f01b2fSopenharmony_ci } 247c5f01b2fSopenharmony_ci } 248c5f01b2fSopenharmony_ci 249c5f01b2fSopenharmony_ci SECTION("ill-formed: wrong second byte") 250c5f01b2fSopenharmony_ci { 251c5f01b2fSopenharmony_ci for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) 252c5f01b2fSopenharmony_ci { 253c5f01b2fSopenharmony_ci for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) 254c5f01b2fSopenharmony_ci { 255c5f01b2fSopenharmony_ci // skip correct second byte 256c5f01b2fSopenharmony_ci if (0x80 <= byte2 && byte2 <= 0x8F) 257c5f01b2fSopenharmony_ci { 258c5f01b2fSopenharmony_ci continue; 259c5f01b2fSopenharmony_ci } 260c5f01b2fSopenharmony_ci 261c5f01b2fSopenharmony_ci for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) 262c5f01b2fSopenharmony_ci { 263c5f01b2fSopenharmony_ci for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) 264c5f01b2fSopenharmony_ci { 265c5f01b2fSopenharmony_ci check_utf8string(false, byte1, byte2, byte3, byte4); 266c5f01b2fSopenharmony_ci check_utf8dump(false, byte1, byte2, byte3, byte4); 267c5f01b2fSopenharmony_ci } 268c5f01b2fSopenharmony_ci } 269c5f01b2fSopenharmony_ci } 270c5f01b2fSopenharmony_ci } 271c5f01b2fSopenharmony_ci } 272c5f01b2fSopenharmony_ci 273c5f01b2fSopenharmony_ci SECTION("ill-formed: wrong third byte") 274c5f01b2fSopenharmony_ci { 275c5f01b2fSopenharmony_ci for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) 276c5f01b2fSopenharmony_ci { 277c5f01b2fSopenharmony_ci for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) 278c5f01b2fSopenharmony_ci { 279c5f01b2fSopenharmony_ci for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) 280c5f01b2fSopenharmony_ci { 281c5f01b2fSopenharmony_ci // skip correct third byte 282c5f01b2fSopenharmony_ci if (0x80 <= byte3 && byte3 <= 0xBF) 283c5f01b2fSopenharmony_ci { 284c5f01b2fSopenharmony_ci continue; 285c5f01b2fSopenharmony_ci } 286c5f01b2fSopenharmony_ci 287c5f01b2fSopenharmony_ci for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) 288c5f01b2fSopenharmony_ci { 289c5f01b2fSopenharmony_ci check_utf8string(false, byte1, byte2, byte3, byte4); 290c5f01b2fSopenharmony_ci check_utf8dump(false, byte1, byte2, byte3, byte4); 291c5f01b2fSopenharmony_ci } 292c5f01b2fSopenharmony_ci } 293c5f01b2fSopenharmony_ci } 294c5f01b2fSopenharmony_ci } 295c5f01b2fSopenharmony_ci } 296c5f01b2fSopenharmony_ci 297c5f01b2fSopenharmony_ci SECTION("ill-formed: wrong fourth byte") 298c5f01b2fSopenharmony_ci { 299c5f01b2fSopenharmony_ci for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) 300c5f01b2fSopenharmony_ci { 301c5f01b2fSopenharmony_ci for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) 302c5f01b2fSopenharmony_ci { 303c5f01b2fSopenharmony_ci for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) 304c5f01b2fSopenharmony_ci { 305c5f01b2fSopenharmony_ci for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) 306c5f01b2fSopenharmony_ci { 307c5f01b2fSopenharmony_ci // skip correct fourth byte 308c5f01b2fSopenharmony_ci if (0x80 <= byte3 && byte3 <= 0xBF) 309c5f01b2fSopenharmony_ci { 310c5f01b2fSopenharmony_ci continue; 311c5f01b2fSopenharmony_ci } 312c5f01b2fSopenharmony_ci 313c5f01b2fSopenharmony_ci check_utf8string(false, byte1, byte2, byte3, byte4); 314c5f01b2fSopenharmony_ci check_utf8dump(false, byte1, byte2, byte3, byte4); 315c5f01b2fSopenharmony_ci } 316c5f01b2fSopenharmony_ci } 317c5f01b2fSopenharmony_ci } 318c5f01b2fSopenharmony_ci } 319c5f01b2fSopenharmony_ci } 320c5f01b2fSopenharmony_ci } 321c5f01b2fSopenharmony_ci } 322c5f01b2fSopenharmony_ci} 323c5f01b2fSopenharmony_ci 324c5f01b2fSopenharmony_ciDOCTEST_CLANG_SUPPRESS_WARNING_POP 325