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#define JSON_TESTS_PRIVATE 12c5f01b2fSopenharmony_ci#include <nlohmann/json.hpp> 13c5f01b2fSopenharmony_ciusing nlohmann::json; 14c5f01b2fSopenharmony_ci#ifdef JSON_TEST_NO_GLOBAL_UDLS 15c5f01b2fSopenharmony_ci using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) 16c5f01b2fSopenharmony_ci#endif 17c5f01b2fSopenharmony_ci 18c5f01b2fSopenharmony_ci#include <valarray> 19c5f01b2fSopenharmony_ci 20c5f01b2fSopenharmony_cinamespace 21c5f01b2fSopenharmony_ci{ 22c5f01b2fSopenharmony_ciclass SaxEventLogger 23c5f01b2fSopenharmony_ci{ 24c5f01b2fSopenharmony_ci public: 25c5f01b2fSopenharmony_ci bool null() 26c5f01b2fSopenharmony_ci { 27c5f01b2fSopenharmony_ci events.emplace_back("null()"); 28c5f01b2fSopenharmony_ci return true; 29c5f01b2fSopenharmony_ci } 30c5f01b2fSopenharmony_ci 31c5f01b2fSopenharmony_ci bool boolean(bool val) 32c5f01b2fSopenharmony_ci { 33c5f01b2fSopenharmony_ci events.emplace_back(val ? "boolean(true)" : "boolean(false)"); 34c5f01b2fSopenharmony_ci return true; 35c5f01b2fSopenharmony_ci } 36c5f01b2fSopenharmony_ci 37c5f01b2fSopenharmony_ci bool number_integer(json::number_integer_t val) 38c5f01b2fSopenharmony_ci { 39c5f01b2fSopenharmony_ci events.push_back("number_integer(" + std::to_string(val) + ")"); 40c5f01b2fSopenharmony_ci return true; 41c5f01b2fSopenharmony_ci } 42c5f01b2fSopenharmony_ci 43c5f01b2fSopenharmony_ci bool number_unsigned(json::number_unsigned_t val) 44c5f01b2fSopenharmony_ci { 45c5f01b2fSopenharmony_ci events.push_back("number_unsigned(" + std::to_string(val) + ")"); 46c5f01b2fSopenharmony_ci return true; 47c5f01b2fSopenharmony_ci } 48c5f01b2fSopenharmony_ci 49c5f01b2fSopenharmony_ci bool number_float(json::number_float_t /*unused*/, const std::string& s) 50c5f01b2fSopenharmony_ci { 51c5f01b2fSopenharmony_ci events.push_back("number_float(" + s + ")"); 52c5f01b2fSopenharmony_ci return true; 53c5f01b2fSopenharmony_ci } 54c5f01b2fSopenharmony_ci 55c5f01b2fSopenharmony_ci bool string(std::string& val) 56c5f01b2fSopenharmony_ci { 57c5f01b2fSopenharmony_ci events.push_back("string(" + val + ")"); 58c5f01b2fSopenharmony_ci return true; 59c5f01b2fSopenharmony_ci } 60c5f01b2fSopenharmony_ci 61c5f01b2fSopenharmony_ci bool binary(json::binary_t& val) 62c5f01b2fSopenharmony_ci { 63c5f01b2fSopenharmony_ci std::string binary_contents = "binary("; 64c5f01b2fSopenharmony_ci std::string comma_space; 65c5f01b2fSopenharmony_ci for (auto b : val) 66c5f01b2fSopenharmony_ci { 67c5f01b2fSopenharmony_ci binary_contents.append(comma_space); 68c5f01b2fSopenharmony_ci binary_contents.append(std::to_string(static_cast<int>(b))); 69c5f01b2fSopenharmony_ci comma_space = ", "; 70c5f01b2fSopenharmony_ci } 71c5f01b2fSopenharmony_ci binary_contents.append(")"); 72c5f01b2fSopenharmony_ci events.push_back(binary_contents); 73c5f01b2fSopenharmony_ci return true; 74c5f01b2fSopenharmony_ci } 75c5f01b2fSopenharmony_ci 76c5f01b2fSopenharmony_ci bool start_object(std::size_t elements) 77c5f01b2fSopenharmony_ci { 78c5f01b2fSopenharmony_ci if (elements == static_cast<std::size_t>(-1)) 79c5f01b2fSopenharmony_ci { 80c5f01b2fSopenharmony_ci events.emplace_back("start_object()"); 81c5f01b2fSopenharmony_ci } 82c5f01b2fSopenharmony_ci else 83c5f01b2fSopenharmony_ci { 84c5f01b2fSopenharmony_ci events.push_back("start_object(" + std::to_string(elements) + ")"); 85c5f01b2fSopenharmony_ci } 86c5f01b2fSopenharmony_ci return true; 87c5f01b2fSopenharmony_ci } 88c5f01b2fSopenharmony_ci 89c5f01b2fSopenharmony_ci bool key(std::string& val) 90c5f01b2fSopenharmony_ci { 91c5f01b2fSopenharmony_ci events.push_back("key(" + val + ")"); 92c5f01b2fSopenharmony_ci return true; 93c5f01b2fSopenharmony_ci } 94c5f01b2fSopenharmony_ci 95c5f01b2fSopenharmony_ci bool end_object() 96c5f01b2fSopenharmony_ci { 97c5f01b2fSopenharmony_ci events.emplace_back("end_object()"); 98c5f01b2fSopenharmony_ci return true; 99c5f01b2fSopenharmony_ci } 100c5f01b2fSopenharmony_ci 101c5f01b2fSopenharmony_ci bool start_array(std::size_t elements) 102c5f01b2fSopenharmony_ci { 103c5f01b2fSopenharmony_ci if (elements == static_cast<std::size_t>(-1)) 104c5f01b2fSopenharmony_ci { 105c5f01b2fSopenharmony_ci events.emplace_back("start_array()"); 106c5f01b2fSopenharmony_ci } 107c5f01b2fSopenharmony_ci else 108c5f01b2fSopenharmony_ci { 109c5f01b2fSopenharmony_ci events.push_back("start_array(" + std::to_string(elements) + ")"); 110c5f01b2fSopenharmony_ci } 111c5f01b2fSopenharmony_ci return true; 112c5f01b2fSopenharmony_ci } 113c5f01b2fSopenharmony_ci 114c5f01b2fSopenharmony_ci bool end_array() 115c5f01b2fSopenharmony_ci { 116c5f01b2fSopenharmony_ci events.emplace_back("end_array()"); 117c5f01b2fSopenharmony_ci return true; 118c5f01b2fSopenharmony_ci } 119c5f01b2fSopenharmony_ci 120c5f01b2fSopenharmony_ci bool parse_error(std::size_t position, const std::string& /*unused*/, const json::exception& /*unused*/) 121c5f01b2fSopenharmony_ci { 122c5f01b2fSopenharmony_ci errored = true; 123c5f01b2fSopenharmony_ci events.push_back("parse_error(" + std::to_string(position) + ")"); 124c5f01b2fSopenharmony_ci return false; 125c5f01b2fSopenharmony_ci } 126c5f01b2fSopenharmony_ci 127c5f01b2fSopenharmony_ci std::vector<std::string> events {}; 128c5f01b2fSopenharmony_ci bool errored = false; 129c5f01b2fSopenharmony_ci}; 130c5f01b2fSopenharmony_ci 131c5f01b2fSopenharmony_ciclass SaxCountdown : public nlohmann::json::json_sax_t 132c5f01b2fSopenharmony_ci{ 133c5f01b2fSopenharmony_ci public: 134c5f01b2fSopenharmony_ci explicit SaxCountdown(const int count) : events_left(count) 135c5f01b2fSopenharmony_ci {} 136c5f01b2fSopenharmony_ci 137c5f01b2fSopenharmony_ci bool null() override 138c5f01b2fSopenharmony_ci { 139c5f01b2fSopenharmony_ci return events_left-- > 0; 140c5f01b2fSopenharmony_ci } 141c5f01b2fSopenharmony_ci 142c5f01b2fSopenharmony_ci bool boolean(bool /*val*/) override 143c5f01b2fSopenharmony_ci { 144c5f01b2fSopenharmony_ci return events_left-- > 0; 145c5f01b2fSopenharmony_ci } 146c5f01b2fSopenharmony_ci 147c5f01b2fSopenharmony_ci bool number_integer(json::number_integer_t /*val*/) override 148c5f01b2fSopenharmony_ci { 149c5f01b2fSopenharmony_ci return events_left-- > 0; 150c5f01b2fSopenharmony_ci } 151c5f01b2fSopenharmony_ci 152c5f01b2fSopenharmony_ci bool number_unsigned(json::number_unsigned_t /*val*/) override 153c5f01b2fSopenharmony_ci { 154c5f01b2fSopenharmony_ci return events_left-- > 0; 155c5f01b2fSopenharmony_ci } 156c5f01b2fSopenharmony_ci 157c5f01b2fSopenharmony_ci bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override 158c5f01b2fSopenharmony_ci { 159c5f01b2fSopenharmony_ci return events_left-- > 0; 160c5f01b2fSopenharmony_ci } 161c5f01b2fSopenharmony_ci 162c5f01b2fSopenharmony_ci bool string(std::string& /*val*/) override 163c5f01b2fSopenharmony_ci { 164c5f01b2fSopenharmony_ci return events_left-- > 0; 165c5f01b2fSopenharmony_ci } 166c5f01b2fSopenharmony_ci 167c5f01b2fSopenharmony_ci bool binary(json::binary_t& /*val*/) override 168c5f01b2fSopenharmony_ci { 169c5f01b2fSopenharmony_ci return events_left-- > 0; 170c5f01b2fSopenharmony_ci } 171c5f01b2fSopenharmony_ci 172c5f01b2fSopenharmony_ci bool start_object(std::size_t /*elements*/) override 173c5f01b2fSopenharmony_ci { 174c5f01b2fSopenharmony_ci return events_left-- > 0; 175c5f01b2fSopenharmony_ci } 176c5f01b2fSopenharmony_ci 177c5f01b2fSopenharmony_ci bool key(std::string& /*val*/) override 178c5f01b2fSopenharmony_ci { 179c5f01b2fSopenharmony_ci return events_left-- > 0; 180c5f01b2fSopenharmony_ci } 181c5f01b2fSopenharmony_ci 182c5f01b2fSopenharmony_ci bool end_object() override 183c5f01b2fSopenharmony_ci { 184c5f01b2fSopenharmony_ci return events_left-- > 0; 185c5f01b2fSopenharmony_ci } 186c5f01b2fSopenharmony_ci 187c5f01b2fSopenharmony_ci bool start_array(std::size_t /*elements*/) override 188c5f01b2fSopenharmony_ci { 189c5f01b2fSopenharmony_ci return events_left-- > 0; 190c5f01b2fSopenharmony_ci } 191c5f01b2fSopenharmony_ci 192c5f01b2fSopenharmony_ci bool end_array() override 193c5f01b2fSopenharmony_ci { 194c5f01b2fSopenharmony_ci return events_left-- > 0; 195c5f01b2fSopenharmony_ci } 196c5f01b2fSopenharmony_ci 197c5f01b2fSopenharmony_ci bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override 198c5f01b2fSopenharmony_ci { 199c5f01b2fSopenharmony_ci return false; 200c5f01b2fSopenharmony_ci } 201c5f01b2fSopenharmony_ci 202c5f01b2fSopenharmony_ci private: 203c5f01b2fSopenharmony_ci int events_left = 0; 204c5f01b2fSopenharmony_ci}; 205c5f01b2fSopenharmony_ci 206c5f01b2fSopenharmony_cijson parser_helper(const std::string& s); 207c5f01b2fSopenharmony_cibool accept_helper(const std::string& s); 208c5f01b2fSopenharmony_civoid comments_helper(const std::string& s); 209c5f01b2fSopenharmony_ci 210c5f01b2fSopenharmony_cijson parser_helper(const std::string& s) 211c5f01b2fSopenharmony_ci{ 212c5f01b2fSopenharmony_ci json j; 213c5f01b2fSopenharmony_ci json::parser(nlohmann::detail::input_adapter(s)).parse(true, j); 214c5f01b2fSopenharmony_ci 215c5f01b2fSopenharmony_ci // if this line was reached, no exception occurred 216c5f01b2fSopenharmony_ci // -> check if result is the same without exceptions 217c5f01b2fSopenharmony_ci json j_nothrow; 218c5f01b2fSopenharmony_ci CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j_nothrow)); 219c5f01b2fSopenharmony_ci CHECK(j_nothrow == j); 220c5f01b2fSopenharmony_ci 221c5f01b2fSopenharmony_ci json j_sax; 222c5f01b2fSopenharmony_ci nlohmann::detail::json_sax_dom_parser<json> sdp(j_sax); 223c5f01b2fSopenharmony_ci json::sax_parse(s, &sdp); 224c5f01b2fSopenharmony_ci CHECK(j_sax == j); 225c5f01b2fSopenharmony_ci 226c5f01b2fSopenharmony_ci comments_helper(s); 227c5f01b2fSopenharmony_ci 228c5f01b2fSopenharmony_ci return j; 229c5f01b2fSopenharmony_ci} 230c5f01b2fSopenharmony_ci 231c5f01b2fSopenharmony_cibool accept_helper(const std::string& s) 232c5f01b2fSopenharmony_ci{ 233c5f01b2fSopenharmony_ci CAPTURE(s) 234c5f01b2fSopenharmony_ci 235c5f01b2fSopenharmony_ci // 1. parse s without exceptions 236c5f01b2fSopenharmony_ci json j; 237c5f01b2fSopenharmony_ci CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j)); 238c5f01b2fSopenharmony_ci const bool ok_noexcept = !j.is_discarded(); 239c5f01b2fSopenharmony_ci 240c5f01b2fSopenharmony_ci // 2. accept s 241c5f01b2fSopenharmony_ci const bool ok_accept = json::parser(nlohmann::detail::input_adapter(s)).accept(true); 242c5f01b2fSopenharmony_ci 243c5f01b2fSopenharmony_ci // 3. check if both approaches come to the same result 244c5f01b2fSopenharmony_ci CHECK(ok_noexcept == ok_accept); 245c5f01b2fSopenharmony_ci 246c5f01b2fSopenharmony_ci // 4. parse with SAX (compare with relaxed accept result) 247c5f01b2fSopenharmony_ci SaxEventLogger el; 248c5f01b2fSopenharmony_ci CHECK_NOTHROW(json::sax_parse(s, &el, json::input_format_t::json, false)); 249c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == !el.errored); 250c5f01b2fSopenharmony_ci 251c5f01b2fSopenharmony_ci // 5. parse with simple callback 252c5f01b2fSopenharmony_ci json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept 253c5f01b2fSopenharmony_ci { 254c5f01b2fSopenharmony_ci return true; 255c5f01b2fSopenharmony_ci }; 256c5f01b2fSopenharmony_ci json j_cb = json::parse(s, cb, false); 257c5f01b2fSopenharmony_ci const bool ok_noexcept_cb = !j_cb.is_discarded(); 258c5f01b2fSopenharmony_ci 259c5f01b2fSopenharmony_ci // 6. check if this approach came to the same result 260c5f01b2fSopenharmony_ci CHECK(ok_noexcept == ok_noexcept_cb); 261c5f01b2fSopenharmony_ci 262c5f01b2fSopenharmony_ci // 7. check if comments are properly ignored 263c5f01b2fSopenharmony_ci if (ok_accept) 264c5f01b2fSopenharmony_ci { 265c5f01b2fSopenharmony_ci comments_helper(s); 266c5f01b2fSopenharmony_ci } 267c5f01b2fSopenharmony_ci 268c5f01b2fSopenharmony_ci // 8. return result 269c5f01b2fSopenharmony_ci return ok_accept; 270c5f01b2fSopenharmony_ci} 271c5f01b2fSopenharmony_ci 272c5f01b2fSopenharmony_civoid comments_helper(const std::string& s) 273c5f01b2fSopenharmony_ci{ 274c5f01b2fSopenharmony_ci json _; 275c5f01b2fSopenharmony_ci 276c5f01b2fSopenharmony_ci // parse/accept with default parser 277c5f01b2fSopenharmony_ci CHECK_NOTHROW(_ = json::parse(s)); 278c5f01b2fSopenharmony_ci CHECK(json::accept(s)); 279c5f01b2fSopenharmony_ci 280c5f01b2fSopenharmony_ci // parse/accept while skipping comments 281c5f01b2fSopenharmony_ci CHECK_NOTHROW(_ = json::parse(s, nullptr, false, true)); 282c5f01b2fSopenharmony_ci CHECK(json::accept(s, true)); 283c5f01b2fSopenharmony_ci 284c5f01b2fSopenharmony_ci std::vector<std::string> json_with_comments; 285c5f01b2fSopenharmony_ci 286c5f01b2fSopenharmony_ci // start with a comment 287c5f01b2fSopenharmony_ci json_with_comments.push_back(std::string("// this is a comment\n") + s); 288c5f01b2fSopenharmony_ci json_with_comments.push_back(std::string("/* this is a comment */") + s); 289c5f01b2fSopenharmony_ci // end with a comment 290c5f01b2fSopenharmony_ci json_with_comments.push_back(s + "// this is a comment"); 291c5f01b2fSopenharmony_ci json_with_comments.push_back(s + "/* this is a comment */"); 292c5f01b2fSopenharmony_ci 293c5f01b2fSopenharmony_ci // check all strings 294c5f01b2fSopenharmony_ci for (const auto& json_with_comment : json_with_comments) 295c5f01b2fSopenharmony_ci { 296c5f01b2fSopenharmony_ci CAPTURE(json_with_comment) 297c5f01b2fSopenharmony_ci CHECK_THROWS_AS(_ = json::parse(json_with_comment), json::parse_error); 298c5f01b2fSopenharmony_ci CHECK(!json::accept(json_with_comment)); 299c5f01b2fSopenharmony_ci 300c5f01b2fSopenharmony_ci CHECK_NOTHROW(_ = json::parse(json_with_comment, nullptr, true, true)); 301c5f01b2fSopenharmony_ci CHECK(json::accept(json_with_comment, true)); 302c5f01b2fSopenharmony_ci } 303c5f01b2fSopenharmony_ci} 304c5f01b2fSopenharmony_ci 305c5f01b2fSopenharmony_ci} // namespace 306c5f01b2fSopenharmony_ci 307c5f01b2fSopenharmony_ciTEST_CASE("parser class") 308c5f01b2fSopenharmony_ci{ 309c5f01b2fSopenharmony_ci SECTION("parse") 310c5f01b2fSopenharmony_ci { 311c5f01b2fSopenharmony_ci SECTION("null") 312c5f01b2fSopenharmony_ci { 313c5f01b2fSopenharmony_ci CHECK(parser_helper("null") == json(nullptr)); 314c5f01b2fSopenharmony_ci } 315c5f01b2fSopenharmony_ci 316c5f01b2fSopenharmony_ci SECTION("true") 317c5f01b2fSopenharmony_ci { 318c5f01b2fSopenharmony_ci CHECK(parser_helper("true") == json(true)); 319c5f01b2fSopenharmony_ci } 320c5f01b2fSopenharmony_ci 321c5f01b2fSopenharmony_ci SECTION("false") 322c5f01b2fSopenharmony_ci { 323c5f01b2fSopenharmony_ci CHECK(parser_helper("false") == json(false)); 324c5f01b2fSopenharmony_ci } 325c5f01b2fSopenharmony_ci 326c5f01b2fSopenharmony_ci SECTION("array") 327c5f01b2fSopenharmony_ci { 328c5f01b2fSopenharmony_ci SECTION("empty array") 329c5f01b2fSopenharmony_ci { 330c5f01b2fSopenharmony_ci CHECK(parser_helper("[]") == json(json::value_t::array)); 331c5f01b2fSopenharmony_ci CHECK(parser_helper("[ ]") == json(json::value_t::array)); 332c5f01b2fSopenharmony_ci } 333c5f01b2fSopenharmony_ci 334c5f01b2fSopenharmony_ci SECTION("nonempty array") 335c5f01b2fSopenharmony_ci { 336c5f01b2fSopenharmony_ci CHECK(parser_helper("[true, false, null]") == json({true, false, nullptr})); 337c5f01b2fSopenharmony_ci } 338c5f01b2fSopenharmony_ci } 339c5f01b2fSopenharmony_ci 340c5f01b2fSopenharmony_ci SECTION("object") 341c5f01b2fSopenharmony_ci { 342c5f01b2fSopenharmony_ci SECTION("empty object") 343c5f01b2fSopenharmony_ci { 344c5f01b2fSopenharmony_ci CHECK(parser_helper("{}") == json(json::value_t::object)); 345c5f01b2fSopenharmony_ci CHECK(parser_helper("{ }") == json(json::value_t::object)); 346c5f01b2fSopenharmony_ci } 347c5f01b2fSopenharmony_ci 348c5f01b2fSopenharmony_ci SECTION("nonempty object") 349c5f01b2fSopenharmony_ci { 350c5f01b2fSopenharmony_ci CHECK(parser_helper("{\"\": true, \"one\": 1, \"two\": null}") == json({{"", true}, {"one", 1}, {"two", nullptr}})); 351c5f01b2fSopenharmony_ci } 352c5f01b2fSopenharmony_ci } 353c5f01b2fSopenharmony_ci 354c5f01b2fSopenharmony_ci SECTION("string") 355c5f01b2fSopenharmony_ci { 356c5f01b2fSopenharmony_ci // empty string 357c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\"") == json(json::value_t::string)); 358c5f01b2fSopenharmony_ci 359c5f01b2fSopenharmony_ci SECTION("errors") 360c5f01b2fSopenharmony_ci { 361c5f01b2fSopenharmony_ci // error: tab in string 362c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\t\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"<U+0009>'", json::parse_error&); 363c5f01b2fSopenharmony_ci // error: newline in string 364c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\n\""), "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"<U+000A>'", json::parse_error&); 365c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\r\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"<U+000D>'", json::parse_error&); 366c5f01b2fSopenharmony_ci // error: backspace in string 367c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"<U+0008>'", json::parse_error&); 368c5f01b2fSopenharmony_ci // improve code coverage 369c5f01b2fSopenharmony_ci CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&); 370c5f01b2fSopenharmony_ci CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&); 371c5f01b2fSopenharmony_ci // unescaped control characters 372c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&); // NOLINT(bugprone-string-literal-with-embedded-nul) 373c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0001 (SOH) must be escaped to \\u0001; last read: '\"<U+0001>'", json::parse_error&); 374c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0002 (STX) must be escaped to \\u0002; last read: '\"<U+0002>'", json::parse_error&); 375c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x03\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0003 (ETX) must be escaped to \\u0003; last read: '\"<U+0003>'", json::parse_error&); 376c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x04\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0004 (EOT) must be escaped to \\u0004; last read: '\"<U+0004>'", json::parse_error&); 377c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x05\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0005 (ENQ) must be escaped to \\u0005; last read: '\"<U+0005>'", json::parse_error&); 378c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x06\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0006 (ACK) must be escaped to \\u0006; last read: '\"<U+0006>'", json::parse_error&); 379c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x07\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0007 (BEL) must be escaped to \\u0007; last read: '\"<U+0007>'", json::parse_error&); 380c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x08\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"<U+0008>'", json::parse_error&); 381c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x09\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"<U+0009>'", json::parse_error&); 382c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x0a\""), "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"<U+000A>'", json::parse_error&); 383c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x0b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000B (VT) must be escaped to \\u000B; last read: '\"<U+000B>'", json::parse_error&); 384c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x0c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f; last read: '\"<U+000C>'", json::parse_error&); 385c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x0d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"<U+000D>'", json::parse_error&); 386c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x0e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000E (SO) must be escaped to \\u000E; last read: '\"<U+000E>'", json::parse_error&); 387c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x0f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000F (SI) must be escaped to \\u000F; last read: '\"<U+000F>'", json::parse_error&); 388c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x10\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0010 (DLE) must be escaped to \\u0010; last read: '\"<U+0010>'", json::parse_error&); 389c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x11\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0011 (DC1) must be escaped to \\u0011; last read: '\"<U+0011>'", json::parse_error&); 390c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x12\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0012 (DC2) must be escaped to \\u0012; last read: '\"<U+0012>'", json::parse_error&); 391c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x13\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0013 (DC3) must be escaped to \\u0013; last read: '\"<U+0013>'", json::parse_error&); 392c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x14\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0014 (DC4) must be escaped to \\u0014; last read: '\"<U+0014>'", json::parse_error&); 393c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x15\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0015 (NAK) must be escaped to \\u0015; last read: '\"<U+0015>'", json::parse_error&); 394c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x16\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0016 (SYN) must be escaped to \\u0016; last read: '\"<U+0016>'", json::parse_error&); 395c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x17\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0017 (ETB) must be escaped to \\u0017; last read: '\"<U+0017>'", json::parse_error&); 396c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x18\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0018 (CAN) must be escaped to \\u0018; last read: '\"<U+0018>'", json::parse_error&); 397c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x19\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0019 (EM) must be escaped to \\u0019; last read: '\"<U+0019>'", json::parse_error&); 398c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x1a\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001A (SUB) must be escaped to \\u001A; last read: '\"<U+001A>'", json::parse_error&); 399c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x1b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001B (ESC) must be escaped to \\u001B; last read: '\"<U+001B>'", json::parse_error&); 400c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x1c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001C (FS) must be escaped to \\u001C; last read: '\"<U+001C>'", json::parse_error&); 401c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x1d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001D (GS) must be escaped to \\u001D; last read: '\"<U+001D>'", json::parse_error&); 402c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x1e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001E (RS) must be escaped to \\u001E; last read: '\"<U+001E>'", json::parse_error&); 403c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\x1f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001F (US) must be escaped to \\u001F; last read: '\"<U+001F>'", json::parse_error&); 404c5f01b2fSopenharmony_ci 405c5f01b2fSopenharmony_ci SECTION("additional test for null byte") 406c5f01b2fSopenharmony_ci { 407c5f01b2fSopenharmony_ci // The test above for the null byte is wrong, because passing 408c5f01b2fSopenharmony_ci // a string to the parser only reads int until it encounters 409c5f01b2fSopenharmony_ci // a null byte. This test inserts the null byte later on and 410c5f01b2fSopenharmony_ci // uses an iterator range. 411c5f01b2fSopenharmony_ci std::string s = "\"1\""; 412c5f01b2fSopenharmony_ci s[1] = '\0'; 413c5f01b2fSopenharmony_ci json _; 414c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(_ = json::parse(s.begin(), s.end()), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0000 (NUL) must be escaped to \\u0000; last read: '\"<U+0000>'", json::parse_error&); 415c5f01b2fSopenharmony_ci } 416c5f01b2fSopenharmony_ci } 417c5f01b2fSopenharmony_ci 418c5f01b2fSopenharmony_ci SECTION("escaped") 419c5f01b2fSopenharmony_ci { 420c5f01b2fSopenharmony_ci // quotation mark "\"" 421c5f01b2fSopenharmony_ci auto r1 = R"("\"")"_json; 422c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\\"\"") == r1); 423c5f01b2fSopenharmony_ci // reverse solidus "\\" 424c5f01b2fSopenharmony_ci auto r2 = R"("\\")"_json; 425c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\\\\"") == r2); 426c5f01b2fSopenharmony_ci // solidus 427c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\/\"") == R"("/")"_json); 428c5f01b2fSopenharmony_ci // backspace 429c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\b\"") == json("\b")); 430c5f01b2fSopenharmony_ci // formfeed 431c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\f\"") == json("\f")); 432c5f01b2fSopenharmony_ci // newline 433c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\n\"") == json("\n")); 434c5f01b2fSopenharmony_ci // carriage return 435c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\r\"") == json("\r")); 436c5f01b2fSopenharmony_ci // horizontal tab 437c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\t\"") == json("\t")); 438c5f01b2fSopenharmony_ci 439c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\u0001\"").get<json::string_t>() == "\x01"); 440c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\u000a\"").get<json::string_t>() == "\n"); 441c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\u00b0\"").get<json::string_t>() == "°"); 442c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\u0c00\"").get<json::string_t>() == "ఀ"); 443c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\ud000\"").get<json::string_t>() == "퀀"); 444c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\u000E\"").get<json::string_t>() == "\x0E"); 445c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\u00F0\"").get<json::string_t>() == "ð"); 446c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\u0100\"").get<json::string_t>() == "Ā"); 447c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\u2000\"").get<json::string_t>() == " "); 448c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\uFFFF\"").get<json::string_t>() == ""); 449c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\u20AC\"").get<json::string_t>() == "€"); 450c5f01b2fSopenharmony_ci CHECK(parser_helper("\"€\"").get<json::string_t>() == "€"); 451c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\"").get<json::string_t>() == ""); 452c5f01b2fSopenharmony_ci 453c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\ud80c\\udc60\"").get<json::string_t>() == "\xf0\x93\x81\xa0"); 454c5f01b2fSopenharmony_ci CHECK(parser_helper("\"\\ud83c\\udf1e\"").get<json::string_t>() == ""); 455c5f01b2fSopenharmony_ci } 456c5f01b2fSopenharmony_ci } 457c5f01b2fSopenharmony_ci 458c5f01b2fSopenharmony_ci SECTION("number") 459c5f01b2fSopenharmony_ci { 460c5f01b2fSopenharmony_ci SECTION("integers") 461c5f01b2fSopenharmony_ci { 462c5f01b2fSopenharmony_ci SECTION("without exponent") 463c5f01b2fSopenharmony_ci { 464c5f01b2fSopenharmony_ci CHECK(parser_helper("-128") == json(-128)); 465c5f01b2fSopenharmony_ci CHECK(parser_helper("-0") == json(-0)); 466c5f01b2fSopenharmony_ci CHECK(parser_helper("0") == json(0)); 467c5f01b2fSopenharmony_ci CHECK(parser_helper("128") == json(128)); 468c5f01b2fSopenharmony_ci } 469c5f01b2fSopenharmony_ci 470c5f01b2fSopenharmony_ci SECTION("with exponent") 471c5f01b2fSopenharmony_ci { 472c5f01b2fSopenharmony_ci CHECK(parser_helper("0e1") == json(0e1)); 473c5f01b2fSopenharmony_ci CHECK(parser_helper("0E1") == json(0e1)); 474c5f01b2fSopenharmony_ci 475c5f01b2fSopenharmony_ci CHECK(parser_helper("10000E-4") == json(10000e-4)); 476c5f01b2fSopenharmony_ci CHECK(parser_helper("10000E-3") == json(10000e-3)); 477c5f01b2fSopenharmony_ci CHECK(parser_helper("10000E-2") == json(10000e-2)); 478c5f01b2fSopenharmony_ci CHECK(parser_helper("10000E-1") == json(10000e-1)); 479c5f01b2fSopenharmony_ci CHECK(parser_helper("10000E0") == json(10000e0)); 480c5f01b2fSopenharmony_ci CHECK(parser_helper("10000E1") == json(10000e1)); 481c5f01b2fSopenharmony_ci CHECK(parser_helper("10000E2") == json(10000e2)); 482c5f01b2fSopenharmony_ci CHECK(parser_helper("10000E3") == json(10000e3)); 483c5f01b2fSopenharmony_ci CHECK(parser_helper("10000E4") == json(10000e4)); 484c5f01b2fSopenharmony_ci 485c5f01b2fSopenharmony_ci CHECK(parser_helper("10000e-4") == json(10000e-4)); 486c5f01b2fSopenharmony_ci CHECK(parser_helper("10000e-3") == json(10000e-3)); 487c5f01b2fSopenharmony_ci CHECK(parser_helper("10000e-2") == json(10000e-2)); 488c5f01b2fSopenharmony_ci CHECK(parser_helper("10000e-1") == json(10000e-1)); 489c5f01b2fSopenharmony_ci CHECK(parser_helper("10000e0") == json(10000e0)); 490c5f01b2fSopenharmony_ci CHECK(parser_helper("10000e1") == json(10000e1)); 491c5f01b2fSopenharmony_ci CHECK(parser_helper("10000e2") == json(10000e2)); 492c5f01b2fSopenharmony_ci CHECK(parser_helper("10000e3") == json(10000e3)); 493c5f01b2fSopenharmony_ci CHECK(parser_helper("10000e4") == json(10000e4)); 494c5f01b2fSopenharmony_ci 495c5f01b2fSopenharmony_ci CHECK(parser_helper("-0e1") == json(-0e1)); 496c5f01b2fSopenharmony_ci CHECK(parser_helper("-0E1") == json(-0e1)); 497c5f01b2fSopenharmony_ci CHECK(parser_helper("-0E123") == json(-0e123)); 498c5f01b2fSopenharmony_ci 499c5f01b2fSopenharmony_ci // numbers after exponent 500c5f01b2fSopenharmony_ci CHECK(parser_helper("10E0") == json(10e0)); 501c5f01b2fSopenharmony_ci CHECK(parser_helper("10E1") == json(10e1)); 502c5f01b2fSopenharmony_ci CHECK(parser_helper("10E2") == json(10e2)); 503c5f01b2fSopenharmony_ci CHECK(parser_helper("10E3") == json(10e3)); 504c5f01b2fSopenharmony_ci CHECK(parser_helper("10E4") == json(10e4)); 505c5f01b2fSopenharmony_ci CHECK(parser_helper("10E5") == json(10e5)); 506c5f01b2fSopenharmony_ci CHECK(parser_helper("10E6") == json(10e6)); 507c5f01b2fSopenharmony_ci CHECK(parser_helper("10E7") == json(10e7)); 508c5f01b2fSopenharmony_ci CHECK(parser_helper("10E8") == json(10e8)); 509c5f01b2fSopenharmony_ci CHECK(parser_helper("10E9") == json(10e9)); 510c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+0") == json(10e0)); 511c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+1") == json(10e1)); 512c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+2") == json(10e2)); 513c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+3") == json(10e3)); 514c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+4") == json(10e4)); 515c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+5") == json(10e5)); 516c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+6") == json(10e6)); 517c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+7") == json(10e7)); 518c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+8") == json(10e8)); 519c5f01b2fSopenharmony_ci CHECK(parser_helper("10E+9") == json(10e9)); 520c5f01b2fSopenharmony_ci CHECK(parser_helper("10E-1") == json(10e-1)); 521c5f01b2fSopenharmony_ci CHECK(parser_helper("10E-2") == json(10e-2)); 522c5f01b2fSopenharmony_ci CHECK(parser_helper("10E-3") == json(10e-3)); 523c5f01b2fSopenharmony_ci CHECK(parser_helper("10E-4") == json(10e-4)); 524c5f01b2fSopenharmony_ci CHECK(parser_helper("10E-5") == json(10e-5)); 525c5f01b2fSopenharmony_ci CHECK(parser_helper("10E-6") == json(10e-6)); 526c5f01b2fSopenharmony_ci CHECK(parser_helper("10E-7") == json(10e-7)); 527c5f01b2fSopenharmony_ci CHECK(parser_helper("10E-8") == json(10e-8)); 528c5f01b2fSopenharmony_ci CHECK(parser_helper("10E-9") == json(10e-9)); 529c5f01b2fSopenharmony_ci } 530c5f01b2fSopenharmony_ci 531c5f01b2fSopenharmony_ci SECTION("edge cases") 532c5f01b2fSopenharmony_ci { 533c5f01b2fSopenharmony_ci // From RFC8259, Section 6: 534c5f01b2fSopenharmony_ci // Note that when such software is used, numbers that are 535c5f01b2fSopenharmony_ci // integers and are in the range [-(2**53)+1, (2**53)-1] 536c5f01b2fSopenharmony_ci // are interoperable in the sense that implementations will 537c5f01b2fSopenharmony_ci // agree exactly on their numeric values. 538c5f01b2fSopenharmony_ci 539c5f01b2fSopenharmony_ci // -(2**53)+1 540c5f01b2fSopenharmony_ci CHECK(parser_helper("-9007199254740991").get<int64_t>() == -9007199254740991); 541c5f01b2fSopenharmony_ci // (2**53)-1 542c5f01b2fSopenharmony_ci CHECK(parser_helper("9007199254740991").get<int64_t>() == 9007199254740991); 543c5f01b2fSopenharmony_ci } 544c5f01b2fSopenharmony_ci 545c5f01b2fSopenharmony_ci SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers) 546c5f01b2fSopenharmony_ci { 547c5f01b2fSopenharmony_ci // While RFC8259, Section 6 specifies a preference for support 548c5f01b2fSopenharmony_ci // for ranges in range of IEEE 754-2008 binary64 (double precision) 549c5f01b2fSopenharmony_ci // this does not accommodate 64 bit integers without loss of accuracy. 550c5f01b2fSopenharmony_ci // As 64 bit integers are now widely used in software, it is desirable 551c5f01b2fSopenharmony_ci // to expand support to to the full 64 bit (signed and unsigned) range 552c5f01b2fSopenharmony_ci // i.e. -(2**63) -> (2**64)-1. 553c5f01b2fSopenharmony_ci 554c5f01b2fSopenharmony_ci // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) 555c5f01b2fSopenharmony_ci CHECK(parser_helper("-9223372036854775808").get<int64_t>() == -9223372036854775807 - 1); 556c5f01b2fSopenharmony_ci // (2**63)-1 557c5f01b2fSopenharmony_ci CHECK(parser_helper("9223372036854775807").get<int64_t>() == 9223372036854775807); 558c5f01b2fSopenharmony_ci // (2**64)-1 559c5f01b2fSopenharmony_ci CHECK(parser_helper("18446744073709551615").get<uint64_t>() == 18446744073709551615u); 560c5f01b2fSopenharmony_ci } 561c5f01b2fSopenharmony_ci } 562c5f01b2fSopenharmony_ci 563c5f01b2fSopenharmony_ci SECTION("floating-point") 564c5f01b2fSopenharmony_ci { 565c5f01b2fSopenharmony_ci SECTION("without exponent") 566c5f01b2fSopenharmony_ci { 567c5f01b2fSopenharmony_ci CHECK(parser_helper("-128.5") == json(-128.5)); 568c5f01b2fSopenharmony_ci CHECK(parser_helper("0.999") == json(0.999)); 569c5f01b2fSopenharmony_ci CHECK(parser_helper("128.5") == json(128.5)); 570c5f01b2fSopenharmony_ci CHECK(parser_helper("-0.0") == json(-0.0)); 571c5f01b2fSopenharmony_ci } 572c5f01b2fSopenharmony_ci 573c5f01b2fSopenharmony_ci SECTION("with exponent") 574c5f01b2fSopenharmony_ci { 575c5f01b2fSopenharmony_ci CHECK(parser_helper("-128.5E3") == json(-128.5E3)); 576c5f01b2fSopenharmony_ci CHECK(parser_helper("-128.5E-3") == json(-128.5E-3)); 577c5f01b2fSopenharmony_ci CHECK(parser_helper("-0.0e1") == json(-0.0e1)); 578c5f01b2fSopenharmony_ci CHECK(parser_helper("-0.0E1") == json(-0.0e1)); 579c5f01b2fSopenharmony_ci } 580c5f01b2fSopenharmony_ci } 581c5f01b2fSopenharmony_ci 582c5f01b2fSopenharmony_ci SECTION("overflow") 583c5f01b2fSopenharmony_ci { 584c5f01b2fSopenharmony_ci // overflows during parsing yield an exception 585c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1.18973e+4932").empty(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&); 586c5f01b2fSopenharmony_ci } 587c5f01b2fSopenharmony_ci 588c5f01b2fSopenharmony_ci SECTION("invalid numbers") 589c5f01b2fSopenharmony_ci { 590c5f01b2fSopenharmony_ci // numbers must not begin with "+" 591c5f01b2fSopenharmony_ci CHECK_THROWS_AS(parser_helper("+1"), json::parse_error&); 592c5f01b2fSopenharmony_ci CHECK_THROWS_AS(parser_helper("+0"), json::parse_error&); 593c5f01b2fSopenharmony_ci 594c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("01"), 595c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&); 596c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-01"), 597c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&); 598c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("--1"), 599c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&); 600c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1."), 601c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.'", json::parse_error&); 602c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1E"), 603c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E'", json::parse_error&); 604c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1E-"), 605c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '1E-'", json::parse_error&); 606c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1.E1"), 607c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.E'", json::parse_error&); 608c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-1E"), 609c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-1E'", json::parse_error&); 610c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0E#"), 611c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-0E#'", json::parse_error&); 612c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0E-#"), 613c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0E-#'", json::parse_error&); 614c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0#"), 615c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: '-0#'; expected end of input", json::parse_error&); 616c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0.0:"), 617c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&); 618c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0.0Z"), 619c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: '-0.0Z'; expected end of input", json::parse_error&); 620c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0E123:"), 621c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&); 622c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0e0-:"), 623c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'; expected end of input", json::parse_error&); 624c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0e-:"), 625c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0e-:'", json::parse_error&); 626c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0f"), 627c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '-0f'; expected end of input", json::parse_error&); 628c5f01b2fSopenharmony_ci } 629c5f01b2fSopenharmony_ci } 630c5f01b2fSopenharmony_ci } 631c5f01b2fSopenharmony_ci 632c5f01b2fSopenharmony_ci SECTION("accept") 633c5f01b2fSopenharmony_ci { 634c5f01b2fSopenharmony_ci SECTION("null") 635c5f01b2fSopenharmony_ci { 636c5f01b2fSopenharmony_ci CHECK(accept_helper("null")); 637c5f01b2fSopenharmony_ci } 638c5f01b2fSopenharmony_ci 639c5f01b2fSopenharmony_ci SECTION("true") 640c5f01b2fSopenharmony_ci { 641c5f01b2fSopenharmony_ci CHECK(accept_helper("true")); 642c5f01b2fSopenharmony_ci } 643c5f01b2fSopenharmony_ci 644c5f01b2fSopenharmony_ci SECTION("false") 645c5f01b2fSopenharmony_ci { 646c5f01b2fSopenharmony_ci CHECK(accept_helper("false")); 647c5f01b2fSopenharmony_ci } 648c5f01b2fSopenharmony_ci 649c5f01b2fSopenharmony_ci SECTION("array") 650c5f01b2fSopenharmony_ci { 651c5f01b2fSopenharmony_ci SECTION("empty array") 652c5f01b2fSopenharmony_ci { 653c5f01b2fSopenharmony_ci CHECK(accept_helper("[]")); 654c5f01b2fSopenharmony_ci CHECK(accept_helper("[ ]")); 655c5f01b2fSopenharmony_ci } 656c5f01b2fSopenharmony_ci 657c5f01b2fSopenharmony_ci SECTION("nonempty array") 658c5f01b2fSopenharmony_ci { 659c5f01b2fSopenharmony_ci CHECK(accept_helper("[true, false, null]")); 660c5f01b2fSopenharmony_ci } 661c5f01b2fSopenharmony_ci } 662c5f01b2fSopenharmony_ci 663c5f01b2fSopenharmony_ci SECTION("object") 664c5f01b2fSopenharmony_ci { 665c5f01b2fSopenharmony_ci SECTION("empty object") 666c5f01b2fSopenharmony_ci { 667c5f01b2fSopenharmony_ci CHECK(accept_helper("{}")); 668c5f01b2fSopenharmony_ci CHECK(accept_helper("{ }")); 669c5f01b2fSopenharmony_ci } 670c5f01b2fSopenharmony_ci 671c5f01b2fSopenharmony_ci SECTION("nonempty object") 672c5f01b2fSopenharmony_ci { 673c5f01b2fSopenharmony_ci CHECK(accept_helper("{\"\": true, \"one\": 1, \"two\": null}")); 674c5f01b2fSopenharmony_ci } 675c5f01b2fSopenharmony_ci } 676c5f01b2fSopenharmony_ci 677c5f01b2fSopenharmony_ci SECTION("string") 678c5f01b2fSopenharmony_ci { 679c5f01b2fSopenharmony_ci // empty string 680c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\"")); 681c5f01b2fSopenharmony_ci 682c5f01b2fSopenharmony_ci SECTION("errors") 683c5f01b2fSopenharmony_ci { 684c5f01b2fSopenharmony_ci // error: tab in string 685c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\t\"") == false); 686c5f01b2fSopenharmony_ci // error: newline in string 687c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\n\"") == false); 688c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\r\"") == false); 689c5f01b2fSopenharmony_ci // error: backspace in string 690c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\b\"") == false); 691c5f01b2fSopenharmony_ci // improve code coverage 692c5f01b2fSopenharmony_ci CHECK(accept_helper("\uFF01") == false); 693c5f01b2fSopenharmony_ci CHECK(accept_helper("[-4:1,]") == false); 694c5f01b2fSopenharmony_ci // unescaped control characters 695c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x00\"") == false); // NOLINT(bugprone-string-literal-with-embedded-nul) 696c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x01\"") == false); 697c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x02\"") == false); 698c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x03\"") == false); 699c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x04\"") == false); 700c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x05\"") == false); 701c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x06\"") == false); 702c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x07\"") == false); 703c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x08\"") == false); 704c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x09\"") == false); 705c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x0a\"") == false); 706c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x0b\"") == false); 707c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x0c\"") == false); 708c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x0d\"") == false); 709c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x0e\"") == false); 710c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x0f\"") == false); 711c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x10\"") == false); 712c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x11\"") == false); 713c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x12\"") == false); 714c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x13\"") == false); 715c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x14\"") == false); 716c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x15\"") == false); 717c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x16\"") == false); 718c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x17\"") == false); 719c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x18\"") == false); 720c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x19\"") == false); 721c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x1a\"") == false); 722c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x1b\"") == false); 723c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x1c\"") == false); 724c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x1d\"") == false); 725c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x1e\"") == false); 726c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\x1f\"") == false); 727c5f01b2fSopenharmony_ci } 728c5f01b2fSopenharmony_ci 729c5f01b2fSopenharmony_ci SECTION("escaped") 730c5f01b2fSopenharmony_ci { 731c5f01b2fSopenharmony_ci // quotation mark "\"" 732c5f01b2fSopenharmony_ci auto r1 = R"("\"")"_json; 733c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\\"\"")); 734c5f01b2fSopenharmony_ci // reverse solidus "\\" 735c5f01b2fSopenharmony_ci auto r2 = R"("\\")"_json; 736c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\\\\"")); 737c5f01b2fSopenharmony_ci // solidus 738c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\/\"")); 739c5f01b2fSopenharmony_ci // backspace 740c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\b\"")); 741c5f01b2fSopenharmony_ci // formfeed 742c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\f\"")); 743c5f01b2fSopenharmony_ci // newline 744c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\n\"")); 745c5f01b2fSopenharmony_ci // carriage return 746c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\r\"")); 747c5f01b2fSopenharmony_ci // horizontal tab 748c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\t\"")); 749c5f01b2fSopenharmony_ci 750c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u0001\"")); 751c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u000a\"")); 752c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u00b0\"")); 753c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u0c00\"")); 754c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\ud000\"")); 755c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u000E\"")); 756c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u00F0\"")); 757c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u0100\"")); 758c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u2000\"")); 759c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\uFFFF\"")); 760c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u20AC\"")); 761c5f01b2fSopenharmony_ci CHECK(accept_helper("\"€\"")); 762c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\"")); 763c5f01b2fSopenharmony_ci 764c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\ud80c\\udc60\"")); 765c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\ud83c\\udf1e\"")); 766c5f01b2fSopenharmony_ci } 767c5f01b2fSopenharmony_ci } 768c5f01b2fSopenharmony_ci 769c5f01b2fSopenharmony_ci SECTION("number") 770c5f01b2fSopenharmony_ci { 771c5f01b2fSopenharmony_ci SECTION("integers") 772c5f01b2fSopenharmony_ci { 773c5f01b2fSopenharmony_ci SECTION("without exponent") 774c5f01b2fSopenharmony_ci { 775c5f01b2fSopenharmony_ci CHECK(accept_helper("-128")); 776c5f01b2fSopenharmony_ci CHECK(accept_helper("-0")); 777c5f01b2fSopenharmony_ci CHECK(accept_helper("0")); 778c5f01b2fSopenharmony_ci CHECK(accept_helper("128")); 779c5f01b2fSopenharmony_ci } 780c5f01b2fSopenharmony_ci 781c5f01b2fSopenharmony_ci SECTION("with exponent") 782c5f01b2fSopenharmony_ci { 783c5f01b2fSopenharmony_ci CHECK(accept_helper("0e1")); 784c5f01b2fSopenharmony_ci CHECK(accept_helper("0E1")); 785c5f01b2fSopenharmony_ci 786c5f01b2fSopenharmony_ci CHECK(accept_helper("10000E-4")); 787c5f01b2fSopenharmony_ci CHECK(accept_helper("10000E-3")); 788c5f01b2fSopenharmony_ci CHECK(accept_helper("10000E-2")); 789c5f01b2fSopenharmony_ci CHECK(accept_helper("10000E-1")); 790c5f01b2fSopenharmony_ci CHECK(accept_helper("10000E0")); 791c5f01b2fSopenharmony_ci CHECK(accept_helper("10000E1")); 792c5f01b2fSopenharmony_ci CHECK(accept_helper("10000E2")); 793c5f01b2fSopenharmony_ci CHECK(accept_helper("10000E3")); 794c5f01b2fSopenharmony_ci CHECK(accept_helper("10000E4")); 795c5f01b2fSopenharmony_ci 796c5f01b2fSopenharmony_ci CHECK(accept_helper("10000e-4")); 797c5f01b2fSopenharmony_ci CHECK(accept_helper("10000e-3")); 798c5f01b2fSopenharmony_ci CHECK(accept_helper("10000e-2")); 799c5f01b2fSopenharmony_ci CHECK(accept_helper("10000e-1")); 800c5f01b2fSopenharmony_ci CHECK(accept_helper("10000e0")); 801c5f01b2fSopenharmony_ci CHECK(accept_helper("10000e1")); 802c5f01b2fSopenharmony_ci CHECK(accept_helper("10000e2")); 803c5f01b2fSopenharmony_ci CHECK(accept_helper("10000e3")); 804c5f01b2fSopenharmony_ci CHECK(accept_helper("10000e4")); 805c5f01b2fSopenharmony_ci 806c5f01b2fSopenharmony_ci CHECK(accept_helper("-0e1")); 807c5f01b2fSopenharmony_ci CHECK(accept_helper("-0E1")); 808c5f01b2fSopenharmony_ci CHECK(accept_helper("-0E123")); 809c5f01b2fSopenharmony_ci } 810c5f01b2fSopenharmony_ci 811c5f01b2fSopenharmony_ci SECTION("edge cases") 812c5f01b2fSopenharmony_ci { 813c5f01b2fSopenharmony_ci // From RFC8259, Section 6: 814c5f01b2fSopenharmony_ci // Note that when such software is used, numbers that are 815c5f01b2fSopenharmony_ci // integers and are in the range [-(2**53)+1, (2**53)-1] 816c5f01b2fSopenharmony_ci // are interoperable in the sense that implementations will 817c5f01b2fSopenharmony_ci // agree exactly on their numeric values. 818c5f01b2fSopenharmony_ci 819c5f01b2fSopenharmony_ci // -(2**53)+1 820c5f01b2fSopenharmony_ci CHECK(accept_helper("-9007199254740991")); 821c5f01b2fSopenharmony_ci // (2**53)-1 822c5f01b2fSopenharmony_ci CHECK(accept_helper("9007199254740991")); 823c5f01b2fSopenharmony_ci } 824c5f01b2fSopenharmony_ci 825c5f01b2fSopenharmony_ci SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers) 826c5f01b2fSopenharmony_ci { 827c5f01b2fSopenharmony_ci // While RFC8259, Section 6 specifies a preference for support 828c5f01b2fSopenharmony_ci // for ranges in range of IEEE 754-2008 binary64 (double precision) 829c5f01b2fSopenharmony_ci // this does not accommodate 64 bit integers without loss of accuracy. 830c5f01b2fSopenharmony_ci // As 64 bit integers are now widely used in software, it is desirable 831c5f01b2fSopenharmony_ci // to expand support to to the full 64 bit (signed and unsigned) range 832c5f01b2fSopenharmony_ci // i.e. -(2**63) -> (2**64)-1. 833c5f01b2fSopenharmony_ci 834c5f01b2fSopenharmony_ci // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) 835c5f01b2fSopenharmony_ci CHECK(accept_helper("-9223372036854775808")); 836c5f01b2fSopenharmony_ci // (2**63)-1 837c5f01b2fSopenharmony_ci CHECK(accept_helper("9223372036854775807")); 838c5f01b2fSopenharmony_ci // (2**64)-1 839c5f01b2fSopenharmony_ci CHECK(accept_helper("18446744073709551615")); 840c5f01b2fSopenharmony_ci } 841c5f01b2fSopenharmony_ci } 842c5f01b2fSopenharmony_ci 843c5f01b2fSopenharmony_ci SECTION("floating-point") 844c5f01b2fSopenharmony_ci { 845c5f01b2fSopenharmony_ci SECTION("without exponent") 846c5f01b2fSopenharmony_ci { 847c5f01b2fSopenharmony_ci CHECK(accept_helper("-128.5")); 848c5f01b2fSopenharmony_ci CHECK(accept_helper("0.999")); 849c5f01b2fSopenharmony_ci CHECK(accept_helper("128.5")); 850c5f01b2fSopenharmony_ci CHECK(accept_helper("-0.0")); 851c5f01b2fSopenharmony_ci } 852c5f01b2fSopenharmony_ci 853c5f01b2fSopenharmony_ci SECTION("with exponent") 854c5f01b2fSopenharmony_ci { 855c5f01b2fSopenharmony_ci CHECK(accept_helper("-128.5E3")); 856c5f01b2fSopenharmony_ci CHECK(accept_helper("-128.5E-3")); 857c5f01b2fSopenharmony_ci CHECK(accept_helper("-0.0e1")); 858c5f01b2fSopenharmony_ci CHECK(accept_helper("-0.0E1")); 859c5f01b2fSopenharmony_ci } 860c5f01b2fSopenharmony_ci } 861c5f01b2fSopenharmony_ci 862c5f01b2fSopenharmony_ci SECTION("overflow") 863c5f01b2fSopenharmony_ci { 864c5f01b2fSopenharmony_ci // overflows during parsing 865c5f01b2fSopenharmony_ci CHECK(!accept_helper("1.18973e+4932")); 866c5f01b2fSopenharmony_ci } 867c5f01b2fSopenharmony_ci 868c5f01b2fSopenharmony_ci SECTION("invalid numbers") 869c5f01b2fSopenharmony_ci { 870c5f01b2fSopenharmony_ci CHECK(accept_helper("01") == false); 871c5f01b2fSopenharmony_ci CHECK(accept_helper("--1") == false); 872c5f01b2fSopenharmony_ci CHECK(accept_helper("1.") == false); 873c5f01b2fSopenharmony_ci CHECK(accept_helper("1E") == false); 874c5f01b2fSopenharmony_ci CHECK(accept_helper("1E-") == false); 875c5f01b2fSopenharmony_ci CHECK(accept_helper("1.E1") == false); 876c5f01b2fSopenharmony_ci CHECK(accept_helper("-1E") == false); 877c5f01b2fSopenharmony_ci CHECK(accept_helper("-0E#") == false); 878c5f01b2fSopenharmony_ci CHECK(accept_helper("-0E-#") == false); 879c5f01b2fSopenharmony_ci CHECK(accept_helper("-0#") == false); 880c5f01b2fSopenharmony_ci CHECK(accept_helper("-0.0:") == false); 881c5f01b2fSopenharmony_ci CHECK(accept_helper("-0.0Z") == false); 882c5f01b2fSopenharmony_ci CHECK(accept_helper("-0E123:") == false); 883c5f01b2fSopenharmony_ci CHECK(accept_helper("-0e0-:") == false); 884c5f01b2fSopenharmony_ci CHECK(accept_helper("-0e-:") == false); 885c5f01b2fSopenharmony_ci CHECK(accept_helper("-0f") == false); 886c5f01b2fSopenharmony_ci 887c5f01b2fSopenharmony_ci // numbers must not begin with "+" 888c5f01b2fSopenharmony_ci CHECK(accept_helper("+1") == false); 889c5f01b2fSopenharmony_ci CHECK(accept_helper("+0") == false); 890c5f01b2fSopenharmony_ci } 891c5f01b2fSopenharmony_ci } 892c5f01b2fSopenharmony_ci } 893c5f01b2fSopenharmony_ci 894c5f01b2fSopenharmony_ci SECTION("parse errors") 895c5f01b2fSopenharmony_ci { 896c5f01b2fSopenharmony_ci // unexpected end of number 897c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("0."), 898c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.'", json::parse_error&); 899c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-"), 900c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-'", json::parse_error&); 901c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("--"), 902c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&); 903c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-0."), 904c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after '.'; last read: '-0.'", json::parse_error&); 905c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-."), 906c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-.'", json::parse_error&); 907c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("-:"), 908c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'", json::parse_error&); 909c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("0.:"), 910c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.:'", json::parse_error&); 911c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("e."), 912c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'e'", json::parse_error&); 913c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1e."), 914c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e.'", json::parse_error&); 915c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1e/"), 916c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e/'", json::parse_error&); 917c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1e:"), 918c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e:'", json::parse_error&); 919c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1E."), 920c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E.'", json::parse_error&); 921c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1E/"), 922c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E/'", json::parse_error&); 923c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("1E:"), 924c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'", json::parse_error&); 925c5f01b2fSopenharmony_ci 926c5f01b2fSopenharmony_ci // unexpected end of null 927c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("n"), 928c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'n'", json::parse_error&); 929c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("nu"), 930c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'nu'", json::parse_error&); 931c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("nul"), 932c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nul'", json::parse_error&); 933c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("nulk"), 934c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulk'", json::parse_error&); 935c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("nulm"), 936c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulm'", json::parse_error&); 937c5f01b2fSopenharmony_ci 938c5f01b2fSopenharmony_ci // unexpected end of true 939c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("t"), 940c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 't'", json::parse_error&); 941c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("tr"), 942c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'tr'", json::parse_error&); 943c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("tru"), 944c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'tru'", json::parse_error&); 945c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("trud"), 946c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'trud'", json::parse_error&); 947c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("truf"), 948c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'truf'", json::parse_error&); 949c5f01b2fSopenharmony_ci 950c5f01b2fSopenharmony_ci // unexpected end of false 951c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("f"), 952c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'f'", json::parse_error&); 953c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("fa"), 954c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'fa'", json::parse_error&); 955c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("fal"), 956c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'fal'", json::parse_error&); 957c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("fals"), 958c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'fals'", json::parse_error&); 959c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("falsd"), 960c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsd'", json::parse_error&); 961c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("falsf"), 962c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsf'", json::parse_error&); 963c5f01b2fSopenharmony_ci 964c5f01b2fSopenharmony_ci // missing/unexpected end of array 965c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("["), 966c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); 967c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("[1"), 968c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&); 969c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("[1,"), 970c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); 971c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("[1,]"), 972c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&); 973c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("]"), 974c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&); 975c5f01b2fSopenharmony_ci 976c5f01b2fSopenharmony_ci // missing/unexpected end of object 977c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("{"), 978c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected end of input; expected string literal", json::parse_error&); 979c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("{\"foo\""), 980c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing object separator - unexpected end of input; expected ':'", json::parse_error&); 981c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":"), 982c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); 983c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":}"), 984c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&); 985c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":1,}"), 986c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 10: syntax error while parsing object key - unexpected '}'; expected string literal", json::parse_error&); 987c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("}"), 988c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&); 989c5f01b2fSopenharmony_ci 990c5f01b2fSopenharmony_ci // missing/unexpected end of string 991c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\""), 992c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&); 993c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\\\""), 994c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: missing closing quote; last read: '\"\\\"'", json::parse_error&); 995c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\\u\""), 996c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u\"'", json::parse_error&); 997c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\\u0\""), 998c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0\"'", json::parse_error&); 999c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\\u01\""), 1000c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01\"'", json::parse_error&); 1001c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\\u012\""), 1002c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012\"'", json::parse_error&); 1003c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\\u"), 1004c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u'", json::parse_error&); 1005c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\\u0"), 1006c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0'", json::parse_error&); 1007c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\\u01"), 1008c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01'", json::parse_error&); 1009c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("\"\\u012"), 1010c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012'", json::parse_error&); 1011c5f01b2fSopenharmony_ci 1012c5f01b2fSopenharmony_ci // invalid escapes 1013c5f01b2fSopenharmony_ci for (int c = 1; c < 128; ++c) 1014c5f01b2fSopenharmony_ci { 1015c5f01b2fSopenharmony_ci auto s = std::string("\"\\") + std::string(1, static_cast<char>(c)) + "\""; 1016c5f01b2fSopenharmony_ci 1017c5f01b2fSopenharmony_ci switch (c) 1018c5f01b2fSopenharmony_ci { 1019c5f01b2fSopenharmony_ci // valid escapes 1020c5f01b2fSopenharmony_ci case ('"'): 1021c5f01b2fSopenharmony_ci case ('\\'): 1022c5f01b2fSopenharmony_ci case ('/'): 1023c5f01b2fSopenharmony_ci case ('b'): 1024c5f01b2fSopenharmony_ci case ('f'): 1025c5f01b2fSopenharmony_ci case ('n'): 1026c5f01b2fSopenharmony_ci case ('r'): 1027c5f01b2fSopenharmony_ci case ('t'): 1028c5f01b2fSopenharmony_ci { 1029c5f01b2fSopenharmony_ci CHECK_NOTHROW(parser_helper(s)); 1030c5f01b2fSopenharmony_ci break; 1031c5f01b2fSopenharmony_ci } 1032c5f01b2fSopenharmony_ci 1033c5f01b2fSopenharmony_ci // \u must be followed with four numbers, so we skip it here 1034c5f01b2fSopenharmony_ci case ('u'): 1035c5f01b2fSopenharmony_ci { 1036c5f01b2fSopenharmony_ci break; 1037c5f01b2fSopenharmony_ci } 1038c5f01b2fSopenharmony_ci 1039c5f01b2fSopenharmony_ci // any other combination of backslash and character is invalid 1040c5f01b2fSopenharmony_ci default: 1041c5f01b2fSopenharmony_ci { 1042c5f01b2fSopenharmony_ci CHECK_THROWS_AS(parser_helper(s), json::parse_error&); 1043c5f01b2fSopenharmony_ci // only check error message if c is not a control character 1044c5f01b2fSopenharmony_ci if (c > 0x1f) 1045c5f01b2fSopenharmony_ci { 1046c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_STD_STR(parser_helper(s), 1047c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid string: forbidden character after backslash; last read: '\"\\" + std::string(1, static_cast<char>(c)) + "'"); 1048c5f01b2fSopenharmony_ci } 1049c5f01b2fSopenharmony_ci break; 1050c5f01b2fSopenharmony_ci } 1051c5f01b2fSopenharmony_ci } 1052c5f01b2fSopenharmony_ci } 1053c5f01b2fSopenharmony_ci 1054c5f01b2fSopenharmony_ci // invalid \uxxxx escapes 1055c5f01b2fSopenharmony_ci { 1056c5f01b2fSopenharmony_ci // check whether character is a valid hex character 1057c5f01b2fSopenharmony_ci const auto valid = [](int c) 1058c5f01b2fSopenharmony_ci { 1059c5f01b2fSopenharmony_ci switch (c) 1060c5f01b2fSopenharmony_ci { 1061c5f01b2fSopenharmony_ci case ('0'): 1062c5f01b2fSopenharmony_ci case ('1'): 1063c5f01b2fSopenharmony_ci case ('2'): 1064c5f01b2fSopenharmony_ci case ('3'): 1065c5f01b2fSopenharmony_ci case ('4'): 1066c5f01b2fSopenharmony_ci case ('5'): 1067c5f01b2fSopenharmony_ci case ('6'): 1068c5f01b2fSopenharmony_ci case ('7'): 1069c5f01b2fSopenharmony_ci case ('8'): 1070c5f01b2fSopenharmony_ci case ('9'): 1071c5f01b2fSopenharmony_ci case ('a'): 1072c5f01b2fSopenharmony_ci case ('b'): 1073c5f01b2fSopenharmony_ci case ('c'): 1074c5f01b2fSopenharmony_ci case ('d'): 1075c5f01b2fSopenharmony_ci case ('e'): 1076c5f01b2fSopenharmony_ci case ('f'): 1077c5f01b2fSopenharmony_ci case ('A'): 1078c5f01b2fSopenharmony_ci case ('B'): 1079c5f01b2fSopenharmony_ci case ('C'): 1080c5f01b2fSopenharmony_ci case ('D'): 1081c5f01b2fSopenharmony_ci case ('E'): 1082c5f01b2fSopenharmony_ci case ('F'): 1083c5f01b2fSopenharmony_ci { 1084c5f01b2fSopenharmony_ci return true; 1085c5f01b2fSopenharmony_ci } 1086c5f01b2fSopenharmony_ci 1087c5f01b2fSopenharmony_ci default: 1088c5f01b2fSopenharmony_ci { 1089c5f01b2fSopenharmony_ci return false; 1090c5f01b2fSopenharmony_ci } 1091c5f01b2fSopenharmony_ci } 1092c5f01b2fSopenharmony_ci }; 1093c5f01b2fSopenharmony_ci 1094c5f01b2fSopenharmony_ci for (int c = 1; c < 128; ++c) 1095c5f01b2fSopenharmony_ci { 1096c5f01b2fSopenharmony_ci std::string s = "\"\\u"; 1097c5f01b2fSopenharmony_ci 1098c5f01b2fSopenharmony_ci // create a string with the iterated character at each position 1099c5f01b2fSopenharmony_ci auto s1 = s + "000" + std::string(1, static_cast<char>(c)) + "\""; 1100c5f01b2fSopenharmony_ci auto s2 = s + "00" + std::string(1, static_cast<char>(c)) + "0\""; 1101c5f01b2fSopenharmony_ci auto s3 = s + "0" + std::string(1, static_cast<char>(c)) + "00\""; 1102c5f01b2fSopenharmony_ci auto s4 = s + std::string(1, static_cast<char>(c)) + "000\""; 1103c5f01b2fSopenharmony_ci 1104c5f01b2fSopenharmony_ci if (valid(c)) 1105c5f01b2fSopenharmony_ci { 1106c5f01b2fSopenharmony_ci CAPTURE(s1) 1107c5f01b2fSopenharmony_ci CHECK_NOTHROW(parser_helper(s1)); 1108c5f01b2fSopenharmony_ci CAPTURE(s2) 1109c5f01b2fSopenharmony_ci CHECK_NOTHROW(parser_helper(s2)); 1110c5f01b2fSopenharmony_ci CAPTURE(s3) 1111c5f01b2fSopenharmony_ci CHECK_NOTHROW(parser_helper(s3)); 1112c5f01b2fSopenharmony_ci CAPTURE(s4) 1113c5f01b2fSopenharmony_ci CHECK_NOTHROW(parser_helper(s4)); 1114c5f01b2fSopenharmony_ci } 1115c5f01b2fSopenharmony_ci else 1116c5f01b2fSopenharmony_ci { 1117c5f01b2fSopenharmony_ci CAPTURE(s1) 1118c5f01b2fSopenharmony_ci CHECK_THROWS_AS(parser_helper(s1), json::parse_error&); 1119c5f01b2fSopenharmony_ci // only check error message if c is not a control character 1120c5f01b2fSopenharmony_ci if (c > 0x1f) 1121c5f01b2fSopenharmony_ci { 1122c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_STD_STR(parser_helper(s1), 1123c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s1.substr(0, 7) + "'"); 1124c5f01b2fSopenharmony_ci } 1125c5f01b2fSopenharmony_ci 1126c5f01b2fSopenharmony_ci CAPTURE(s2) 1127c5f01b2fSopenharmony_ci CHECK_THROWS_AS(parser_helper(s2), json::parse_error&); 1128c5f01b2fSopenharmony_ci // only check error message if c is not a control character 1129c5f01b2fSopenharmony_ci if (c > 0x1f) 1130c5f01b2fSopenharmony_ci { 1131c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_STD_STR(parser_helper(s2), 1132c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s2.substr(0, 6) + "'"); 1133c5f01b2fSopenharmony_ci } 1134c5f01b2fSopenharmony_ci 1135c5f01b2fSopenharmony_ci CAPTURE(s3) 1136c5f01b2fSopenharmony_ci CHECK_THROWS_AS(parser_helper(s3), json::parse_error&); 1137c5f01b2fSopenharmony_ci // only check error message if c is not a control character 1138c5f01b2fSopenharmony_ci if (c > 0x1f) 1139c5f01b2fSopenharmony_ci { 1140c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_STD_STR(parser_helper(s3), 1141c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s3.substr(0, 5) + "'"); 1142c5f01b2fSopenharmony_ci } 1143c5f01b2fSopenharmony_ci 1144c5f01b2fSopenharmony_ci CAPTURE(s4) 1145c5f01b2fSopenharmony_ci CHECK_THROWS_AS(parser_helper(s4), json::parse_error&); 1146c5f01b2fSopenharmony_ci // only check error message if c is not a control character 1147c5f01b2fSopenharmony_ci if (c > 0x1f) 1148c5f01b2fSopenharmony_ci { 1149c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_STD_STR(parser_helper(s4), 1150c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s4.substr(0, 4) + "'"); 1151c5f01b2fSopenharmony_ci } 1152c5f01b2fSopenharmony_ci } 1153c5f01b2fSopenharmony_ci } 1154c5f01b2fSopenharmony_ci } 1155c5f01b2fSopenharmony_ci 1156c5f01b2fSopenharmony_ci json _; 1157c5f01b2fSopenharmony_ci 1158c5f01b2fSopenharmony_ci // missing part of a surrogate pair 1159c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\""), "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'", json::parse_error&); 1160c5f01b2fSopenharmony_ci // invalid surrogate pair 1161c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uD80C\""), 1162c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'", json::parse_error&); 1163c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\u0000\""), 1164c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\u0000'", json::parse_error&); 1165c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uFFFF\""), 1166c5f01b2fSopenharmony_ci "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uFFFF'", json::parse_error&); 1167c5f01b2fSopenharmony_ci } 1168c5f01b2fSopenharmony_ci 1169c5f01b2fSopenharmony_ci SECTION("parse errors (accept)") 1170c5f01b2fSopenharmony_ci { 1171c5f01b2fSopenharmony_ci // unexpected end of number 1172c5f01b2fSopenharmony_ci CHECK(accept_helper("0.") == false); 1173c5f01b2fSopenharmony_ci CHECK(accept_helper("-") == false); 1174c5f01b2fSopenharmony_ci CHECK(accept_helper("--") == false); 1175c5f01b2fSopenharmony_ci CHECK(accept_helper("-0.") == false); 1176c5f01b2fSopenharmony_ci CHECK(accept_helper("-.") == false); 1177c5f01b2fSopenharmony_ci CHECK(accept_helper("-:") == false); 1178c5f01b2fSopenharmony_ci CHECK(accept_helper("0.:") == false); 1179c5f01b2fSopenharmony_ci CHECK(accept_helper("e.") == false); 1180c5f01b2fSopenharmony_ci CHECK(accept_helper("1e.") == false); 1181c5f01b2fSopenharmony_ci CHECK(accept_helper("1e/") == false); 1182c5f01b2fSopenharmony_ci CHECK(accept_helper("1e:") == false); 1183c5f01b2fSopenharmony_ci CHECK(accept_helper("1E.") == false); 1184c5f01b2fSopenharmony_ci CHECK(accept_helper("1E/") == false); 1185c5f01b2fSopenharmony_ci CHECK(accept_helper("1E:") == false); 1186c5f01b2fSopenharmony_ci 1187c5f01b2fSopenharmony_ci // unexpected end of null 1188c5f01b2fSopenharmony_ci CHECK(accept_helper("n") == false); 1189c5f01b2fSopenharmony_ci CHECK(accept_helper("nu") == false); 1190c5f01b2fSopenharmony_ci CHECK(accept_helper("nul") == false); 1191c5f01b2fSopenharmony_ci 1192c5f01b2fSopenharmony_ci // unexpected end of true 1193c5f01b2fSopenharmony_ci CHECK(accept_helper("t") == false); 1194c5f01b2fSopenharmony_ci CHECK(accept_helper("tr") == false); 1195c5f01b2fSopenharmony_ci CHECK(accept_helper("tru") == false); 1196c5f01b2fSopenharmony_ci 1197c5f01b2fSopenharmony_ci // unexpected end of false 1198c5f01b2fSopenharmony_ci CHECK(accept_helper("f") == false); 1199c5f01b2fSopenharmony_ci CHECK(accept_helper("fa") == false); 1200c5f01b2fSopenharmony_ci CHECK(accept_helper("fal") == false); 1201c5f01b2fSopenharmony_ci CHECK(accept_helper("fals") == false); 1202c5f01b2fSopenharmony_ci 1203c5f01b2fSopenharmony_ci // missing/unexpected end of array 1204c5f01b2fSopenharmony_ci CHECK(accept_helper("[") == false); 1205c5f01b2fSopenharmony_ci CHECK(accept_helper("[1") == false); 1206c5f01b2fSopenharmony_ci CHECK(accept_helper("[1,") == false); 1207c5f01b2fSopenharmony_ci CHECK(accept_helper("[1,]") == false); 1208c5f01b2fSopenharmony_ci CHECK(accept_helper("]") == false); 1209c5f01b2fSopenharmony_ci 1210c5f01b2fSopenharmony_ci // missing/unexpected end of object 1211c5f01b2fSopenharmony_ci CHECK(accept_helper("{") == false); 1212c5f01b2fSopenharmony_ci CHECK(accept_helper("{\"foo\"") == false); 1213c5f01b2fSopenharmony_ci CHECK(accept_helper("{\"foo\":") == false); 1214c5f01b2fSopenharmony_ci CHECK(accept_helper("{\"foo\":}") == false); 1215c5f01b2fSopenharmony_ci CHECK(accept_helper("{\"foo\":1,}") == false); 1216c5f01b2fSopenharmony_ci CHECK(accept_helper("}") == false); 1217c5f01b2fSopenharmony_ci 1218c5f01b2fSopenharmony_ci // missing/unexpected end of string 1219c5f01b2fSopenharmony_ci CHECK(accept_helper("\"") == false); 1220c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\\"") == false); 1221c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u\"") == false); 1222c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u0\"") == false); 1223c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u01\"") == false); 1224c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u012\"") == false); 1225c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u") == false); 1226c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u0") == false); 1227c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u01") == false); 1228c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\u012") == false); 1229c5f01b2fSopenharmony_ci 1230c5f01b2fSopenharmony_ci // unget of newline 1231c5f01b2fSopenharmony_ci CHECK(parser_helper("\n123\n") == 123); 1232c5f01b2fSopenharmony_ci 1233c5f01b2fSopenharmony_ci // invalid escapes 1234c5f01b2fSopenharmony_ci for (int c = 1; c < 128; ++c) 1235c5f01b2fSopenharmony_ci { 1236c5f01b2fSopenharmony_ci auto s = std::string("\"\\") + std::string(1, static_cast<char>(c)) + "\""; 1237c5f01b2fSopenharmony_ci 1238c5f01b2fSopenharmony_ci switch (c) 1239c5f01b2fSopenharmony_ci { 1240c5f01b2fSopenharmony_ci // valid escapes 1241c5f01b2fSopenharmony_ci case ('"'): 1242c5f01b2fSopenharmony_ci case ('\\'): 1243c5f01b2fSopenharmony_ci case ('/'): 1244c5f01b2fSopenharmony_ci case ('b'): 1245c5f01b2fSopenharmony_ci case ('f'): 1246c5f01b2fSopenharmony_ci case ('n'): 1247c5f01b2fSopenharmony_ci case ('r'): 1248c5f01b2fSopenharmony_ci case ('t'): 1249c5f01b2fSopenharmony_ci { 1250c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept()); 1251c5f01b2fSopenharmony_ci break; 1252c5f01b2fSopenharmony_ci } 1253c5f01b2fSopenharmony_ci 1254c5f01b2fSopenharmony_ci // \u must be followed with four numbers, so we skip it here 1255c5f01b2fSopenharmony_ci case ('u'): 1256c5f01b2fSopenharmony_ci { 1257c5f01b2fSopenharmony_ci break; 1258c5f01b2fSopenharmony_ci } 1259c5f01b2fSopenharmony_ci 1260c5f01b2fSopenharmony_ci // any other combination of backslash and character is invalid 1261c5f01b2fSopenharmony_ci default: 1262c5f01b2fSopenharmony_ci { 1263c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept() == false); 1264c5f01b2fSopenharmony_ci break; 1265c5f01b2fSopenharmony_ci } 1266c5f01b2fSopenharmony_ci } 1267c5f01b2fSopenharmony_ci } 1268c5f01b2fSopenharmony_ci 1269c5f01b2fSopenharmony_ci // invalid \uxxxx escapes 1270c5f01b2fSopenharmony_ci { 1271c5f01b2fSopenharmony_ci // check whether character is a valid hex character 1272c5f01b2fSopenharmony_ci const auto valid = [](int c) 1273c5f01b2fSopenharmony_ci { 1274c5f01b2fSopenharmony_ci switch (c) 1275c5f01b2fSopenharmony_ci { 1276c5f01b2fSopenharmony_ci case ('0'): 1277c5f01b2fSopenharmony_ci case ('1'): 1278c5f01b2fSopenharmony_ci case ('2'): 1279c5f01b2fSopenharmony_ci case ('3'): 1280c5f01b2fSopenharmony_ci case ('4'): 1281c5f01b2fSopenharmony_ci case ('5'): 1282c5f01b2fSopenharmony_ci case ('6'): 1283c5f01b2fSopenharmony_ci case ('7'): 1284c5f01b2fSopenharmony_ci case ('8'): 1285c5f01b2fSopenharmony_ci case ('9'): 1286c5f01b2fSopenharmony_ci case ('a'): 1287c5f01b2fSopenharmony_ci case ('b'): 1288c5f01b2fSopenharmony_ci case ('c'): 1289c5f01b2fSopenharmony_ci case ('d'): 1290c5f01b2fSopenharmony_ci case ('e'): 1291c5f01b2fSopenharmony_ci case ('f'): 1292c5f01b2fSopenharmony_ci case ('A'): 1293c5f01b2fSopenharmony_ci case ('B'): 1294c5f01b2fSopenharmony_ci case ('C'): 1295c5f01b2fSopenharmony_ci case ('D'): 1296c5f01b2fSopenharmony_ci case ('E'): 1297c5f01b2fSopenharmony_ci case ('F'): 1298c5f01b2fSopenharmony_ci { 1299c5f01b2fSopenharmony_ci return true; 1300c5f01b2fSopenharmony_ci } 1301c5f01b2fSopenharmony_ci 1302c5f01b2fSopenharmony_ci default: 1303c5f01b2fSopenharmony_ci { 1304c5f01b2fSopenharmony_ci return false; 1305c5f01b2fSopenharmony_ci } 1306c5f01b2fSopenharmony_ci } 1307c5f01b2fSopenharmony_ci }; 1308c5f01b2fSopenharmony_ci 1309c5f01b2fSopenharmony_ci for (int c = 1; c < 128; ++c) 1310c5f01b2fSopenharmony_ci { 1311c5f01b2fSopenharmony_ci std::string s = "\"\\u"; 1312c5f01b2fSopenharmony_ci 1313c5f01b2fSopenharmony_ci // create a string with the iterated character at each position 1314c5f01b2fSopenharmony_ci const auto s1 = s + "000" + std::string(1, static_cast<char>(c)) + "\""; 1315c5f01b2fSopenharmony_ci const auto s2 = s + "00" + std::string(1, static_cast<char>(c)) + "0\""; 1316c5f01b2fSopenharmony_ci const auto s3 = s + "0" + std::string(1, static_cast<char>(c)) + "00\""; 1317c5f01b2fSopenharmony_ci const auto s4 = s + std::string(1, static_cast<char>(c)) + "000\""; 1318c5f01b2fSopenharmony_ci 1319c5f01b2fSopenharmony_ci if (valid(c)) 1320c5f01b2fSopenharmony_ci { 1321c5f01b2fSopenharmony_ci CAPTURE(s1) 1322c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s1)).accept()); 1323c5f01b2fSopenharmony_ci CAPTURE(s2) 1324c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s2)).accept()); 1325c5f01b2fSopenharmony_ci CAPTURE(s3) 1326c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s3)).accept()); 1327c5f01b2fSopenharmony_ci CAPTURE(s4) 1328c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s4)).accept()); 1329c5f01b2fSopenharmony_ci } 1330c5f01b2fSopenharmony_ci else 1331c5f01b2fSopenharmony_ci { 1332c5f01b2fSopenharmony_ci CAPTURE(s1) 1333c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s1)).accept() == false); 1334c5f01b2fSopenharmony_ci 1335c5f01b2fSopenharmony_ci CAPTURE(s2) 1336c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s2)).accept() == false); 1337c5f01b2fSopenharmony_ci 1338c5f01b2fSopenharmony_ci CAPTURE(s3) 1339c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s3)).accept() == false); 1340c5f01b2fSopenharmony_ci 1341c5f01b2fSopenharmony_ci CAPTURE(s4) 1342c5f01b2fSopenharmony_ci CHECK(json::parser(nlohmann::detail::input_adapter(s4)).accept() == false); 1343c5f01b2fSopenharmony_ci } 1344c5f01b2fSopenharmony_ci } 1345c5f01b2fSopenharmony_ci } 1346c5f01b2fSopenharmony_ci 1347c5f01b2fSopenharmony_ci // missing part of a surrogate pair 1348c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\uD80C\"") == false); 1349c5f01b2fSopenharmony_ci // invalid surrogate pair 1350c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\uD80C\\uD80C\"") == false); 1351c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\uD80C\\u0000\"") == false); 1352c5f01b2fSopenharmony_ci CHECK(accept_helper("\"\\uD80C\\uFFFF\"") == false); 1353c5f01b2fSopenharmony_ci } 1354c5f01b2fSopenharmony_ci 1355c5f01b2fSopenharmony_ci SECTION("tests found by mutate++") 1356c5f01b2fSopenharmony_ci { 1357c5f01b2fSopenharmony_ci // test case to make sure no comma precedes the first key 1358c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("{,\"key\": false}"), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected ','; expected string literal", json::parse_error&); 1359c5f01b2fSopenharmony_ci // test case to make sure an object is properly closed 1360c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(parser_helper("[{\"key\": false true]"), "[json.exception.parse_error.101] parse error at line 1, column 19: syntax error while parsing object - unexpected true literal; expected '}'", json::parse_error&); 1361c5f01b2fSopenharmony_ci 1362c5f01b2fSopenharmony_ci // test case to make sure the callback is properly evaluated after reading a key 1363c5f01b2fSopenharmony_ci { 1364c5f01b2fSopenharmony_ci json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) noexcept 1365c5f01b2fSopenharmony_ci { 1366c5f01b2fSopenharmony_ci return event != json::parse_event_t::key; 1367c5f01b2fSopenharmony_ci }; 1368c5f01b2fSopenharmony_ci 1369c5f01b2fSopenharmony_ci json x = json::parse("{\"key\": false}", cb); 1370c5f01b2fSopenharmony_ci CHECK(x == json::object()); 1371c5f01b2fSopenharmony_ci } 1372c5f01b2fSopenharmony_ci } 1373c5f01b2fSopenharmony_ci 1374c5f01b2fSopenharmony_ci SECTION("callback function") 1375c5f01b2fSopenharmony_ci { 1376c5f01b2fSopenharmony_ci const auto* s_object = R"( 1377c5f01b2fSopenharmony_ci { 1378c5f01b2fSopenharmony_ci "foo": 2, 1379c5f01b2fSopenharmony_ci "bar": { 1380c5f01b2fSopenharmony_ci "baz": 1 1381c5f01b2fSopenharmony_ci } 1382c5f01b2fSopenharmony_ci } 1383c5f01b2fSopenharmony_ci )"; 1384c5f01b2fSopenharmony_ci 1385c5f01b2fSopenharmony_ci const auto* s_array = R"( 1386c5f01b2fSopenharmony_ci [1,2,[3,4,5],4,5] 1387c5f01b2fSopenharmony_ci )"; 1388c5f01b2fSopenharmony_ci 1389c5f01b2fSopenharmony_ci const auto* structured_array = R"( 1390c5f01b2fSopenharmony_ci [ 1391c5f01b2fSopenharmony_ci 1, 1392c5f01b2fSopenharmony_ci { 1393c5f01b2fSopenharmony_ci "foo": "bar" 1394c5f01b2fSopenharmony_ci }, 1395c5f01b2fSopenharmony_ci { 1396c5f01b2fSopenharmony_ci "qux": "baz" 1397c5f01b2fSopenharmony_ci } 1398c5f01b2fSopenharmony_ci ] 1399c5f01b2fSopenharmony_ci )"; 1400c5f01b2fSopenharmony_ci 1401c5f01b2fSopenharmony_ci SECTION("filter nothing") 1402c5f01b2fSopenharmony_ci { 1403c5f01b2fSopenharmony_ci json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept 1404c5f01b2fSopenharmony_ci { 1405c5f01b2fSopenharmony_ci return true; 1406c5f01b2fSopenharmony_ci }); 1407c5f01b2fSopenharmony_ci 1408c5f01b2fSopenharmony_ci CHECK (j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}})); 1409c5f01b2fSopenharmony_ci 1410c5f01b2fSopenharmony_ci json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept 1411c5f01b2fSopenharmony_ci { 1412c5f01b2fSopenharmony_ci return true; 1413c5f01b2fSopenharmony_ci }); 1414c5f01b2fSopenharmony_ci 1415c5f01b2fSopenharmony_ci CHECK (j_array == json({1, 2, {3, 4, 5}, 4, 5})); 1416c5f01b2fSopenharmony_ci } 1417c5f01b2fSopenharmony_ci 1418c5f01b2fSopenharmony_ci SECTION("filter everything") 1419c5f01b2fSopenharmony_ci { 1420c5f01b2fSopenharmony_ci json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept 1421c5f01b2fSopenharmony_ci { 1422c5f01b2fSopenharmony_ci return false; 1423c5f01b2fSopenharmony_ci }); 1424c5f01b2fSopenharmony_ci 1425c5f01b2fSopenharmony_ci // the top-level object will be discarded, leaving a null 1426c5f01b2fSopenharmony_ci CHECK (j_object.is_null()); 1427c5f01b2fSopenharmony_ci 1428c5f01b2fSopenharmony_ci json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept 1429c5f01b2fSopenharmony_ci { 1430c5f01b2fSopenharmony_ci return false; 1431c5f01b2fSopenharmony_ci }); 1432c5f01b2fSopenharmony_ci 1433c5f01b2fSopenharmony_ci // the top-level array will be discarded, leaving a null 1434c5f01b2fSopenharmony_ci CHECK (j_array.is_null()); 1435c5f01b2fSopenharmony_ci } 1436c5f01b2fSopenharmony_ci 1437c5f01b2fSopenharmony_ci SECTION("filter specific element") 1438c5f01b2fSopenharmony_ci { 1439c5f01b2fSopenharmony_ci json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept 1440c5f01b2fSopenharmony_ci { 1441c5f01b2fSopenharmony_ci // filter all number(2) elements 1442c5f01b2fSopenharmony_ci return event != json::parse_event_t::value || j != json(2); 1443c5f01b2fSopenharmony_ci }); 1444c5f01b2fSopenharmony_ci 1445c5f01b2fSopenharmony_ci CHECK (j_object == json({{"bar", {{"baz", 1}}}})); 1446c5f01b2fSopenharmony_ci 1447c5f01b2fSopenharmony_ci json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept 1448c5f01b2fSopenharmony_ci { 1449c5f01b2fSopenharmony_ci return event != json::parse_event_t::value || j != json(2); 1450c5f01b2fSopenharmony_ci }); 1451c5f01b2fSopenharmony_ci 1452c5f01b2fSopenharmony_ci CHECK (j_array == json({1, {3, 4, 5}, 4, 5})); 1453c5f01b2fSopenharmony_ci } 1454c5f01b2fSopenharmony_ci 1455c5f01b2fSopenharmony_ci SECTION("filter object in array") 1456c5f01b2fSopenharmony_ci { 1457c5f01b2fSopenharmony_ci json j_filtered1 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json & parsed) 1458c5f01b2fSopenharmony_ci { 1459c5f01b2fSopenharmony_ci return !(e == json::parse_event_t::object_end && parsed.contains("foo")); 1460c5f01b2fSopenharmony_ci }); 1461c5f01b2fSopenharmony_ci 1462c5f01b2fSopenharmony_ci // the specified object will be discarded, and removed. 1463c5f01b2fSopenharmony_ci CHECK (j_filtered1.size() == 2); 1464c5f01b2fSopenharmony_ci CHECK (j_filtered1 == json({1, {{"qux", "baz"}}})); 1465c5f01b2fSopenharmony_ci 1466c5f01b2fSopenharmony_ci json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/) noexcept 1467c5f01b2fSopenharmony_ci { 1468c5f01b2fSopenharmony_ci return e != json::parse_event_t::object_end; 1469c5f01b2fSopenharmony_ci }); 1470c5f01b2fSopenharmony_ci 1471c5f01b2fSopenharmony_ci // removed all objects in array. 1472c5f01b2fSopenharmony_ci CHECK (j_filtered2.size() == 1); 1473c5f01b2fSopenharmony_ci CHECK (j_filtered2 == json({1})); 1474c5f01b2fSopenharmony_ci } 1475c5f01b2fSopenharmony_ci 1476c5f01b2fSopenharmony_ci SECTION("filter specific events") 1477c5f01b2fSopenharmony_ci { 1478c5f01b2fSopenharmony_ci SECTION("first closing event") 1479c5f01b2fSopenharmony_ci { 1480c5f01b2fSopenharmony_ci { 1481c5f01b2fSopenharmony_ci json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept 1482c5f01b2fSopenharmony_ci { 1483c5f01b2fSopenharmony_ci static bool first = true; 1484c5f01b2fSopenharmony_ci if (e == json::parse_event_t::object_end && first) 1485c5f01b2fSopenharmony_ci { 1486c5f01b2fSopenharmony_ci first = false; 1487c5f01b2fSopenharmony_ci return false; 1488c5f01b2fSopenharmony_ci } 1489c5f01b2fSopenharmony_ci 1490c5f01b2fSopenharmony_ci return true; 1491c5f01b2fSopenharmony_ci }); 1492c5f01b2fSopenharmony_ci 1493c5f01b2fSopenharmony_ci // the first completed object will be discarded 1494c5f01b2fSopenharmony_ci CHECK (j_object == json({{"foo", 2}})); 1495c5f01b2fSopenharmony_ci } 1496c5f01b2fSopenharmony_ci 1497c5f01b2fSopenharmony_ci { 1498c5f01b2fSopenharmony_ci json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept 1499c5f01b2fSopenharmony_ci { 1500c5f01b2fSopenharmony_ci static bool first = true; 1501c5f01b2fSopenharmony_ci if (e == json::parse_event_t::array_end && first) 1502c5f01b2fSopenharmony_ci { 1503c5f01b2fSopenharmony_ci first = false; 1504c5f01b2fSopenharmony_ci return false; 1505c5f01b2fSopenharmony_ci } 1506c5f01b2fSopenharmony_ci 1507c5f01b2fSopenharmony_ci return true; 1508c5f01b2fSopenharmony_ci }); 1509c5f01b2fSopenharmony_ci 1510c5f01b2fSopenharmony_ci // the first completed array will be discarded 1511c5f01b2fSopenharmony_ci CHECK (j_array == json({1, 2, 4, 5})); 1512c5f01b2fSopenharmony_ci } 1513c5f01b2fSopenharmony_ci } 1514c5f01b2fSopenharmony_ci } 1515c5f01b2fSopenharmony_ci 1516c5f01b2fSopenharmony_ci SECTION("special cases") 1517c5f01b2fSopenharmony_ci { 1518c5f01b2fSopenharmony_ci // the following test cases cover the situation in which an empty 1519c5f01b2fSopenharmony_ci // object and array is discarded only after the closing character 1520c5f01b2fSopenharmony_ci // has been read 1521c5f01b2fSopenharmony_ci 1522c5f01b2fSopenharmony_ci json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept 1523c5f01b2fSopenharmony_ci { 1524c5f01b2fSopenharmony_ci return e != json::parse_event_t::object_end; 1525c5f01b2fSopenharmony_ci }); 1526c5f01b2fSopenharmony_ci CHECK(j_empty_object == json()); 1527c5f01b2fSopenharmony_ci 1528c5f01b2fSopenharmony_ci json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept 1529c5f01b2fSopenharmony_ci { 1530c5f01b2fSopenharmony_ci return e != json::parse_event_t::array_end; 1531c5f01b2fSopenharmony_ci }); 1532c5f01b2fSopenharmony_ci CHECK(j_empty_array == json()); 1533c5f01b2fSopenharmony_ci } 1534c5f01b2fSopenharmony_ci } 1535c5f01b2fSopenharmony_ci 1536c5f01b2fSopenharmony_ci SECTION("constructing from contiguous containers") 1537c5f01b2fSopenharmony_ci { 1538c5f01b2fSopenharmony_ci SECTION("from std::vector") 1539c5f01b2fSopenharmony_ci { 1540c5f01b2fSopenharmony_ci std::vector<uint8_t> v = {'t', 'r', 'u', 'e'}; 1541c5f01b2fSopenharmony_ci json j; 1542c5f01b2fSopenharmony_ci json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1543c5f01b2fSopenharmony_ci CHECK(j == json(true)); 1544c5f01b2fSopenharmony_ci } 1545c5f01b2fSopenharmony_ci 1546c5f01b2fSopenharmony_ci SECTION("from std::array") 1547c5f01b2fSopenharmony_ci { 1548c5f01b2fSopenharmony_ci std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} }; 1549c5f01b2fSopenharmony_ci json j; 1550c5f01b2fSopenharmony_ci json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1551c5f01b2fSopenharmony_ci CHECK(j == json(true)); 1552c5f01b2fSopenharmony_ci } 1553c5f01b2fSopenharmony_ci 1554c5f01b2fSopenharmony_ci SECTION("from array") 1555c5f01b2fSopenharmony_ci { 1556c5f01b2fSopenharmony_ci uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 1557c5f01b2fSopenharmony_ci json j; 1558c5f01b2fSopenharmony_ci json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1559c5f01b2fSopenharmony_ci CHECK(j == json(true)); 1560c5f01b2fSopenharmony_ci } 1561c5f01b2fSopenharmony_ci 1562c5f01b2fSopenharmony_ci SECTION("from char literal") 1563c5f01b2fSopenharmony_ci { 1564c5f01b2fSopenharmony_ci CHECK(parser_helper("true") == json(true)); 1565c5f01b2fSopenharmony_ci } 1566c5f01b2fSopenharmony_ci 1567c5f01b2fSopenharmony_ci SECTION("from std::string") 1568c5f01b2fSopenharmony_ci { 1569c5f01b2fSopenharmony_ci std::string v = {'t', 'r', 'u', 'e'}; 1570c5f01b2fSopenharmony_ci json j; 1571c5f01b2fSopenharmony_ci json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1572c5f01b2fSopenharmony_ci CHECK(j == json(true)); 1573c5f01b2fSopenharmony_ci } 1574c5f01b2fSopenharmony_ci 1575c5f01b2fSopenharmony_ci SECTION("from std::initializer_list") 1576c5f01b2fSopenharmony_ci { 1577c5f01b2fSopenharmony_ci std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'}; 1578c5f01b2fSopenharmony_ci json j; 1579c5f01b2fSopenharmony_ci json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1580c5f01b2fSopenharmony_ci CHECK(j == json(true)); 1581c5f01b2fSopenharmony_ci } 1582c5f01b2fSopenharmony_ci 1583c5f01b2fSopenharmony_ci SECTION("from std::valarray") 1584c5f01b2fSopenharmony_ci { 1585c5f01b2fSopenharmony_ci std::valarray<uint8_t> v = {'t', 'r', 'u', 'e'}; 1586c5f01b2fSopenharmony_ci json j; 1587c5f01b2fSopenharmony_ci json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1588c5f01b2fSopenharmony_ci CHECK(j == json(true)); 1589c5f01b2fSopenharmony_ci } 1590c5f01b2fSopenharmony_ci } 1591c5f01b2fSopenharmony_ci 1592c5f01b2fSopenharmony_ci SECTION("improve test coverage") 1593c5f01b2fSopenharmony_ci { 1594c5f01b2fSopenharmony_ci SECTION("parser with callback") 1595c5f01b2fSopenharmony_ci { 1596c5f01b2fSopenharmony_ci json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept 1597c5f01b2fSopenharmony_ci { 1598c5f01b2fSopenharmony_ci return true; 1599c5f01b2fSopenharmony_ci }; 1600c5f01b2fSopenharmony_ci 1601c5f01b2fSopenharmony_ci CHECK(json::parse("{\"foo\": true:", cb, false).is_discarded()); 1602c5f01b2fSopenharmony_ci 1603c5f01b2fSopenharmony_ci json _; 1604c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(_ = json::parse("{\"foo\": true:", cb), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing object - unexpected ':'; expected '}'", json::parse_error&); 1605c5f01b2fSopenharmony_ci 1606c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(_ = json::parse("1.18973e+4932", cb), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&); 1607c5f01b2fSopenharmony_ci } 1608c5f01b2fSopenharmony_ci 1609c5f01b2fSopenharmony_ci SECTION("SAX parser") 1610c5f01b2fSopenharmony_ci { 1611c5f01b2fSopenharmony_ci SECTION("} without value") 1612c5f01b2fSopenharmony_ci { 1613c5f01b2fSopenharmony_ci SaxCountdown s(1); 1614c5f01b2fSopenharmony_ci CHECK(json::sax_parse("{}", &s) == false); 1615c5f01b2fSopenharmony_ci } 1616c5f01b2fSopenharmony_ci 1617c5f01b2fSopenharmony_ci SECTION("} with value") 1618c5f01b2fSopenharmony_ci { 1619c5f01b2fSopenharmony_ci SaxCountdown s(3); 1620c5f01b2fSopenharmony_ci CHECK(json::sax_parse("{\"k1\": true}", &s) == false); 1621c5f01b2fSopenharmony_ci } 1622c5f01b2fSopenharmony_ci 1623c5f01b2fSopenharmony_ci SECTION("second key") 1624c5f01b2fSopenharmony_ci { 1625c5f01b2fSopenharmony_ci SaxCountdown s(3); 1626c5f01b2fSopenharmony_ci CHECK(json::sax_parse("{\"k1\": true, \"k2\": false}", &s) == false); 1627c5f01b2fSopenharmony_ci } 1628c5f01b2fSopenharmony_ci 1629c5f01b2fSopenharmony_ci SECTION("] without value") 1630c5f01b2fSopenharmony_ci { 1631c5f01b2fSopenharmony_ci SaxCountdown s(1); 1632c5f01b2fSopenharmony_ci CHECK(json::sax_parse("[]", &s) == false); 1633c5f01b2fSopenharmony_ci } 1634c5f01b2fSopenharmony_ci 1635c5f01b2fSopenharmony_ci SECTION("] with value") 1636c5f01b2fSopenharmony_ci { 1637c5f01b2fSopenharmony_ci SaxCountdown s(2); 1638c5f01b2fSopenharmony_ci CHECK(json::sax_parse("[1]", &s) == false); 1639c5f01b2fSopenharmony_ci } 1640c5f01b2fSopenharmony_ci 1641c5f01b2fSopenharmony_ci SECTION("float") 1642c5f01b2fSopenharmony_ci { 1643c5f01b2fSopenharmony_ci SaxCountdown s(0); 1644c5f01b2fSopenharmony_ci CHECK(json::sax_parse("3.14", &s) == false); 1645c5f01b2fSopenharmony_ci } 1646c5f01b2fSopenharmony_ci 1647c5f01b2fSopenharmony_ci SECTION("false") 1648c5f01b2fSopenharmony_ci { 1649c5f01b2fSopenharmony_ci SaxCountdown s(0); 1650c5f01b2fSopenharmony_ci CHECK(json::sax_parse("false", &s) == false); 1651c5f01b2fSopenharmony_ci } 1652c5f01b2fSopenharmony_ci 1653c5f01b2fSopenharmony_ci SECTION("null") 1654c5f01b2fSopenharmony_ci { 1655c5f01b2fSopenharmony_ci SaxCountdown s(0); 1656c5f01b2fSopenharmony_ci CHECK(json::sax_parse("null", &s) == false); 1657c5f01b2fSopenharmony_ci } 1658c5f01b2fSopenharmony_ci 1659c5f01b2fSopenharmony_ci SECTION("true") 1660c5f01b2fSopenharmony_ci { 1661c5f01b2fSopenharmony_ci SaxCountdown s(0); 1662c5f01b2fSopenharmony_ci CHECK(json::sax_parse("true", &s) == false); 1663c5f01b2fSopenharmony_ci } 1664c5f01b2fSopenharmony_ci 1665c5f01b2fSopenharmony_ci SECTION("unsigned") 1666c5f01b2fSopenharmony_ci { 1667c5f01b2fSopenharmony_ci SaxCountdown s(0); 1668c5f01b2fSopenharmony_ci CHECK(json::sax_parse("12", &s) == false); 1669c5f01b2fSopenharmony_ci } 1670c5f01b2fSopenharmony_ci 1671c5f01b2fSopenharmony_ci SECTION("integer") 1672c5f01b2fSopenharmony_ci { 1673c5f01b2fSopenharmony_ci SaxCountdown s(0); 1674c5f01b2fSopenharmony_ci CHECK(json::sax_parse("-12", &s) == false); 1675c5f01b2fSopenharmony_ci } 1676c5f01b2fSopenharmony_ci 1677c5f01b2fSopenharmony_ci SECTION("string") 1678c5f01b2fSopenharmony_ci { 1679c5f01b2fSopenharmony_ci SaxCountdown s(0); 1680c5f01b2fSopenharmony_ci CHECK(json::sax_parse("\"foo\"", &s) == false); 1681c5f01b2fSopenharmony_ci } 1682c5f01b2fSopenharmony_ci } 1683c5f01b2fSopenharmony_ci } 1684c5f01b2fSopenharmony_ci 1685c5f01b2fSopenharmony_ci SECTION("error messages for comments") 1686c5f01b2fSopenharmony_ci { 1687c5f01b2fSopenharmony_ci json _; 1688c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(_ = json::parse("/a", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid comment; expecting '/' or '*' after '/'; last read: '/a'", json::parse_error); 1689c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(_ = json::parse("/*", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid comment; missing closing '*/'; last read: '/*<U+0000>'", json::parse_error); 1690c5f01b2fSopenharmony_ci } 1691c5f01b2fSopenharmony_ci} 1692