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