1 /*
2 __ _____ _____ _____
3 __| | __| | | | JSON for Modern C++ (test suite)
4 | | |__ | | | | | | version 3.7.3
5 |_____|_____|_____|_|___| https://github.com/nlohmann/json
6
7 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8 SPDX-License-Identifier: MIT
9 Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
10
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 SOFTWARE.
28 */
29
30 #include "doctest_compatibility.h"
31
32 #define private public
33 #include <nlohmann/json.hpp>
34 using nlohmann::json;
35 #undef private
36
37 namespace
38 {
39 // shortcut to scan a string literal
40 json::lexer::token_type scan_string(const char* s);
scan_string(const char * s)41 json::lexer::token_type scan_string(const char* s)
42 {
43 return json::lexer(nlohmann::detail::input_adapter(s)).scan();
44 }
45 }
46
47 TEST_CASE("lexer class")
48 {
49 SECTION("scan")
50 {
51 SECTION("structural characters")
52 {
53 CHECK((scan_string("[") == json::lexer::token_type::begin_array));
54 CHECK((scan_string("]") == json::lexer::token_type::end_array));
55 CHECK((scan_string("{") == json::lexer::token_type::begin_object));
56 CHECK((scan_string("}") == json::lexer::token_type::end_object));
57 CHECK((scan_string(",") == json::lexer::token_type::value_separator));
58 CHECK((scan_string(":") == json::lexer::token_type::name_separator));
59 }
60
61 SECTION("literal names")
62 {
63 CHECK((scan_string("null") == json::lexer::token_type::literal_null));
64 CHECK((scan_string("true") == json::lexer::token_type::literal_true));
65 CHECK((scan_string("false") == json::lexer::token_type::literal_false));
66 }
67
68 SECTION("numbers")
69 {
70 CHECK((scan_string("0") == json::lexer::token_type::value_unsigned));
71 CHECK((scan_string("1") == json::lexer::token_type::value_unsigned));
72 CHECK((scan_string("2") == json::lexer::token_type::value_unsigned));
73 CHECK((scan_string("3") == json::lexer::token_type::value_unsigned));
74 CHECK((scan_string("4") == json::lexer::token_type::value_unsigned));
75 CHECK((scan_string("5") == json::lexer::token_type::value_unsigned));
76 CHECK((scan_string("6") == json::lexer::token_type::value_unsigned));
77 CHECK((scan_string("7") == json::lexer::token_type::value_unsigned));
78 CHECK((scan_string("8") == json::lexer::token_type::value_unsigned));
79 CHECK((scan_string("9") == json::lexer::token_type::value_unsigned));
80
81 CHECK((scan_string("-0") == json::lexer::token_type::value_integer));
82 CHECK((scan_string("-1") == json::lexer::token_type::value_integer));
83
84 CHECK((scan_string("1.1") == json::lexer::token_type::value_float));
85 CHECK((scan_string("-1.1") == json::lexer::token_type::value_float));
86 CHECK((scan_string("1E10") == json::lexer::token_type::value_float));
87 }
88
89 SECTION("whitespace")
90 {
91 // result is end_of_input, because not token is following
92 CHECK((scan_string(" ") == json::lexer::token_type::end_of_input));
93 CHECK((scan_string("\t") == json::lexer::token_type::end_of_input));
94 CHECK((scan_string("\n") == json::lexer::token_type::end_of_input));
95 CHECK((scan_string("\r") == json::lexer::token_type::end_of_input));
96 CHECK((scan_string(" \t\n\r\n\t ") == json::lexer::token_type::end_of_input));
97 }
98 }
99
100 SECTION("token_type_name")
101 {
102 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::uninitialized)) == "<uninitialized>"));
103 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::literal_true)) == "true literal"));
104 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::literal_false)) == "false literal"));
105 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::literal_null)) == "null literal"));
106 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_string)) == "string literal"));
107 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_unsigned)) == "number literal"));
108 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_integer)) == "number literal"));
109 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_float)) == "number literal"));
110 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::begin_array)) == "'['"));
111 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::begin_object)) == "'{'"));
112 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::end_array)) == "']'"));
113 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::end_object)) == "'}'"));
114 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::name_separator)) == "':'"));
115 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_separator)) == "','"));
116 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::parse_error)) == "<parse error>"));
117 CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::end_of_input)) == "end of input"));
118 }
119
120 SECTION("parse errors on first character")
121 {
122 for (int c = 1; c < 128; ++c)
123 {
124 // create string from the ASCII code
125 const auto s = std::string(1, static_cast<char>(c));
126 // store scan() result
127 const auto res = scan_string(s.c_str());
128
129 switch (c)
130 {
131 // single characters that are valid tokens
132 case ('['):
133 case (']'):
134 case ('{'):
135 case ('}'):
136 case (','):
137 case (':'):
138 case ('0'):
139 case ('1'):
140 case ('2'):
141 case ('3'):
142 case ('4'):
143 case ('5'):
144 case ('6'):
145 case ('7'):
146 case ('8'):
147 case ('9'):
148 {
149 CHECK((res != json::lexer::token_type::parse_error));
150 break;
151 }
152
153 // whitespace
154 case (' '):
155 case ('\t'):
156 case ('\n'):
157 case ('\r'):
158 {
159 CHECK((res == json::lexer::token_type::end_of_input));
160 break;
161 }
162
163 // anything else is not expected
164 default:
165 {
166 CHECK((res == json::lexer::token_type::parse_error));
167 break;
168 }
169 }
170 }
171 }
172
173 SECTION("very large string")
174 {
175 // strings larger than 1024 bytes yield a resize of the lexer's yytext buffer
176 std::string s("\"");
177 s += std::string(2048, 'x');
178 s += "\"";
179 CHECK((scan_string(s.c_str()) == json::lexer::token_type::value_string));
180 }
181 }
182