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