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#ifdef JSON_TEST_NO_GLOBAL_UDLS 15c5f01b2fSopenharmony_ci using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) 16c5f01b2fSopenharmony_ci#endif 17c5f01b2fSopenharmony_ci 18c5f01b2fSopenharmony_ci#include <map> 19c5f01b2fSopenharmony_ci#include <sstream> 20c5f01b2fSopenharmony_ci 21c5f01b2fSopenharmony_ciTEST_CASE("JSON pointers") 22c5f01b2fSopenharmony_ci{ 23c5f01b2fSopenharmony_ci SECTION("errors") 24c5f01b2fSopenharmony_ci { 25c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(json::json_pointer("foo"), 26c5f01b2fSopenharmony_ci "[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'", json::parse_error&); 27c5f01b2fSopenharmony_ci 28c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(json::json_pointer("/~~"), 29c5f01b2fSopenharmony_ci "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); 30c5f01b2fSopenharmony_ci 31c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(json::json_pointer("/~"), 32c5f01b2fSopenharmony_ci "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); 33c5f01b2fSopenharmony_ci 34c5f01b2fSopenharmony_ci json::json_pointer p; 35c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(p.top(), 36c5f01b2fSopenharmony_ci "[json.exception.out_of_range.405] JSON pointer has no parent", json::out_of_range&); 37c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(p.pop_back(), 38c5f01b2fSopenharmony_ci "[json.exception.out_of_range.405] JSON pointer has no parent", json::out_of_range&); 39c5f01b2fSopenharmony_ci 40c5f01b2fSopenharmony_ci SECTION("array index error") 41c5f01b2fSopenharmony_ci { 42c5f01b2fSopenharmony_ci json v = {1, 2, 3, 4}; 43c5f01b2fSopenharmony_ci json::json_pointer ptr("/10e"); 44c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(v[ptr], 45c5f01b2fSopenharmony_ci "[json.exception.out_of_range.404] unresolved reference token '10e'", json::out_of_range&); 46c5f01b2fSopenharmony_ci } 47c5f01b2fSopenharmony_ci } 48c5f01b2fSopenharmony_ci 49c5f01b2fSopenharmony_ci SECTION("examples from RFC 6901") 50c5f01b2fSopenharmony_ci { 51c5f01b2fSopenharmony_ci SECTION("nonconst access") 52c5f01b2fSopenharmony_ci { 53c5f01b2fSopenharmony_ci json j = R"( 54c5f01b2fSopenharmony_ci { 55c5f01b2fSopenharmony_ci "foo": ["bar", "baz"], 56c5f01b2fSopenharmony_ci "": 0, 57c5f01b2fSopenharmony_ci "a/b": 1, 58c5f01b2fSopenharmony_ci "c%d": 2, 59c5f01b2fSopenharmony_ci "e^f": 3, 60c5f01b2fSopenharmony_ci "g|h": 4, 61c5f01b2fSopenharmony_ci "i\\j": 5, 62c5f01b2fSopenharmony_ci "k\"l": 6, 63c5f01b2fSopenharmony_ci " ": 7, 64c5f01b2fSopenharmony_ci "m~n": 8 65c5f01b2fSopenharmony_ci } 66c5f01b2fSopenharmony_ci )"_json; 67c5f01b2fSopenharmony_ci 68c5f01b2fSopenharmony_ci // the whole document 69c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer()] == j); 70c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("")] == j); 71c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer())); 72c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer(""))); 73c5f01b2fSopenharmony_ci 74c5f01b2fSopenharmony_ci // array access 75c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/foo")] == j["foo"]); 76c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/foo"))); 77c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/foo/0")] == j["foo"][0]); 78c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/foo/1")] == j["foo"][1]); 79c5f01b2fSopenharmony_ci CHECK(j["/foo/1"_json_pointer] == j["foo"][1]); 80c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/foo/0"))); 81c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/foo/1"))); 82c5f01b2fSopenharmony_ci CHECK(!j.contains(json::json_pointer("/foo/3"))); 83c5f01b2fSopenharmony_ci CHECK(!j.contains(json::json_pointer("/foo/+"))); 84c5f01b2fSopenharmony_ci CHECK(!j.contains(json::json_pointer("/foo/1+2"))); 85c5f01b2fSopenharmony_ci CHECK(!j.contains(json::json_pointer("/foo/-"))); 86c5f01b2fSopenharmony_ci 87c5f01b2fSopenharmony_ci // checked array access 88c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]); 89c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/foo/1")) == j["foo"][1]); 90c5f01b2fSopenharmony_ci 91c5f01b2fSopenharmony_ci // empty string access 92c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/")] == j[""]); 93c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer(""))); 94c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/"))); 95c5f01b2fSopenharmony_ci 96c5f01b2fSopenharmony_ci // other cases 97c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/ ")] == j[" "]); 98c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/c%d")] == j["c%d"]); 99c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/e^f")] == j["e^f"]); 100c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/g|h")] == j["g|h"]); 101c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/i\\j")] == j["i\\j"]); 102c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/k\"l")] == j["k\"l"]); 103c5f01b2fSopenharmony_ci 104c5f01b2fSopenharmony_ci // contains 105c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/ "))); 106c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/c%d"))); 107c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/e^f"))); 108c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/g|h"))); 109c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/i\\j"))); 110c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/k\"l"))); 111c5f01b2fSopenharmony_ci 112c5f01b2fSopenharmony_ci // checked access 113c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/ ")) == j[" "]); 114c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/c%d")) == j["c%d"]); 115c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/e^f")) == j["e^f"]); 116c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/g|h")) == j["g|h"]); 117c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/i\\j")) == j["i\\j"]); 118c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/k\"l")) == j["k\"l"]); 119c5f01b2fSopenharmony_ci 120c5f01b2fSopenharmony_ci // escaped access 121c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/a~1b")] == j["a/b"]); 122c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]); 123c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/a~1b"))); 124c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/m~0n"))); 125c5f01b2fSopenharmony_ci 126c5f01b2fSopenharmony_ci // unescaped access 127c5f01b2fSopenharmony_ci // access to nonexisting values yield object creation 128c5f01b2fSopenharmony_ci CHECK(!j.contains(json::json_pointer("/a/b"))); 129c5f01b2fSopenharmony_ci CHECK_NOTHROW(j[json::json_pointer("/a/b")] = 42); 130c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/a/b"))); 131c5f01b2fSopenharmony_ci CHECK(j["a"]["b"] == json(42)); 132c5f01b2fSopenharmony_ci 133c5f01b2fSopenharmony_ci CHECK(!j.contains(json::json_pointer("/a/c/1"))); 134c5f01b2fSopenharmony_ci CHECK_NOTHROW(j[json::json_pointer("/a/c/1")] = 42); 135c5f01b2fSopenharmony_ci CHECK(j["a"]["c"] == json({nullptr, 42})); 136c5f01b2fSopenharmony_ci CHECK(j.contains(json::json_pointer("/a/c/1"))); 137c5f01b2fSopenharmony_ci 138c5f01b2fSopenharmony_ci CHECK(!j.contains(json::json_pointer("/a/d/-"))); 139c5f01b2fSopenharmony_ci CHECK_NOTHROW(j[json::json_pointer("/a/d/-")] = 42); 140c5f01b2fSopenharmony_ci CHECK(!j.contains(json::json_pointer("/a/d/-"))); 141c5f01b2fSopenharmony_ci CHECK(j["a"]["d"] == json::array({42})); 142c5f01b2fSopenharmony_ci // "/a/b" works for JSON {"a": {"b": 42}} 143c5f01b2fSopenharmony_ci CHECK(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")] == json(42)); 144c5f01b2fSopenharmony_ci 145c5f01b2fSopenharmony_ci // unresolved access 146c5f01b2fSopenharmony_ci json j_primitive = 1; 147c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_primitive["/foo"_json_pointer], 148c5f01b2fSopenharmony_ci "[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&); 149c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_primitive.at("/foo"_json_pointer), 150c5f01b2fSopenharmony_ci "[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&); 151c5f01b2fSopenharmony_ci CHECK(!j_primitive.contains(json::json_pointer("/foo"))); 152c5f01b2fSopenharmony_ci } 153c5f01b2fSopenharmony_ci 154c5f01b2fSopenharmony_ci SECTION("const access") 155c5f01b2fSopenharmony_ci { 156c5f01b2fSopenharmony_ci const json j = R"( 157c5f01b2fSopenharmony_ci { 158c5f01b2fSopenharmony_ci "foo": ["bar", "baz"], 159c5f01b2fSopenharmony_ci "": 0, 160c5f01b2fSopenharmony_ci "a/b": 1, 161c5f01b2fSopenharmony_ci "c%d": 2, 162c5f01b2fSopenharmony_ci "e^f": 3, 163c5f01b2fSopenharmony_ci "g|h": 4, 164c5f01b2fSopenharmony_ci "i\\j": 5, 165c5f01b2fSopenharmony_ci "k\"l": 6, 166c5f01b2fSopenharmony_ci " ": 7, 167c5f01b2fSopenharmony_ci "m~n": 8 168c5f01b2fSopenharmony_ci } 169c5f01b2fSopenharmony_ci )"_json; 170c5f01b2fSopenharmony_ci 171c5f01b2fSopenharmony_ci // the whole document 172c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer()] == j); 173c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("")] == j); 174c5f01b2fSopenharmony_ci 175c5f01b2fSopenharmony_ci // array access 176c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/foo")] == j["foo"]); 177c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/foo/0")] == j["foo"][0]); 178c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/foo/1")] == j["foo"][1]); 179c5f01b2fSopenharmony_ci CHECK(j["/foo/1"_json_pointer] == j["foo"][1]); 180c5f01b2fSopenharmony_ci 181c5f01b2fSopenharmony_ci // checked array access 182c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]); 183c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/foo/1")) == j["foo"][1]); 184c5f01b2fSopenharmony_ci 185c5f01b2fSopenharmony_ci // empty string access 186c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/")] == j[""]); 187c5f01b2fSopenharmony_ci 188c5f01b2fSopenharmony_ci // other cases 189c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/ ")] == j[" "]); 190c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/c%d")] == j["c%d"]); 191c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/e^f")] == j["e^f"]); 192c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/g|h")] == j["g|h"]); 193c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/i\\j")] == j["i\\j"]); 194c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/k\"l")] == j["k\"l"]); 195c5f01b2fSopenharmony_ci 196c5f01b2fSopenharmony_ci // checked access 197c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/ ")) == j[" "]); 198c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/c%d")) == j["c%d"]); 199c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/e^f")) == j["e^f"]); 200c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/g|h")) == j["g|h"]); 201c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/i\\j")) == j["i\\j"]); 202c5f01b2fSopenharmony_ci CHECK(j.at(json::json_pointer("/k\"l")) == j["k\"l"]); 203c5f01b2fSopenharmony_ci 204c5f01b2fSopenharmony_ci // escaped access 205c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/a~1b")] == j["a/b"]); 206c5f01b2fSopenharmony_ci CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]); 207c5f01b2fSopenharmony_ci 208c5f01b2fSopenharmony_ci // unescaped access 209c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j.at(json::json_pointer("/a/b")), 210c5f01b2fSopenharmony_ci "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&); 211c5f01b2fSopenharmony_ci 212c5f01b2fSopenharmony_ci // unresolved access 213c5f01b2fSopenharmony_ci const json j_primitive = 1; 214c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_primitive["/foo"_json_pointer], 215c5f01b2fSopenharmony_ci "[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&); 216c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_primitive.at("/foo"_json_pointer), 217c5f01b2fSopenharmony_ci "[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&); 218c5f01b2fSopenharmony_ci } 219c5f01b2fSopenharmony_ci 220c5f01b2fSopenharmony_ci SECTION("user-defined string literal") 221c5f01b2fSopenharmony_ci { 222c5f01b2fSopenharmony_ci json j = R"( 223c5f01b2fSopenharmony_ci { 224c5f01b2fSopenharmony_ci "foo": ["bar", "baz"], 225c5f01b2fSopenharmony_ci "": 0, 226c5f01b2fSopenharmony_ci "a/b": 1, 227c5f01b2fSopenharmony_ci "c%d": 2, 228c5f01b2fSopenharmony_ci "e^f": 3, 229c5f01b2fSopenharmony_ci "g|h": 4, 230c5f01b2fSopenharmony_ci "i\\j": 5, 231c5f01b2fSopenharmony_ci "k\"l": 6, 232c5f01b2fSopenharmony_ci " ": 7, 233c5f01b2fSopenharmony_ci "m~n": 8 234c5f01b2fSopenharmony_ci } 235c5f01b2fSopenharmony_ci )"_json; 236c5f01b2fSopenharmony_ci 237c5f01b2fSopenharmony_ci // the whole document 238c5f01b2fSopenharmony_ci CHECK(j[""_json_pointer] == j); 239c5f01b2fSopenharmony_ci CHECK(j.contains(""_json_pointer)); 240c5f01b2fSopenharmony_ci 241c5f01b2fSopenharmony_ci // array access 242c5f01b2fSopenharmony_ci CHECK(j["/foo"_json_pointer] == j["foo"]); 243c5f01b2fSopenharmony_ci CHECK(j["/foo/0"_json_pointer] == j["foo"][0]); 244c5f01b2fSopenharmony_ci CHECK(j["/foo/1"_json_pointer] == j["foo"][1]); 245c5f01b2fSopenharmony_ci CHECK(j.contains("/foo"_json_pointer)); 246c5f01b2fSopenharmony_ci CHECK(j.contains("/foo/0"_json_pointer)); 247c5f01b2fSopenharmony_ci CHECK(j.contains("/foo/1"_json_pointer)); 248c5f01b2fSopenharmony_ci CHECK(!j.contains("/foo/-"_json_pointer)); 249c5f01b2fSopenharmony_ci } 250c5f01b2fSopenharmony_ci } 251c5f01b2fSopenharmony_ci 252c5f01b2fSopenharmony_ci SECTION("array access") 253c5f01b2fSopenharmony_ci { 254c5f01b2fSopenharmony_ci SECTION("nonconst access") 255c5f01b2fSopenharmony_ci { 256c5f01b2fSopenharmony_ci json j = {1, 2, 3}; 257c5f01b2fSopenharmony_ci const json j_const = j; 258c5f01b2fSopenharmony_ci 259c5f01b2fSopenharmony_ci // check reading access 260c5f01b2fSopenharmony_ci CHECK(j["/0"_json_pointer] == j[0]); 261c5f01b2fSopenharmony_ci CHECK(j["/1"_json_pointer] == j[1]); 262c5f01b2fSopenharmony_ci CHECK(j["/2"_json_pointer] == j[2]); 263c5f01b2fSopenharmony_ci 264c5f01b2fSopenharmony_ci // assign to existing index 265c5f01b2fSopenharmony_ci j["/1"_json_pointer] = 13; 266c5f01b2fSopenharmony_ci CHECK(j[1] == json(13)); 267c5f01b2fSopenharmony_ci 268c5f01b2fSopenharmony_ci // assign to nonexisting index 269c5f01b2fSopenharmony_ci j["/3"_json_pointer] = 33; 270c5f01b2fSopenharmony_ci CHECK(j[3] == json(33)); 271c5f01b2fSopenharmony_ci 272c5f01b2fSopenharmony_ci // assign to nonexisting index (with gap) 273c5f01b2fSopenharmony_ci j["/5"_json_pointer] = 55; 274c5f01b2fSopenharmony_ci CHECK(j == json({1, 13, 3, 33, nullptr, 55})); 275c5f01b2fSopenharmony_ci 276c5f01b2fSopenharmony_ci // error with leading 0 277c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j["/01"_json_pointer], 278c5f01b2fSopenharmony_ci "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&); 279c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const["/01"_json_pointer], 280c5f01b2fSopenharmony_ci "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&); 281c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j.at("/01"_json_pointer), 282c5f01b2fSopenharmony_ci "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&); 283c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const.at("/01"_json_pointer), 284c5f01b2fSopenharmony_ci "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&); 285c5f01b2fSopenharmony_ci 286c5f01b2fSopenharmony_ci CHECK(!j.contains("/01"_json_pointer)); 287c5f01b2fSopenharmony_ci CHECK(!j.contains("/01"_json_pointer)); 288c5f01b2fSopenharmony_ci CHECK(!j_const.contains("/01"_json_pointer)); 289c5f01b2fSopenharmony_ci CHECK(!j_const.contains("/01"_json_pointer)); 290c5f01b2fSopenharmony_ci 291c5f01b2fSopenharmony_ci // error with incorrect numbers 292c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j["/one"_json_pointer] = 1, 293c5f01b2fSopenharmony_ci "[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); 294c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const["/one"_json_pointer] == 1, 295c5f01b2fSopenharmony_ci "[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); 296c5f01b2fSopenharmony_ci 297c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j.at("/one"_json_pointer) = 1, 298c5f01b2fSopenharmony_ci "[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); 299c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const.at("/one"_json_pointer) == 1, 300c5f01b2fSopenharmony_ci "[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); 301c5f01b2fSopenharmony_ci 302c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j["/+1"_json_pointer] = 1, 303c5f01b2fSopenharmony_ci "[json.exception.parse_error.109] parse error: array index '+1' is not a number", json::parse_error&); 304c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const["/+1"_json_pointer] == 1, 305c5f01b2fSopenharmony_ci "[json.exception.parse_error.109] parse error: array index '+1' is not a number", json::parse_error&); 306c5f01b2fSopenharmony_ci 307c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j["/1+1"_json_pointer] = 1, 308c5f01b2fSopenharmony_ci "[json.exception.out_of_range.404] unresolved reference token '1+1'", json::out_of_range&); 309c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const["/1+1"_json_pointer] == 1, 310c5f01b2fSopenharmony_ci "[json.exception.out_of_range.404] unresolved reference token '1+1'", json::out_of_range&); 311c5f01b2fSopenharmony_ci 312c5f01b2fSopenharmony_ci { 313c5f01b2fSopenharmony_ci auto too_large_index = std::to_string((std::numeric_limits<unsigned long long>::max)()) + "1"; 314c5f01b2fSopenharmony_ci json::json_pointer jp(std::string("/") + too_large_index); 315c5f01b2fSopenharmony_ci std::string throw_msg = std::string("[json.exception.out_of_range.404] unresolved reference token '") + too_large_index + "'"; 316c5f01b2fSopenharmony_ci 317c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&); 318c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&); 319c5f01b2fSopenharmony_ci } 320c5f01b2fSopenharmony_ci 321c5f01b2fSopenharmony_ci // on some machines, the check below is not constant 322c5f01b2fSopenharmony_ci DOCTEST_MSVC_SUPPRESS_WARNING_PUSH 323c5f01b2fSopenharmony_ci DOCTEST_MSVC_SUPPRESS_WARNING(4127) 324c5f01b2fSopenharmony_ci 325c5f01b2fSopenharmony_ci if (sizeof(typename json::size_type) < sizeof(unsigned long long)) 326c5f01b2fSopenharmony_ci { 327c5f01b2fSopenharmony_ci auto size_type_max_uul = static_cast<unsigned long long>((std::numeric_limits<json::size_type>::max)()); 328c5f01b2fSopenharmony_ci auto too_large_index = std::to_string(size_type_max_uul); 329c5f01b2fSopenharmony_ci json::json_pointer jp(std::string("/") + too_large_index); 330c5f01b2fSopenharmony_ci std::string throw_msg = std::string("[json.exception.out_of_range.410] array index ") + too_large_index + " exceeds size_type"; 331c5f01b2fSopenharmony_ci 332c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&); 333c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&); 334c5f01b2fSopenharmony_ci } 335c5f01b2fSopenharmony_ci 336c5f01b2fSopenharmony_ci DOCTEST_MSVC_SUPPRESS_WARNING_POP 337c5f01b2fSopenharmony_ci 338c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j.at("/one"_json_pointer) = 1, 339c5f01b2fSopenharmony_ci "[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); 340c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const.at("/one"_json_pointer) == 1, 341c5f01b2fSopenharmony_ci "[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); 342c5f01b2fSopenharmony_ci 343c5f01b2fSopenharmony_ci CHECK(!j.contains("/one"_json_pointer)); 344c5f01b2fSopenharmony_ci CHECK(!j.contains("/one"_json_pointer)); 345c5f01b2fSopenharmony_ci CHECK(!j_const.contains("/one"_json_pointer)); 346c5f01b2fSopenharmony_ci CHECK(!j_const.contains("/one"_json_pointer)); 347c5f01b2fSopenharmony_ci 348c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), 349c5f01b2fSopenharmony_ci "[json.exception.parse_error.109] parse error: array index 'three' is not a number", json::parse_error&); 350c5f01b2fSopenharmony_ci 351c5f01b2fSopenharmony_ci // assign to "-" 352c5f01b2fSopenharmony_ci j["/-"_json_pointer] = 99; 353c5f01b2fSopenharmony_ci CHECK(j == json({1, 13, 3, 33, nullptr, 55, 99})); 354c5f01b2fSopenharmony_ci 355c5f01b2fSopenharmony_ci // error when using "-" in const object 356c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const["/-"_json_pointer], 357c5f01b2fSopenharmony_ci "[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&); 358c5f01b2fSopenharmony_ci CHECK(!j_const.contains("/-"_json_pointer)); 359c5f01b2fSopenharmony_ci 360c5f01b2fSopenharmony_ci // error when using "-" with at 361c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j.at("/-"_json_pointer), 362c5f01b2fSopenharmony_ci "[json.exception.out_of_range.402] array index '-' (7) is out of range", json::out_of_range&); 363c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_const.at("/-"_json_pointer), 364c5f01b2fSopenharmony_ci "[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&); 365c5f01b2fSopenharmony_ci CHECK(!j_const.contains("/-"_json_pointer)); 366c5f01b2fSopenharmony_ci } 367c5f01b2fSopenharmony_ci 368c5f01b2fSopenharmony_ci SECTION("const access") 369c5f01b2fSopenharmony_ci { 370c5f01b2fSopenharmony_ci const json j = {1, 2, 3}; 371c5f01b2fSopenharmony_ci 372c5f01b2fSopenharmony_ci // check reading access 373c5f01b2fSopenharmony_ci CHECK(j["/0"_json_pointer] == j[0]); 374c5f01b2fSopenharmony_ci CHECK(j["/1"_json_pointer] == j[1]); 375c5f01b2fSopenharmony_ci CHECK(j["/2"_json_pointer] == j[2]); 376c5f01b2fSopenharmony_ci 377c5f01b2fSopenharmony_ci // assign to nonexisting index 378c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j.at("/3"_json_pointer), 379c5f01b2fSopenharmony_ci "[json.exception.out_of_range.401] array index 3 is out of range", json::out_of_range&); 380c5f01b2fSopenharmony_ci CHECK(!j.contains("/3"_json_pointer)); 381c5f01b2fSopenharmony_ci 382c5f01b2fSopenharmony_ci // assign to nonexisting index (with gap) 383c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j.at("/5"_json_pointer), 384c5f01b2fSopenharmony_ci "[json.exception.out_of_range.401] array index 5 is out of range", json::out_of_range&); 385c5f01b2fSopenharmony_ci CHECK(!j.contains("/5"_json_pointer)); 386c5f01b2fSopenharmony_ci 387c5f01b2fSopenharmony_ci // assign to "-" 388c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j["/-"_json_pointer], 389c5f01b2fSopenharmony_ci "[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&); 390c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j.at("/-"_json_pointer), 391c5f01b2fSopenharmony_ci "[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&); 392c5f01b2fSopenharmony_ci CHECK(!j.contains("/-"_json_pointer)); 393c5f01b2fSopenharmony_ci } 394c5f01b2fSopenharmony_ci } 395c5f01b2fSopenharmony_ci 396c5f01b2fSopenharmony_ci SECTION("flatten") 397c5f01b2fSopenharmony_ci { 398c5f01b2fSopenharmony_ci json j = 399c5f01b2fSopenharmony_ci { 400c5f01b2fSopenharmony_ci {"pi", 3.141}, 401c5f01b2fSopenharmony_ci {"happy", true}, 402c5f01b2fSopenharmony_ci {"name", "Niels"}, 403c5f01b2fSopenharmony_ci {"nothing", nullptr}, 404c5f01b2fSopenharmony_ci { 405c5f01b2fSopenharmony_ci "answer", { 406c5f01b2fSopenharmony_ci {"everything", 42} 407c5f01b2fSopenharmony_ci } 408c5f01b2fSopenharmony_ci }, 409c5f01b2fSopenharmony_ci {"list", {1, 0, 2}}, 410c5f01b2fSopenharmony_ci { 411c5f01b2fSopenharmony_ci "object", { 412c5f01b2fSopenharmony_ci {"currency", "USD"}, 413c5f01b2fSopenharmony_ci {"value", 42.99}, 414c5f01b2fSopenharmony_ci {"", "empty string"}, 415c5f01b2fSopenharmony_ci {"/", "slash"}, 416c5f01b2fSopenharmony_ci {"~", "tilde"}, 417c5f01b2fSopenharmony_ci {"~1", "tilde1"} 418c5f01b2fSopenharmony_ci } 419c5f01b2fSopenharmony_ci } 420c5f01b2fSopenharmony_ci }; 421c5f01b2fSopenharmony_ci 422c5f01b2fSopenharmony_ci json j_flatten = 423c5f01b2fSopenharmony_ci { 424c5f01b2fSopenharmony_ci {"/pi", 3.141}, 425c5f01b2fSopenharmony_ci {"/happy", true}, 426c5f01b2fSopenharmony_ci {"/name", "Niels"}, 427c5f01b2fSopenharmony_ci {"/nothing", nullptr}, 428c5f01b2fSopenharmony_ci {"/answer/everything", 42}, 429c5f01b2fSopenharmony_ci {"/list/0", 1}, 430c5f01b2fSopenharmony_ci {"/list/1", 0}, 431c5f01b2fSopenharmony_ci {"/list/2", 2}, 432c5f01b2fSopenharmony_ci {"/object/currency", "USD"}, 433c5f01b2fSopenharmony_ci {"/object/value", 42.99}, 434c5f01b2fSopenharmony_ci {"/object/", "empty string"}, 435c5f01b2fSopenharmony_ci {"/object/~1", "slash"}, 436c5f01b2fSopenharmony_ci {"/object/~0", "tilde"}, 437c5f01b2fSopenharmony_ci {"/object/~01", "tilde1"} 438c5f01b2fSopenharmony_ci }; 439c5f01b2fSopenharmony_ci 440c5f01b2fSopenharmony_ci // check if flattened result is as expected 441c5f01b2fSopenharmony_ci CHECK(j.flatten() == j_flatten); 442c5f01b2fSopenharmony_ci 443c5f01b2fSopenharmony_ci // check if unflattened result is as expected 444c5f01b2fSopenharmony_ci CHECK(j_flatten.unflatten() == j); 445c5f01b2fSopenharmony_ci 446c5f01b2fSopenharmony_ci // error for nonobjects 447c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(json(1).unflatten(), 448c5f01b2fSopenharmony_ci "[json.exception.type_error.314] only objects can be unflattened", json::type_error&); 449c5f01b2fSopenharmony_ci 450c5f01b2fSopenharmony_ci // error for nonprimitve values 451c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS 452c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(json({{"/1", {1, 2, 3}}}).unflatten(), "[json.exception.type_error.315] (/~11) values in object must be primitive", json::type_error&); 453c5f01b2fSopenharmony_ci#else 454c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(json({{"/1", {1, 2, 3}}}).unflatten(), "[json.exception.type_error.315] values in object must be primitive", json::type_error&); 455c5f01b2fSopenharmony_ci#endif 456c5f01b2fSopenharmony_ci 457c5f01b2fSopenharmony_ci // error for conflicting values 458c5f01b2fSopenharmony_ci json j_error = {{"", 42}, {"/foo", 17}}; 459c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(j_error.unflatten(), 460c5f01b2fSopenharmony_ci "[json.exception.type_error.313] invalid value to unflatten", json::type_error&); 461c5f01b2fSopenharmony_ci 462c5f01b2fSopenharmony_ci // explicit roundtrip check 463c5f01b2fSopenharmony_ci CHECK(j.flatten().unflatten() == j); 464c5f01b2fSopenharmony_ci 465c5f01b2fSopenharmony_ci // roundtrip for primitive values 466c5f01b2fSopenharmony_ci json j_null; 467c5f01b2fSopenharmony_ci CHECK(j_null.flatten().unflatten() == j_null); 468c5f01b2fSopenharmony_ci json j_number = 42; 469c5f01b2fSopenharmony_ci CHECK(j_number.flatten().unflatten() == j_number); 470c5f01b2fSopenharmony_ci json j_boolean = false; 471c5f01b2fSopenharmony_ci CHECK(j_boolean.flatten().unflatten() == j_boolean); 472c5f01b2fSopenharmony_ci json j_string = "foo"; 473c5f01b2fSopenharmony_ci CHECK(j_string.flatten().unflatten() == j_string); 474c5f01b2fSopenharmony_ci 475c5f01b2fSopenharmony_ci // roundtrip for empty structured values (will be unflattened to null) 476c5f01b2fSopenharmony_ci json j_array(json::value_t::array); 477c5f01b2fSopenharmony_ci CHECK(j_array.flatten().unflatten() == json()); 478c5f01b2fSopenharmony_ci json j_object(json::value_t::object); 479c5f01b2fSopenharmony_ci CHECK(j_object.flatten().unflatten() == json()); 480c5f01b2fSopenharmony_ci } 481c5f01b2fSopenharmony_ci 482c5f01b2fSopenharmony_ci SECTION("string representation") 483c5f01b2fSopenharmony_ci { 484c5f01b2fSopenharmony_ci for (const auto* ptr_str : 485c5f01b2fSopenharmony_ci {"", "/foo", "/foo/0", "/", "/a~1b", "/c%d", "/e^f", "/g|h", "/i\\j", "/k\"l", "/ ", "/m~0n" 486c5f01b2fSopenharmony_ci }) 487c5f01b2fSopenharmony_ci { 488c5f01b2fSopenharmony_ci json::json_pointer ptr(ptr_str); 489c5f01b2fSopenharmony_ci std::stringstream ss; 490c5f01b2fSopenharmony_ci ss << ptr; 491c5f01b2fSopenharmony_ci CHECK(ptr.to_string() == ptr_str); 492c5f01b2fSopenharmony_ci CHECK(std::string(ptr) == ptr_str); 493c5f01b2fSopenharmony_ci CHECK(ss.str() == ptr_str); 494c5f01b2fSopenharmony_ci } 495c5f01b2fSopenharmony_ci } 496c5f01b2fSopenharmony_ci 497c5f01b2fSopenharmony_ci SECTION("conversion") 498c5f01b2fSopenharmony_ci { 499c5f01b2fSopenharmony_ci SECTION("array") 500c5f01b2fSopenharmony_ci { 501c5f01b2fSopenharmony_ci json j; 502c5f01b2fSopenharmony_ci // all numbers -> array 503c5f01b2fSopenharmony_ci j["/12"_json_pointer] = 0; 504c5f01b2fSopenharmony_ci CHECK(j.is_array()); 505c5f01b2fSopenharmony_ci } 506c5f01b2fSopenharmony_ci 507c5f01b2fSopenharmony_ci SECTION("object") 508c5f01b2fSopenharmony_ci { 509c5f01b2fSopenharmony_ci json j; 510c5f01b2fSopenharmony_ci // contains a number, but is not a number -> object 511c5f01b2fSopenharmony_ci j["/a12"_json_pointer] = 0; 512c5f01b2fSopenharmony_ci CHECK(j.is_object()); 513c5f01b2fSopenharmony_ci } 514c5f01b2fSopenharmony_ci } 515c5f01b2fSopenharmony_ci 516c5f01b2fSopenharmony_ci SECTION("empty, push, pop and parent") 517c5f01b2fSopenharmony_ci { 518c5f01b2fSopenharmony_ci const json j = 519c5f01b2fSopenharmony_ci { 520c5f01b2fSopenharmony_ci {"", "Hello"}, 521c5f01b2fSopenharmony_ci {"pi", 3.141}, 522c5f01b2fSopenharmony_ci {"happy", true}, 523c5f01b2fSopenharmony_ci {"name", "Niels"}, 524c5f01b2fSopenharmony_ci {"nothing", nullptr}, 525c5f01b2fSopenharmony_ci { 526c5f01b2fSopenharmony_ci "answer", { 527c5f01b2fSopenharmony_ci {"everything", 42} 528c5f01b2fSopenharmony_ci } 529c5f01b2fSopenharmony_ci }, 530c5f01b2fSopenharmony_ci {"list", {1, 0, 2}}, 531c5f01b2fSopenharmony_ci { 532c5f01b2fSopenharmony_ci "object", { 533c5f01b2fSopenharmony_ci {"currency", "USD"}, 534c5f01b2fSopenharmony_ci {"value", 42.99}, 535c5f01b2fSopenharmony_ci {"", "empty string"}, 536c5f01b2fSopenharmony_ci {"/", "slash"}, 537c5f01b2fSopenharmony_ci {"~", "tilde"}, 538c5f01b2fSopenharmony_ci {"~1", "tilde1"} 539c5f01b2fSopenharmony_ci } 540c5f01b2fSopenharmony_ci } 541c5f01b2fSopenharmony_ci }; 542c5f01b2fSopenharmony_ci 543c5f01b2fSopenharmony_ci // empty json_pointer returns the root JSON-object 544c5f01b2fSopenharmony_ci auto ptr = ""_json_pointer; 545c5f01b2fSopenharmony_ci CHECK(ptr.empty()); 546c5f01b2fSopenharmony_ci CHECK(j[ptr] == j); 547c5f01b2fSopenharmony_ci 548c5f01b2fSopenharmony_ci // simple field access 549c5f01b2fSopenharmony_ci ptr.push_back("pi"); 550c5f01b2fSopenharmony_ci CHECK(!ptr.empty()); 551c5f01b2fSopenharmony_ci CHECK(j[ptr] == j["pi"]); 552c5f01b2fSopenharmony_ci 553c5f01b2fSopenharmony_ci ptr.pop_back(); 554c5f01b2fSopenharmony_ci CHECK(ptr.empty()); 555c5f01b2fSopenharmony_ci CHECK(j[ptr] == j); 556c5f01b2fSopenharmony_ci 557c5f01b2fSopenharmony_ci // object and children access 558c5f01b2fSopenharmony_ci const std::string answer("answer"); 559c5f01b2fSopenharmony_ci ptr.push_back(answer); 560c5f01b2fSopenharmony_ci ptr.push_back("everything"); 561c5f01b2fSopenharmony_ci CHECK(!ptr.empty()); 562c5f01b2fSopenharmony_ci CHECK(j[ptr] == j["answer"]["everything"]); 563c5f01b2fSopenharmony_ci 564c5f01b2fSopenharmony_ci // check access via const pointer 565c5f01b2fSopenharmony_ci const auto cptr = ptr; 566c5f01b2fSopenharmony_ci CHECK(cptr.back() == "everything"); 567c5f01b2fSopenharmony_ci 568c5f01b2fSopenharmony_ci ptr.pop_back(); 569c5f01b2fSopenharmony_ci ptr.pop_back(); 570c5f01b2fSopenharmony_ci CHECK(ptr.empty()); 571c5f01b2fSopenharmony_ci CHECK(j[ptr] == j); 572c5f01b2fSopenharmony_ci 573c5f01b2fSopenharmony_ci // push key which has to be encoded 574c5f01b2fSopenharmony_ci ptr.push_back("object"); 575c5f01b2fSopenharmony_ci ptr.push_back("/"); 576c5f01b2fSopenharmony_ci CHECK(j[ptr] == j["object"]["/"]); 577c5f01b2fSopenharmony_ci CHECK(ptr.to_string() == "/object/~1"); 578c5f01b2fSopenharmony_ci 579c5f01b2fSopenharmony_ci CHECK(j[ptr.parent_pointer()] == j["object"]); 580c5f01b2fSopenharmony_ci ptr = ptr.parent_pointer().parent_pointer(); 581c5f01b2fSopenharmony_ci CHECK(ptr.empty()); 582c5f01b2fSopenharmony_ci CHECK(j[ptr] == j); 583c5f01b2fSopenharmony_ci // parent-pointer of the empty json_pointer is empty 584c5f01b2fSopenharmony_ci ptr = ptr.parent_pointer(); 585c5f01b2fSopenharmony_ci CHECK(ptr.empty()); 586c5f01b2fSopenharmony_ci CHECK(j[ptr] == j); 587c5f01b2fSopenharmony_ci 588c5f01b2fSopenharmony_ci CHECK_THROWS_WITH(ptr.pop_back(), 589c5f01b2fSopenharmony_ci "[json.exception.out_of_range.405] JSON pointer has no parent"); 590c5f01b2fSopenharmony_ci } 591c5f01b2fSopenharmony_ci 592c5f01b2fSopenharmony_ci SECTION("operators") 593c5f01b2fSopenharmony_ci { 594c5f01b2fSopenharmony_ci const json j = 595c5f01b2fSopenharmony_ci { 596c5f01b2fSopenharmony_ci {"", "Hello"}, 597c5f01b2fSopenharmony_ci {"pi", 3.141}, 598c5f01b2fSopenharmony_ci {"happy", true}, 599c5f01b2fSopenharmony_ci {"name", "Niels"}, 600c5f01b2fSopenharmony_ci {"nothing", nullptr}, 601c5f01b2fSopenharmony_ci { 602c5f01b2fSopenharmony_ci "answer", { 603c5f01b2fSopenharmony_ci {"everything", 42} 604c5f01b2fSopenharmony_ci } 605c5f01b2fSopenharmony_ci }, 606c5f01b2fSopenharmony_ci {"list", {1, 0, 2}}, 607c5f01b2fSopenharmony_ci { 608c5f01b2fSopenharmony_ci "object", { 609c5f01b2fSopenharmony_ci {"currency", "USD"}, 610c5f01b2fSopenharmony_ci {"value", 42.99}, 611c5f01b2fSopenharmony_ci {"", "empty string"}, 612c5f01b2fSopenharmony_ci {"/", "slash"}, 613c5f01b2fSopenharmony_ci {"~", "tilde"}, 614c5f01b2fSopenharmony_ci {"~1", "tilde1"} 615c5f01b2fSopenharmony_ci } 616c5f01b2fSopenharmony_ci } 617c5f01b2fSopenharmony_ci }; 618c5f01b2fSopenharmony_ci 619c5f01b2fSopenharmony_ci // empty json_pointer returns the root JSON-object 620c5f01b2fSopenharmony_ci auto ptr = ""_json_pointer; 621c5f01b2fSopenharmony_ci CHECK(j[ptr] == j); 622c5f01b2fSopenharmony_ci 623c5f01b2fSopenharmony_ci // simple field access 624c5f01b2fSopenharmony_ci ptr = ptr / "pi"; 625c5f01b2fSopenharmony_ci CHECK(j[ptr] == j["pi"]); 626c5f01b2fSopenharmony_ci 627c5f01b2fSopenharmony_ci ptr.pop_back(); 628c5f01b2fSopenharmony_ci CHECK(j[ptr] == j); 629c5f01b2fSopenharmony_ci 630c5f01b2fSopenharmony_ci // object and children access 631c5f01b2fSopenharmony_ci const std::string answer("answer"); 632c5f01b2fSopenharmony_ci ptr /= answer; 633c5f01b2fSopenharmony_ci ptr = ptr / "everything"; 634c5f01b2fSopenharmony_ci CHECK(j[ptr] == j["answer"]["everything"]); 635c5f01b2fSopenharmony_ci 636c5f01b2fSopenharmony_ci ptr.pop_back(); 637c5f01b2fSopenharmony_ci ptr.pop_back(); 638c5f01b2fSopenharmony_ci CHECK(j[ptr] == j); 639c5f01b2fSopenharmony_ci 640c5f01b2fSopenharmony_ci CHECK(ptr / ""_json_pointer == ptr); 641c5f01b2fSopenharmony_ci CHECK(j["/answer"_json_pointer / "/everything"_json_pointer] == j["answer"]["everything"]); 642c5f01b2fSopenharmony_ci 643c5f01b2fSopenharmony_ci // list children access 644c5f01b2fSopenharmony_ci CHECK(j["/list"_json_pointer / 1] == j["list"][1]); 645c5f01b2fSopenharmony_ci 646c5f01b2fSopenharmony_ci // push key which has to be encoded 647c5f01b2fSopenharmony_ci ptr /= "object"; 648c5f01b2fSopenharmony_ci ptr = ptr / "/"; 649c5f01b2fSopenharmony_ci CHECK(j[ptr] == j["object"]["/"]); 650c5f01b2fSopenharmony_ci CHECK(ptr.to_string() == "/object/~1"); 651c5f01b2fSopenharmony_ci } 652c5f01b2fSopenharmony_ci 653c5f01b2fSopenharmony_ci SECTION("equality comparison") 654c5f01b2fSopenharmony_ci { 655c5f01b2fSopenharmony_ci const char* ptr_cpstring = "/foo/bar"; 656c5f01b2fSopenharmony_ci const char ptr_castring[] = "/foo/bar"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) 657c5f01b2fSopenharmony_ci std::string ptr_string{"/foo/bar"}; 658c5f01b2fSopenharmony_ci auto ptr1 = json::json_pointer(ptr_string); 659c5f01b2fSopenharmony_ci auto ptr2 = json::json_pointer(ptr_string); 660c5f01b2fSopenharmony_ci 661c5f01b2fSopenharmony_ci // build with C++20 to test rewritten candidates 662c5f01b2fSopenharmony_ci // JSON_HAS_CPP_20 663c5f01b2fSopenharmony_ci 664c5f01b2fSopenharmony_ci CHECK(ptr1 == ptr2); 665c5f01b2fSopenharmony_ci 666c5f01b2fSopenharmony_ci CHECK(ptr1 == "/foo/bar"); 667c5f01b2fSopenharmony_ci CHECK(ptr1 == ptr_cpstring); 668c5f01b2fSopenharmony_ci CHECK(ptr1 == ptr_castring); 669c5f01b2fSopenharmony_ci CHECK(ptr1 == ptr_string); 670c5f01b2fSopenharmony_ci 671c5f01b2fSopenharmony_ci CHECK("/foo/bar" == ptr1); 672c5f01b2fSopenharmony_ci CHECK(ptr_cpstring == ptr1); 673c5f01b2fSopenharmony_ci CHECK(ptr_castring == ptr1); 674c5f01b2fSopenharmony_ci CHECK(ptr_string == ptr1); 675c5f01b2fSopenharmony_ci 676c5f01b2fSopenharmony_ci CHECK_FALSE(ptr1 != ptr2); 677c5f01b2fSopenharmony_ci 678c5f01b2fSopenharmony_ci CHECK_FALSE(ptr1 != "/foo/bar"); 679c5f01b2fSopenharmony_ci CHECK_FALSE(ptr1 != ptr_cpstring); 680c5f01b2fSopenharmony_ci CHECK_FALSE(ptr1 != ptr_castring); 681c5f01b2fSopenharmony_ci CHECK_FALSE(ptr1 != ptr_string); 682c5f01b2fSopenharmony_ci 683c5f01b2fSopenharmony_ci CHECK_FALSE("/foo/bar" != ptr1); 684c5f01b2fSopenharmony_ci CHECK_FALSE(ptr_cpstring != ptr1); 685c5f01b2fSopenharmony_ci CHECK_FALSE(ptr_castring != ptr1); 686c5f01b2fSopenharmony_ci CHECK_FALSE(ptr_string != ptr1); 687c5f01b2fSopenharmony_ci 688c5f01b2fSopenharmony_ci SECTION("exceptions") 689c5f01b2fSopenharmony_ci { 690c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(ptr1 == "foo", 691c5f01b2fSopenharmony_ci "[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'", json::parse_error&); 692c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS("foo" == ptr1, 693c5f01b2fSopenharmony_ci "[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'", json::parse_error&); 694c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS(ptr1 == "/~~", 695c5f01b2fSopenharmony_ci "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); 696c5f01b2fSopenharmony_ci CHECK_THROWS_WITH_AS("/~~" == ptr1, 697c5f01b2fSopenharmony_ci "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); 698c5f01b2fSopenharmony_ci } 699c5f01b2fSopenharmony_ci } 700c5f01b2fSopenharmony_ci 701c5f01b2fSopenharmony_ci SECTION("less-than comparison") 702c5f01b2fSopenharmony_ci { 703c5f01b2fSopenharmony_ci auto ptr1 = json::json_pointer("/foo/a"); 704c5f01b2fSopenharmony_ci auto ptr2 = json::json_pointer("/foo/b"); 705c5f01b2fSopenharmony_ci 706c5f01b2fSopenharmony_ci CHECK(ptr1 < ptr2); 707c5f01b2fSopenharmony_ci CHECK_FALSE(ptr2 < ptr1); 708c5f01b2fSopenharmony_ci 709c5f01b2fSopenharmony_ci // build with C++20 710c5f01b2fSopenharmony_ci // JSON_HAS_CPP_20 711c5f01b2fSopenharmony_ci#if JSON_HAS_THREE_WAY_COMPARISON 712c5f01b2fSopenharmony_ci CHECK((ptr1 <=> ptr2) == std::strong_ordering::less); // *NOPAD* 713c5f01b2fSopenharmony_ci CHECK(ptr2 > ptr1); 714c5f01b2fSopenharmony_ci#endif 715c5f01b2fSopenharmony_ci } 716c5f01b2fSopenharmony_ci 717c5f01b2fSopenharmony_ci SECTION("usable as map key") 718c5f01b2fSopenharmony_ci { 719c5f01b2fSopenharmony_ci auto ptr = json::json_pointer("/foo"); 720c5f01b2fSopenharmony_ci std::map<json::json_pointer, int> m; 721c5f01b2fSopenharmony_ci 722c5f01b2fSopenharmony_ci m[ptr] = 42; 723c5f01b2fSopenharmony_ci 724c5f01b2fSopenharmony_ci CHECK(m.find(ptr) != m.end()); 725c5f01b2fSopenharmony_ci } 726c5f01b2fSopenharmony_ci 727c5f01b2fSopenharmony_ci SECTION("backwards compatibility and mixing") 728c5f01b2fSopenharmony_ci { 729c5f01b2fSopenharmony_ci json j = R"( 730c5f01b2fSopenharmony_ci { 731c5f01b2fSopenharmony_ci "foo": ["bar", "baz"] 732c5f01b2fSopenharmony_ci } 733c5f01b2fSopenharmony_ci )"_json; 734c5f01b2fSopenharmony_ci 735c5f01b2fSopenharmony_ci using nlohmann::ordered_json; 736c5f01b2fSopenharmony_ci using json_ptr_str = nlohmann::json_pointer<std::string>; 737c5f01b2fSopenharmony_ci using json_ptr_j = nlohmann::json_pointer<json>; 738c5f01b2fSopenharmony_ci using json_ptr_oj = nlohmann::json_pointer<ordered_json>; 739c5f01b2fSopenharmony_ci 740c5f01b2fSopenharmony_ci CHECK(std::is_same<json_ptr_str::string_t, json::json_pointer::string_t>::value); 741c5f01b2fSopenharmony_ci CHECK(std::is_same<json_ptr_str::string_t, ordered_json::json_pointer::string_t>::value); 742c5f01b2fSopenharmony_ci CHECK(std::is_same<json_ptr_str::string_t, json_ptr_j::string_t>::value); 743c5f01b2fSopenharmony_ci CHECK(std::is_same<json_ptr_str::string_t, json_ptr_oj::string_t>::value); 744c5f01b2fSopenharmony_ci 745c5f01b2fSopenharmony_ci std::string ptr_string{"/foo/0"}; 746c5f01b2fSopenharmony_ci json_ptr_str ptr{ptr_string}; 747c5f01b2fSopenharmony_ci json_ptr_j ptr_j{ptr_string}; 748c5f01b2fSopenharmony_ci json_ptr_oj ptr_oj{ptr_string}; 749c5f01b2fSopenharmony_ci 750c5f01b2fSopenharmony_ci CHECK(j.contains(ptr)); 751c5f01b2fSopenharmony_ci CHECK(j.contains(ptr_j)); 752c5f01b2fSopenharmony_ci CHECK(j.contains(ptr_oj)); 753c5f01b2fSopenharmony_ci 754c5f01b2fSopenharmony_ci CHECK(j.at(ptr) == j.at(ptr_j)); 755c5f01b2fSopenharmony_ci CHECK(j.at(ptr) == j.at(ptr_oj)); 756c5f01b2fSopenharmony_ci 757c5f01b2fSopenharmony_ci CHECK(j[ptr] == j[ptr_j]); 758c5f01b2fSopenharmony_ci CHECK(j[ptr] == j[ptr_oj]); 759c5f01b2fSopenharmony_ci 760c5f01b2fSopenharmony_ci CHECK(j.value(ptr, "x") == j.value(ptr_j, "x")); 761c5f01b2fSopenharmony_ci CHECK(j.value(ptr, "x") == j.value(ptr_oj, "x")); 762c5f01b2fSopenharmony_ci 763c5f01b2fSopenharmony_ci CHECK(ptr == ptr_j); 764c5f01b2fSopenharmony_ci CHECK(ptr == ptr_oj); 765c5f01b2fSopenharmony_ci CHECK_FALSE(ptr != ptr_j); 766c5f01b2fSopenharmony_ci CHECK_FALSE(ptr != ptr_oj); 767c5f01b2fSopenharmony_ci 768c5f01b2fSopenharmony_ci SECTION("equality comparison") 769c5f01b2fSopenharmony_ci { 770c5f01b2fSopenharmony_ci // build with C++20 to test rewritten candidates 771c5f01b2fSopenharmony_ci // JSON_HAS_CPP_20 772c5f01b2fSopenharmony_ci 773c5f01b2fSopenharmony_ci CHECK(ptr == ptr_j); 774c5f01b2fSopenharmony_ci CHECK(ptr == ptr_oj); 775c5f01b2fSopenharmony_ci CHECK(ptr_j == ptr); 776c5f01b2fSopenharmony_ci CHECK(ptr_j == ptr_oj); 777c5f01b2fSopenharmony_ci CHECK(ptr_oj == ptr_j); 778c5f01b2fSopenharmony_ci CHECK(ptr_oj == ptr); 779c5f01b2fSopenharmony_ci 780c5f01b2fSopenharmony_ci CHECK_FALSE(ptr != ptr_j); 781c5f01b2fSopenharmony_ci CHECK_FALSE(ptr != ptr_oj); 782c5f01b2fSopenharmony_ci CHECK_FALSE(ptr_j != ptr); 783c5f01b2fSopenharmony_ci CHECK_FALSE(ptr_j != ptr_oj); 784c5f01b2fSopenharmony_ci CHECK_FALSE(ptr_oj != ptr_j); 785c5f01b2fSopenharmony_ci CHECK_FALSE(ptr_oj != ptr); 786c5f01b2fSopenharmony_ci } 787c5f01b2fSopenharmony_ci } 788c5f01b2fSopenharmony_ci} 789