1 /*
2     __ _____ _____ _____
3  __|  |   __|     |   | |  JSON for Modern C++ (test suite)
4 |  |  |__   |  |  | | | |  version 3.10.4
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 #ifdef JSON_DIAGNOSTICS
33     #undef JSON_DIAGNOSTICS
34 #endif
35 
36 #define JSON_DIAGNOSTICS 1
37 
38 #include <nlohmann/json.hpp>
39 using nlohmann::json;
40 
41 TEST_CASE("Better diagnostics")
42 {
43     SECTION("empty JSON Pointer")
44     {
45         json j = 1;
46         std::string s;
47         CHECK_THROWS_WITH_AS(s = j.get<std::string>(), "[json.exception.type_error.302] type must be string, but is number", json::type_error);
48     }
49 
50     SECTION("invalid type")
51     {
52         json j;
53         j["a"]["b"]["c"] = 1;
54         std::string s;
55         CHECK_THROWS_WITH_AS(s = j["a"]["b"]["c"].get<std::string>(), "[json.exception.type_error.302] (/a/b/c) type must be string, but is number", json::type_error);
56     }
57 
58     SECTION("missing key")
59     {
60         json j;
61         j["object"]["object"] = true;
62         CHECK_THROWS_WITH_AS(j["object"].at("not_found"), "[json.exception.out_of_range.403] (/object) key 'not_found' not found", json::out_of_range);
63     }
64 
65     SECTION("array index out of range")
66     {
67         json j;
68         j["array"][4] = true;
69         CHECK_THROWS_WITH_AS(j["array"].at(5), "[json.exception.out_of_range.401] (/array) array index 5 is out of range", json::out_of_range);
70     }
71 
72     SECTION("array index at wrong type")
73     {
74         json j;
75         j["array"][4] = true;
76         CHECK_THROWS_WITH_AS(j["array"][4][5], "[json.exception.type_error.305] (/array/4) cannot use operator[] with a numeric argument with boolean", json::type_error);
77     }
78 
79     SECTION("wrong iterator")
80     {
81         json j;
82         j["array"] = json::array();
83         CHECK_THROWS_WITH_AS(j["array"].erase(j.begin()), "[json.exception.invalid_iterator.202] (/array) iterator does not fit current value", json::invalid_iterator);
84     }
85 
86     SECTION("JSON Pointer escaping")
87     {
88         json j;
89         j["a/b"]["m~n"] = 1;
90         std::string s;
91         CHECK_THROWS_WITH_AS(s = j["a/b"]["m~n"].get<std::string>(), "[json.exception.type_error.302] (/a~1b/m~0n) type must be string, but is number", json::type_error);
92     }
93 
94     SECTION("Parse error")
95     {
96         json _;
97         CHECK_THROWS_WITH_AS(_ = json::parse(""), "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error);
98     }
99 
100     SECTION("Regression test for https://github.com/nlohmann/json/pull/2562#pullrequestreview-574858448")
101     {
102         CHECK_THROWS_WITH_AS(json({"0", "0"})[1].get<int>(), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error);
103         CHECK_THROWS_WITH_AS(json({"0", "1"})[1].get<int>(), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error);
104     }
105 
106     SECTION("Regression test for https://github.com/nlohmann/json/pull/2562/files/380a613f2b5d32425021129cd1f371ddcfd54ddf#r563259793")
107     {
108         json j;
109         j["/foo"] = {1, 2, 3};
110         CHECK_THROWS_WITH_AS(j.unflatten(), "[json.exception.type_error.315] (/~1foo) values in object must be primitive", json::type_error);
111     }
112 
113     SECTION("Regression test for https://github.com/nlohmann/json/issues/2838")
114     {
115         // void push_back(basic_json&& val)
116         {
117             json j_arr = json::array();
118             j_arr.push_back(json::object());
119             j_arr.push_back(json::object());
120             j_arr.push_back(json::object());
121             j_arr.push_back(json::object());
122             json j_obj = json::object();
123             j_obj["key"] = j_arr;
124         }
125 
126         // void push_back(const basic_json& val)
127         {
128             json j_arr = json::array();
129             auto object = json::object();
130             j_arr.push_back(object);
131             j_arr.push_back(object);
132             j_arr.push_back(object);
133             j_arr.push_back(object);
134             json j_obj = json::object();
135             j_obj["key"] = j_arr;
136         }
137 
138         // reference emplace_back(Args&& ... args)
139         {
140             json j_arr = json::array();
141             j_arr.emplace_back(json::object());
142             j_arr.emplace_back(json::object());
143             j_arr.emplace_back(json::object());
144             j_arr.emplace_back(json::object());
145             json j_obj = json::object();
146             j_obj["key"] = j_arr;
147         }
148 
149         // iterator insert(const_iterator pos, const basic_json& val)
150         {
151             json j_arr = json::array();
152             j_arr.insert(j_arr.begin(), json::object());
153             j_arr.insert(j_arr.begin(), json::object());
154             j_arr.insert(j_arr.begin(), json::object());
155             j_arr.insert(j_arr.begin(), json::object());
156             json j_obj = json::object();
157             j_obj["key"] = j_arr;
158         }
159 
160         // iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
161         {
162             json j_arr = json::array();
163             j_arr.insert(j_arr.begin(), 2, json::object());
164             json j_obj = json::object();
165             j_obj["key"] = j_arr;
166         }
167 
168         // iterator insert(const_iterator pos, const_iterator first, const_iterator last)
169         {
170             json j_arr = json::array();
171             json j_objects = {json::object(), json::object()};
172             j_arr.insert(j_arr.begin(), j_objects.begin(), j_objects.end());
173             json j_obj = json::object();
174             j_obj["key"] = j_arr;
175         }
176     }
177 
178     SECTION("Regression test for issue #2962 - JSON_DIAGNOSTICS assertion for ordered_json")
179     {
180         nlohmann::ordered_json j;
181         nlohmann::ordered_json j2;
182         const std::string value;
183         j["first"] = value;
184         j["second"] = value;
185         j2["something"] = j;
186     }
187 
188     SECTION("Regression test for issue #3007 - Parent pointers properly set when using update()")
189     {
190         // void update(const_reference j)
191         {
192             json j = json::object();
193 
194             {
195                 json j2 = json::object();
196                 j2["one"] = 1;
197 
198                 j.update(j2);
199             }
200 
201             // Must call operator[] on const element, otherwise m_parent gets updated.
202             auto const& constJ = j;
203             CHECK_THROWS_WITH_AS(constJ["one"].at(0), "[json.exception.type_error.304] (/one) cannot use at() with number", json::type_error);
204         }
205 
206         // void update(const_iterator first, const_iterator last)
207         {
208             json j = json::object();
209 
210             {
211                 json j2 = json::object();
212                 j2["one"] = 1;
213 
214                 j.update(j2.begin(), j2.end());
215             }
216 
217             // Must call operator[] on const element, otherwise m_parent gets updated.
218             auto const& constJ = j;
219             CHECK_THROWS_WITH_AS(constJ["one"].at(0), "[json.exception.type_error.304] (/one) cannot use at() with number", json::type_error);
220         }
221 
222         // Code from #3007 triggering unwanted assertion without fix to update().
223         {
224             json root = json::array();
225             json lower = json::object();
226 
227             {
228                 json lowest = json::object();
229                 lowest["one"] = 1;
230 
231                 lower.update(lowest);
232             }
233 
234             root.push_back(lower);
235         }
236     }
237 
238     SECTION("Regression test for https://github.com/nlohmann/json/issues/3032")
239     {
240         // reference operator[](size_type idx)
241         {
242             json j_arr = json::array();
243             j_arr[0] = 0;
244             j_arr[1] = 1;
245             j_arr[2] = 2;
246             j_arr[3] = 3;
247             j_arr[4] = 4;
248             j_arr[5] = 5;
249             j_arr[6] = 6;
250             j_arr[7] = 7;
251             json j_arr_copy = j_arr;
252         }
253     }
254 }
255