1 // __ _____ _____ _____ 2 // __| | __| | | | JSON for Modern C++ (supporting code) 3 // | | |__ | | | | | | version 3.11.3 4 // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 // 6 // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> 7 // SPDX-License-Identifier: MIT 8 9 #include "doctest_compatibility.h" 10 11 #include <algorithm> 12 #include <nlohmann/json.hpp> 13 using nlohmann::json; 14 15 TEST_CASE("algorithms") 16 { 17 json j_array = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz"}; 18 json j_object = {{"one", 1}, {"two", 2}}; 19 20 SECTION("non-modifying sequence operations") 21 { 22 SECTION("std::all_of") 23 { 24 CHECK(std::all_of(j_array.begin(), j_array.end(), [](const json & value) __anon65bee81c0102(const json & value) 25 { 26 return !value.empty(); 27 })); 28 CHECK(std::all_of(j_object.begin(), j_object.end(), [](const json & value) __anon65bee81c0202(const json & value) 29 { 30 return value.type() == json::value_t::number_integer; 31 })); 32 } 33 34 SECTION("std::any_of") 35 { 36 CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value) __anon65bee81c0302(const json & value) 37 { 38 return value.is_string() && value.get<std::string>() == "foo"; 39 })); 40 CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value) __anon65bee81c0402(const json & value) 41 { 42 return value.get<int>() > 1; 43 })); 44 } 45 46 SECTION("std::none_of") 47 { 48 CHECK(std::none_of(j_array.begin(), j_array.end(), [](const json & value) __anon65bee81c0502(const json & value) 49 { 50 return value.empty(); 51 })); 52 CHECK(std::none_of(j_object.begin(), j_object.end(), [](const json & value) __anon65bee81c0602(const json & value) 53 { 54 return value.get<int>() <= 0; 55 })); 56 } 57 58 SECTION("std::for_each") 59 { 60 SECTION("reading") 61 { 62 int sum = 0; 63 64 std::for_each(j_array.cbegin(), j_array.cend(), [&sum](const json & value) __anon65bee81c0702(const json & value) 65 { 66 if (value.is_number()) 67 { 68 sum += static_cast<int>(value); 69 } 70 }); 71 72 CHECK(sum == 45); 73 } 74 75 SECTION("writing") 76 { 77 auto add17 = [](json & value) __anon65bee81c0802(json & value) 78 { 79 if (value.is_array()) 80 { 81 value.push_back(17); 82 } 83 }; 84 85 std::for_each(j_array.begin(), j_array.end(), add17); 86 87 CHECK(j_array[6] == json({1, 2, 3, 17})); 88 } 89 } 90 91 SECTION("std::count") 92 { 93 CHECK(std::count(j_array.begin(), j_array.end(), json(true)) == 1); 94 } 95 96 SECTION("std::count_if") 97 { 98 CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json & value) __anon65bee81c0902(const json & value) 99 { 100 return (value.is_number()); 101 }) == 3); 102 CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json&) __anon65bee81c0a02(const json&) 103 { 104 return true; 105 }) == 9); 106 } 107 108 SECTION("std::mismatch") 109 { 110 json j_array2 = {13, 29, 3, {{"one", 1}, {"two", 2}, {"three", 3}}, true, false, {1, 2, 3}, "foo", "baz"}; 111 auto res = std::mismatch(j_array.begin(), j_array.end(), j_array2.begin()); 112 CHECK(*res.first == json({{"one", 1}, {"two", 2}})); 113 CHECK(*res.second == json({{"one", 1}, {"two", 2}, {"three", 3}})); 114 } 115 116 SECTION("std::equal") 117 { 118 SECTION("using operator==") 119 { 120 CHECK(std::equal(j_array.begin(), j_array.end(), j_array.begin())); 121 CHECK(std::equal(j_object.begin(), j_object.end(), j_object.begin())); 122 CHECK(!std::equal(j_array.begin(), j_array.end(), j_object.begin())); 123 } 124 125 SECTION("using user-defined comparison") 126 { 127 // compare objects only by size of its elements 128 json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"}; 129 CHECK(!std::equal(j_array.begin(), j_array.end(), j_array2.begin())); 130 CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(), 131 [](const json & a, const json & b) __anon65bee81c0b02(const json & a, const json & b) 132 { 133 return (a.size() == b.size()); 134 })); 135 } 136 } 137 138 SECTION("std::find") 139 { 140 auto it = std::find(j_array.begin(), j_array.end(), json(false)); 141 CHECK(std::distance(j_array.begin(), it) == 5); 142 } 143 144 SECTION("std::find_if") 145 { 146 auto it = std::find_if(j_array.begin(), j_array.end(), 147 [](const json & value) __anon65bee81c0c02(const json & value) 148 { 149 return value.is_boolean(); 150 }); 151 CHECK(std::distance(j_array.begin(), it) == 4); 152 } 153 154 SECTION("std::find_if_not") 155 { 156 auto it = std::find_if_not(j_array.begin(), j_array.end(), 157 [](const json & value) __anon65bee81c0d02(const json & value) 158 { 159 return value.is_number(); 160 }); 161 CHECK(std::distance(j_array.begin(), it) == 3); 162 } 163 164 SECTION("std::adjacent_find") 165 { 166 CHECK(std::adjacent_find(j_array.begin(), j_array.end()) == j_array.end()); 167 CHECK(std::adjacent_find(j_array.begin(), j_array.end(), 168 [](const json & v1, const json & v2) __anon65bee81c0e02(const json & v1, const json & v2) 169 { 170 return v1.type() == v2.type(); 171 }) == j_array.begin()); 172 } 173 } 174 175 SECTION("modifying sequence operations") 176 { 177 SECTION("std::reverse") 178 { 179 std::reverse(j_array.begin(), j_array.end()); 180 CHECK(j_array == json({"baz", "foo", {1, 2, 3}, false, true, {{"one", 1}, {"two", 2}}, 3, 29, 13})); 181 } 182 183 SECTION("std::rotate") 184 { 185 std::rotate(j_array.begin(), j_array.begin() + 1, j_array.end()); 186 CHECK(j_array == json({29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", 13})); 187 } 188 189 SECTION("std::partition") 190 { 191 auto it = std::partition(j_array.begin(), j_array.end(), [](const json & v) __anon65bee81c0f02(const json & v) 192 { 193 return v.is_string(); 194 }); 195 CHECK(std::distance(j_array.begin(), it) == 2); 196 CHECK(!it[2].is_string()); 197 } 198 } 199 200 SECTION("sorting operations") 201 { 202 SECTION("std::sort") 203 { 204 SECTION("with standard comparison") 205 { 206 json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr}; 207 std::sort(j.begin(), j.end()); 208 CHECK(j == json({nullptr, false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"})); 209 } 210 211 SECTION("with user-defined comparison") 212 { 213 json j = {3, {{"one", 1}, {"two", 2}}, {1, 2, 3}, nullptr}; 214 std::sort(j.begin(), j.end(), [](const json & a, const json & b) __anon65bee81c1002(const json & a, const json & b) 215 { 216 return a.size() < b.size(); 217 }); 218 CHECK(j == json({nullptr, 3, {{"one", 1}, {"two", 2}}, {1, 2, 3}})); 219 } 220 221 SECTION("sorting an object") 222 { 223 json j({{"one", 1}, {"two", 2}}); 224 CHECK_THROWS_WITH_AS(std::sort(j.begin(), j.end()), "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&); 225 } 226 } 227 228 SECTION("std::partial_sort") 229 { 230 json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr}; 231 std::partial_sort(j.begin(), j.begin() + 4, j.end()); 232 CHECK(j == json({nullptr, false, true, 3, {{"one", 1}, {"two", 2}}, 29, {1, 2, 3}, "foo", "baz", 13})); 233 } 234 } 235 236 SECTION("set operations") 237 { 238 SECTION("std::merge") 239 { 240 { 241 json j1 = {2, 4, 6, 8}; 242 json j2 = {1, 2, 3, 5, 7}; 243 json j3; 244 245 std::merge(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3)); 246 CHECK(j3 == json({1, 2, 2, 3, 4, 5, 6, 7, 8})); 247 } 248 } 249 250 SECTION("std::set_difference") 251 { 252 json j1 = {1, 2, 3, 4, 5, 6, 7, 8}; 253 json j2 = {1, 2, 3, 5, 7}; 254 json j3; 255 256 std::set_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3)); 257 CHECK(j3 == json({4, 6, 8})); 258 } 259 260 SECTION("std::set_intersection") 261 { 262 json j1 = {1, 2, 3, 4, 5, 6, 7, 8}; 263 json j2 = {1, 2, 3, 5, 7}; 264 json j3; 265 266 std::set_intersection(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3)); 267 CHECK(j3 == json({1, 2, 3, 5, 7})); 268 } 269 270 SECTION("std::set_union") 271 { 272 json j1 = {2, 4, 6, 8}; 273 json j2 = {1, 2, 3, 5, 7}; 274 json j3; 275 276 std::set_union(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3)); 277 CHECK(j3 == json({1, 2, 3, 4, 5, 6, 7, 8})); 278 } 279 280 SECTION("std::set_symmetric_difference") 281 { 282 json j1 = {2, 4, 6, 8}; 283 json j2 = {1, 2, 3, 5, 7}; 284 json j3; 285 286 std::set_symmetric_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3)); 287 CHECK(j3 == json({1, 3, 4, 5, 6, 7, 8})); 288 } 289 } 290 291 SECTION("heap operations") 292 { 293 std::make_heap(j_array.begin(), j_array.end()); 294 CHECK(std::is_heap(j_array.begin(), j_array.end())); 295 std::sort_heap(j_array.begin(), j_array.end()); 296 CHECK(j_array == json({false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"})); 297 } 298 299 SECTION("iota") 300 { 301 SECTION("int") 302 { 303 json json_arr = {0, 5, 2, 4, 10, 20, 30, 40, 50, 1}; 304 std::iota(json_arr.begin(), json_arr.end(), 0); 305 CHECK(json_arr == json({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); 306 } 307 SECTION("double") 308 { 309 json json_arr = {0.5, 1.5, 1.3, 4.1, 10.2, 20.5, 30.6, 40.1, 50.22, 1.5}; 310 std::iota(json_arr.begin(), json_arr.end(), 0.5); 311 CHECK(json_arr == json({0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5})); 312 } 313 314 SECTION("char") 315 { 316 json json_arr = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '0', '1'}; 317 std::iota(json_arr.begin(), json_arr.end(), '0'); 318 CHECK(json_arr == json({'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'})); 319 } 320 } 321 322 SECTION("copy") 323 { 324 SECTION("copy without if") 325 { 326 json dest_arr; 327 const json source_arr = {1, 2, 3, 4}; 328 329 std::copy(source_arr.begin(), source_arr.end(), std::back_inserter(dest_arr)); 330 331 CHECK(dest_arr == source_arr); 332 } 333 SECTION("copy if") 334 { 335 json dest_arr; 336 const json source_arr = {0, 3, 6, 9, 12, 15, 20}; 337 338 std::copy_if(source_arr.begin(), source_arr.end(), std::back_inserter(dest_arr), [](const json & _value) __anon65bee81c1102(const json & _value) 339 { 340 return _value.get<int>() % 3 == 0; 341 }); 342 CHECK(dest_arr == json({0, 3, 6, 9, 12, 15})); 343 } 344 SECTION("copy n") 345 { 346 const json source_arr = {0, 1, 2, 3, 4, 5, 6, 7}; 347 json dest_arr; 348 const unsigned char numToCopy = 2; 349 350 std::copy_n(source_arr.begin(), numToCopy, std::back_inserter(dest_arr)); 351 CHECK(dest_arr == json{0, 1}); 352 353 } 354 SECTION("copy n chars") 355 { 356 const json source_arr = {'1', '2', '3', '4', '5', '6', '7'}; 357 json dest_arr; 358 const unsigned char numToCopy = 4; 359 360 std::copy_n(source_arr.begin(), numToCopy, std::back_inserter(dest_arr)); 361 CHECK(dest_arr == json{'1', '2', '3', '4'}); 362 } 363 } 364 365 } 366