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 15c5f01b2fSopenharmony_cinamespace 16c5f01b2fSopenharmony_ci{ 17c5f01b2fSopenharmony_ci// shortcut to scan a string literal 18c5f01b2fSopenharmony_cijson::lexer::token_type scan_string(const char* s, bool ignore_comments = false); 19c5f01b2fSopenharmony_cijson::lexer::token_type scan_string(const char* s, const bool ignore_comments) 20c5f01b2fSopenharmony_ci{ 21c5f01b2fSopenharmony_ci auto ia = nlohmann::detail::input_adapter(s); 22c5f01b2fSopenharmony_ci return nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments).scan(); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) 23c5f01b2fSopenharmony_ci} 24c5f01b2fSopenharmony_ci} // namespace 25c5f01b2fSopenharmony_ci 26c5f01b2fSopenharmony_cistd::string get_error_message(const char* s, bool ignore_comments = false); 27c5f01b2fSopenharmony_cistd::string get_error_message(const char* s, const bool ignore_comments) 28c5f01b2fSopenharmony_ci{ 29c5f01b2fSopenharmony_ci auto ia = nlohmann::detail::input_adapter(s); 30c5f01b2fSopenharmony_ci auto lexer = nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) 31c5f01b2fSopenharmony_ci lexer.scan(); 32c5f01b2fSopenharmony_ci return lexer.get_error_message(); 33c5f01b2fSopenharmony_ci} 34c5f01b2fSopenharmony_ci 35c5f01b2fSopenharmony_ciTEST_CASE("lexer class") 36c5f01b2fSopenharmony_ci{ 37c5f01b2fSopenharmony_ci SECTION("scan") 38c5f01b2fSopenharmony_ci { 39c5f01b2fSopenharmony_ci SECTION("structural characters") 40c5f01b2fSopenharmony_ci { 41c5f01b2fSopenharmony_ci CHECK((scan_string("[") == json::lexer::token_type::begin_array)); 42c5f01b2fSopenharmony_ci CHECK((scan_string("]") == json::lexer::token_type::end_array)); 43c5f01b2fSopenharmony_ci CHECK((scan_string("{") == json::lexer::token_type::begin_object)); 44c5f01b2fSopenharmony_ci CHECK((scan_string("}") == json::lexer::token_type::end_object)); 45c5f01b2fSopenharmony_ci CHECK((scan_string(",") == json::lexer::token_type::value_separator)); 46c5f01b2fSopenharmony_ci CHECK((scan_string(":") == json::lexer::token_type::name_separator)); 47c5f01b2fSopenharmony_ci } 48c5f01b2fSopenharmony_ci 49c5f01b2fSopenharmony_ci SECTION("literal names") 50c5f01b2fSopenharmony_ci { 51c5f01b2fSopenharmony_ci CHECK((scan_string("null") == json::lexer::token_type::literal_null)); 52c5f01b2fSopenharmony_ci CHECK((scan_string("true") == json::lexer::token_type::literal_true)); 53c5f01b2fSopenharmony_ci CHECK((scan_string("false") == json::lexer::token_type::literal_false)); 54c5f01b2fSopenharmony_ci } 55c5f01b2fSopenharmony_ci 56c5f01b2fSopenharmony_ci SECTION("numbers") 57c5f01b2fSopenharmony_ci { 58c5f01b2fSopenharmony_ci CHECK((scan_string("0") == json::lexer::token_type::value_unsigned)); 59c5f01b2fSopenharmony_ci CHECK((scan_string("1") == json::lexer::token_type::value_unsigned)); 60c5f01b2fSopenharmony_ci CHECK((scan_string("2") == json::lexer::token_type::value_unsigned)); 61c5f01b2fSopenharmony_ci CHECK((scan_string("3") == json::lexer::token_type::value_unsigned)); 62c5f01b2fSopenharmony_ci CHECK((scan_string("4") == json::lexer::token_type::value_unsigned)); 63c5f01b2fSopenharmony_ci CHECK((scan_string("5") == json::lexer::token_type::value_unsigned)); 64c5f01b2fSopenharmony_ci CHECK((scan_string("6") == json::lexer::token_type::value_unsigned)); 65c5f01b2fSopenharmony_ci CHECK((scan_string("7") == json::lexer::token_type::value_unsigned)); 66c5f01b2fSopenharmony_ci CHECK((scan_string("8") == json::lexer::token_type::value_unsigned)); 67c5f01b2fSopenharmony_ci CHECK((scan_string("9") == json::lexer::token_type::value_unsigned)); 68c5f01b2fSopenharmony_ci 69c5f01b2fSopenharmony_ci CHECK((scan_string("-0") == json::lexer::token_type::value_integer)); 70c5f01b2fSopenharmony_ci CHECK((scan_string("-1") == json::lexer::token_type::value_integer)); 71c5f01b2fSopenharmony_ci 72c5f01b2fSopenharmony_ci CHECK((scan_string("1.1") == json::lexer::token_type::value_float)); 73c5f01b2fSopenharmony_ci CHECK((scan_string("-1.1") == json::lexer::token_type::value_float)); 74c5f01b2fSopenharmony_ci CHECK((scan_string("1E10") == json::lexer::token_type::value_float)); 75c5f01b2fSopenharmony_ci } 76c5f01b2fSopenharmony_ci 77c5f01b2fSopenharmony_ci SECTION("whitespace") 78c5f01b2fSopenharmony_ci { 79c5f01b2fSopenharmony_ci // result is end_of_input, because not token is following 80c5f01b2fSopenharmony_ci CHECK((scan_string(" ") == json::lexer::token_type::end_of_input)); 81c5f01b2fSopenharmony_ci CHECK((scan_string("\t") == json::lexer::token_type::end_of_input)); 82c5f01b2fSopenharmony_ci CHECK((scan_string("\n") == json::lexer::token_type::end_of_input)); 83c5f01b2fSopenharmony_ci CHECK((scan_string("\r") == json::lexer::token_type::end_of_input)); 84c5f01b2fSopenharmony_ci CHECK((scan_string(" \t\n\r\n\t ") == json::lexer::token_type::end_of_input)); 85c5f01b2fSopenharmony_ci } 86c5f01b2fSopenharmony_ci } 87c5f01b2fSopenharmony_ci 88c5f01b2fSopenharmony_ci SECTION("token_type_name") 89c5f01b2fSopenharmony_ci { 90c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::uninitialized)) == "<uninitialized>")); 91c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::literal_true)) == "true literal")); 92c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::literal_false)) == "false literal")); 93c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::literal_null)) == "null literal")); 94c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_string)) == "string literal")); 95c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_unsigned)) == "number literal")); 96c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_integer)) == "number literal")); 97c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_float)) == "number literal")); 98c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::begin_array)) == "'['")); 99c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::begin_object)) == "'{'")); 100c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::end_array)) == "']'")); 101c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::end_object)) == "'}'")); 102c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::name_separator)) == "':'")); 103c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_separator)) == "','")); 104c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::parse_error)) == "<parse error>")); 105c5f01b2fSopenharmony_ci CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::end_of_input)) == "end of input")); 106c5f01b2fSopenharmony_ci } 107c5f01b2fSopenharmony_ci 108c5f01b2fSopenharmony_ci SECTION("parse errors on first character") 109c5f01b2fSopenharmony_ci { 110c5f01b2fSopenharmony_ci for (int c = 1; c < 128; ++c) 111c5f01b2fSopenharmony_ci { 112c5f01b2fSopenharmony_ci // create string from the ASCII code 113c5f01b2fSopenharmony_ci const auto s = std::string(1, static_cast<char>(c)); 114c5f01b2fSopenharmony_ci // store scan() result 115c5f01b2fSopenharmony_ci const auto res = scan_string(s.c_str()); 116c5f01b2fSopenharmony_ci 117c5f01b2fSopenharmony_ci CAPTURE(s) 118c5f01b2fSopenharmony_ci 119c5f01b2fSopenharmony_ci switch (c) 120c5f01b2fSopenharmony_ci { 121c5f01b2fSopenharmony_ci // single characters that are valid tokens 122c5f01b2fSopenharmony_ci case ('['): 123c5f01b2fSopenharmony_ci case (']'): 124c5f01b2fSopenharmony_ci case ('{'): 125c5f01b2fSopenharmony_ci case ('}'): 126c5f01b2fSopenharmony_ci case (','): 127c5f01b2fSopenharmony_ci case (':'): 128c5f01b2fSopenharmony_ci case ('0'): 129c5f01b2fSopenharmony_ci case ('1'): 130c5f01b2fSopenharmony_ci case ('2'): 131c5f01b2fSopenharmony_ci case ('3'): 132c5f01b2fSopenharmony_ci case ('4'): 133c5f01b2fSopenharmony_ci case ('5'): 134c5f01b2fSopenharmony_ci case ('6'): 135c5f01b2fSopenharmony_ci case ('7'): 136c5f01b2fSopenharmony_ci case ('8'): 137c5f01b2fSopenharmony_ci case ('9'): 138c5f01b2fSopenharmony_ci { 139c5f01b2fSopenharmony_ci CHECK((res != json::lexer::token_type::parse_error)); 140c5f01b2fSopenharmony_ci break; 141c5f01b2fSopenharmony_ci } 142c5f01b2fSopenharmony_ci 143c5f01b2fSopenharmony_ci // whitespace 144c5f01b2fSopenharmony_ci case (' '): 145c5f01b2fSopenharmony_ci case ('\t'): 146c5f01b2fSopenharmony_ci case ('\n'): 147c5f01b2fSopenharmony_ci case ('\r'): 148c5f01b2fSopenharmony_ci { 149c5f01b2fSopenharmony_ci CHECK((res == json::lexer::token_type::end_of_input)); 150c5f01b2fSopenharmony_ci break; 151c5f01b2fSopenharmony_ci } 152c5f01b2fSopenharmony_ci 153c5f01b2fSopenharmony_ci // anything else is not expected 154c5f01b2fSopenharmony_ci default: 155c5f01b2fSopenharmony_ci { 156c5f01b2fSopenharmony_ci CHECK((res == json::lexer::token_type::parse_error)); 157c5f01b2fSopenharmony_ci break; 158c5f01b2fSopenharmony_ci } 159c5f01b2fSopenharmony_ci } 160c5f01b2fSopenharmony_ci } 161c5f01b2fSopenharmony_ci } 162c5f01b2fSopenharmony_ci 163c5f01b2fSopenharmony_ci SECTION("very large string") 164c5f01b2fSopenharmony_ci { 165c5f01b2fSopenharmony_ci // strings larger than 1024 bytes yield a resize of the lexer's yytext buffer 166c5f01b2fSopenharmony_ci std::string s("\""); 167c5f01b2fSopenharmony_ci s += std::string(2048, 'x'); 168c5f01b2fSopenharmony_ci s += "\""; 169c5f01b2fSopenharmony_ci CHECK((scan_string(s.c_str()) == json::lexer::token_type::value_string)); 170c5f01b2fSopenharmony_ci } 171c5f01b2fSopenharmony_ci 172c5f01b2fSopenharmony_ci SECTION("fail on comments") 173c5f01b2fSopenharmony_ci { 174c5f01b2fSopenharmony_ci CHECK((scan_string("/", false) == json::lexer::token_type::parse_error)); 175c5f01b2fSopenharmony_ci CHECK(get_error_message("/", false) == "invalid literal"); 176c5f01b2fSopenharmony_ci 177c5f01b2fSopenharmony_ci CHECK((scan_string("/!", false) == json::lexer::token_type::parse_error)); 178c5f01b2fSopenharmony_ci CHECK(get_error_message("/!", false) == "invalid literal"); 179c5f01b2fSopenharmony_ci CHECK((scan_string("/*", false) == json::lexer::token_type::parse_error)); 180c5f01b2fSopenharmony_ci CHECK(get_error_message("/*", false) == "invalid literal"); 181c5f01b2fSopenharmony_ci CHECK((scan_string("/**", false) == json::lexer::token_type::parse_error)); 182c5f01b2fSopenharmony_ci CHECK(get_error_message("/**", false) == "invalid literal"); 183c5f01b2fSopenharmony_ci 184c5f01b2fSopenharmony_ci CHECK((scan_string("//", false) == json::lexer::token_type::parse_error)); 185c5f01b2fSopenharmony_ci CHECK(get_error_message("//", false) == "invalid literal"); 186c5f01b2fSopenharmony_ci CHECK((scan_string("/**/", false) == json::lexer::token_type::parse_error)); 187c5f01b2fSopenharmony_ci CHECK(get_error_message("/**/", false) == "invalid literal"); 188c5f01b2fSopenharmony_ci CHECK((scan_string("/** /", false) == json::lexer::token_type::parse_error)); 189c5f01b2fSopenharmony_ci CHECK(get_error_message("/** /", false) == "invalid literal"); 190c5f01b2fSopenharmony_ci 191c5f01b2fSopenharmony_ci CHECK((scan_string("/***/", false) == json::lexer::token_type::parse_error)); 192c5f01b2fSopenharmony_ci CHECK(get_error_message("/***/", false) == "invalid literal"); 193c5f01b2fSopenharmony_ci CHECK((scan_string("/* true */", false) == json::lexer::token_type::parse_error)); 194c5f01b2fSopenharmony_ci CHECK(get_error_message("/* true */", false) == "invalid literal"); 195c5f01b2fSopenharmony_ci CHECK((scan_string("/*/**/", false) == json::lexer::token_type::parse_error)); 196c5f01b2fSopenharmony_ci CHECK(get_error_message("/*/**/", false) == "invalid literal"); 197c5f01b2fSopenharmony_ci CHECK((scan_string("/*/* */", false) == json::lexer::token_type::parse_error)); 198c5f01b2fSopenharmony_ci CHECK(get_error_message("/*/* */", false) == "invalid literal"); 199c5f01b2fSopenharmony_ci } 200c5f01b2fSopenharmony_ci 201c5f01b2fSopenharmony_ci SECTION("ignore comments") 202c5f01b2fSopenharmony_ci { 203c5f01b2fSopenharmony_ci CHECK((scan_string("/", true) == json::lexer::token_type::parse_error)); 204c5f01b2fSopenharmony_ci CHECK(get_error_message("/", true) == "invalid comment; expecting '/' or '*' after '/'"); 205c5f01b2fSopenharmony_ci 206c5f01b2fSopenharmony_ci CHECK((scan_string("/!", true) == json::lexer::token_type::parse_error)); 207c5f01b2fSopenharmony_ci CHECK(get_error_message("/!", true) == "invalid comment; expecting '/' or '*' after '/'"); 208c5f01b2fSopenharmony_ci CHECK((scan_string("/*", true) == json::lexer::token_type::parse_error)); 209c5f01b2fSopenharmony_ci CHECK(get_error_message("/*", true) == "invalid comment; missing closing '*/'"); 210c5f01b2fSopenharmony_ci CHECK((scan_string("/**", true) == json::lexer::token_type::parse_error)); 211c5f01b2fSopenharmony_ci CHECK(get_error_message("/**", true) == "invalid comment; missing closing '*/'"); 212c5f01b2fSopenharmony_ci 213c5f01b2fSopenharmony_ci CHECK((scan_string("//", true) == json::lexer::token_type::end_of_input)); 214c5f01b2fSopenharmony_ci CHECK((scan_string("/**/", true) == json::lexer::token_type::end_of_input)); 215c5f01b2fSopenharmony_ci CHECK((scan_string("/** /", true) == json::lexer::token_type::parse_error)); 216c5f01b2fSopenharmony_ci CHECK(get_error_message("/** /", true) == "invalid comment; missing closing '*/'"); 217c5f01b2fSopenharmony_ci 218c5f01b2fSopenharmony_ci CHECK((scan_string("/***/", true) == json::lexer::token_type::end_of_input)); 219c5f01b2fSopenharmony_ci CHECK((scan_string("/* true */", true) == json::lexer::token_type::end_of_input)); 220c5f01b2fSopenharmony_ci CHECK((scan_string("/*/**/", true) == json::lexer::token_type::end_of_input)); 221c5f01b2fSopenharmony_ci CHECK((scan_string("/*/* */", true) == json::lexer::token_type::end_of_input)); 222c5f01b2fSopenharmony_ci 223c5f01b2fSopenharmony_ci CHECK((scan_string("//\n//\n", true) == json::lexer::token_type::end_of_input)); 224c5f01b2fSopenharmony_ci CHECK((scan_string("/**//**//**/", true) == json::lexer::token_type::end_of_input)); 225c5f01b2fSopenharmony_ci } 226c5f01b2fSopenharmony_ci} 227