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#include <nlohmann/json.hpp>
12c5f01b2fSopenharmony_ciusing nlohmann::json;
13c5f01b2fSopenharmony_ci#ifdef JSON_TEST_NO_GLOBAL_UDLS
14c5f01b2fSopenharmony_ci    using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
15c5f01b2fSopenharmony_ci#endif
16c5f01b2fSopenharmony_ci
17c5f01b2fSopenharmony_ci#include <fstream>
18c5f01b2fSopenharmony_ci#include "make_test_data_available.hpp"
19c5f01b2fSopenharmony_ci
20c5f01b2fSopenharmony_ciTEST_CASE("JSON patch")
21c5f01b2fSopenharmony_ci{
22c5f01b2fSopenharmony_ci    SECTION("examples from RFC 6902")
23c5f01b2fSopenharmony_ci    {
24c5f01b2fSopenharmony_ci        SECTION("4. Operations")
25c5f01b2fSopenharmony_ci        {
26c5f01b2fSopenharmony_ci            // the ordering of members in JSON objects is not significant:
27c5f01b2fSopenharmony_ci            json op1 = R"({ "op": "add", "path": "/a/b/c", "value": "foo" })"_json;
28c5f01b2fSopenharmony_ci            json op2 = R"({ "path": "/a/b/c", "op": "add", "value": "foo" })"_json;
29c5f01b2fSopenharmony_ci            json op3 = R"({ "value": "foo", "path": "/a/b/c", "op": "add" })"_json;
30c5f01b2fSopenharmony_ci
31c5f01b2fSopenharmony_ci            // check if the operation objects are equivalent
32c5f01b2fSopenharmony_ci            CHECK(op1 == op2);
33c5f01b2fSopenharmony_ci            CHECK(op1 == op3);
34c5f01b2fSopenharmony_ci        }
35c5f01b2fSopenharmony_ci
36c5f01b2fSopenharmony_ci        SECTION("4.1 add")
37c5f01b2fSopenharmony_ci        {
38c5f01b2fSopenharmony_ci            json patch1 = R"([{ "op": "add", "path": "/a/b", "value": [ "foo", "bar" ] }])"_json;
39c5f01b2fSopenharmony_ci
40c5f01b2fSopenharmony_ci            // However, the object itself or an array containing it does need
41c5f01b2fSopenharmony_ci            // to exist, and it remains an error for that not to be the case.
42c5f01b2fSopenharmony_ci            // For example, an "add" with a target location of "/a/b" starting
43c5f01b2fSopenharmony_ci            // with this document
44c5f01b2fSopenharmony_ci            json doc1 = R"({ "a": { "foo": 1 } })"_json;
45c5f01b2fSopenharmony_ci
46c5f01b2fSopenharmony_ci            // is not an error, because "a" exists, and "b" will be added to
47c5f01b2fSopenharmony_ci            // its value.
48c5f01b2fSopenharmony_ci            CHECK_NOTHROW(doc1.patch(patch1));
49c5f01b2fSopenharmony_ci            auto doc1_ans = R"(
50c5f01b2fSopenharmony_ci                {
51c5f01b2fSopenharmony_ci                    "a": {
52c5f01b2fSopenharmony_ci                        "foo": 1,
53c5f01b2fSopenharmony_ci                        "b": [ "foo", "bar" ]
54c5f01b2fSopenharmony_ci                    }
55c5f01b2fSopenharmony_ci                }
56c5f01b2fSopenharmony_ci            )"_json;
57c5f01b2fSopenharmony_ci            CHECK(doc1.patch(patch1) == doc1_ans);
58c5f01b2fSopenharmony_ci
59c5f01b2fSopenharmony_ci            // It is an error in this document:
60c5f01b2fSopenharmony_ci            json doc2 = R"({ "q": { "bar": 2 } })"_json;
61c5f01b2fSopenharmony_ci
62c5f01b2fSopenharmony_ci            // because "a" does not exist.
63c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_AS(doc2.patch(patch1), "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&);
64c5f01b2fSopenharmony_ci
65c5f01b2fSopenharmony_ci            json doc3 = R"({ "a": {} })"_json;
66c5f01b2fSopenharmony_ci            json patch2 = R"([{ "op": "add", "path": "/a/b/c", "value": 1 }])"_json;
67c5f01b2fSopenharmony_ci
68c5f01b2fSopenharmony_ci            // should cause an error because "b" does not exist in doc3
69c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
70c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_AS(doc3.patch(patch2), "[json.exception.out_of_range.403] (/a) key 'b' not found", json::out_of_range&);
71c5f01b2fSopenharmony_ci#else
72c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_AS(doc3.patch(patch2), "[json.exception.out_of_range.403] key 'b' not found", json::out_of_range&);
73c5f01b2fSopenharmony_ci#endif
74c5f01b2fSopenharmony_ci        }
75c5f01b2fSopenharmony_ci
76c5f01b2fSopenharmony_ci        SECTION("4.2 remove")
77c5f01b2fSopenharmony_ci        {
78c5f01b2fSopenharmony_ci            // If removing an element from an array, any elements above the
79c5f01b2fSopenharmony_ci            // specified index are shifted one position to the left.
80c5f01b2fSopenharmony_ci            json doc = {1, 2, 3, 4};
81c5f01b2fSopenharmony_ci            json patch = {{{"op", "remove"}, {"path", "/1"}}};
82c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == json({1, 3, 4}));
83c5f01b2fSopenharmony_ci        }
84c5f01b2fSopenharmony_ci
85c5f01b2fSopenharmony_ci        SECTION("A.1. Adding an Object Member")
86c5f01b2fSopenharmony_ci        {
87c5f01b2fSopenharmony_ci            // An example target JSON document:
88c5f01b2fSopenharmony_ci            json doc = R"(
89c5f01b2fSopenharmony_ci                    { "foo": "bar"}
90c5f01b2fSopenharmony_ci                )"_json;
91c5f01b2fSopenharmony_ci
92c5f01b2fSopenharmony_ci            // A JSON Patch document:
93c5f01b2fSopenharmony_ci            json patch = R"(
94c5f01b2fSopenharmony_ci                    [
95c5f01b2fSopenharmony_ci                        { "op": "add", "path": "/baz", "value": "qux" }
96c5f01b2fSopenharmony_ci                    ]
97c5f01b2fSopenharmony_ci                )"_json;
98c5f01b2fSopenharmony_ci
99c5f01b2fSopenharmony_ci            // The resulting JSON document:
100c5f01b2fSopenharmony_ci            json expected = R"(
101c5f01b2fSopenharmony_ci                    {
102c5f01b2fSopenharmony_ci                        "baz": "qux",
103c5f01b2fSopenharmony_ci                        "foo": "bar"
104c5f01b2fSopenharmony_ci                    }
105c5f01b2fSopenharmony_ci                )"_json;
106c5f01b2fSopenharmony_ci
107c5f01b2fSopenharmony_ci            // check if patched value is as expected
108c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
109c5f01b2fSopenharmony_ci
110c5f01b2fSopenharmony_ci            // check roundtrip
111c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
112c5f01b2fSopenharmony_ci        }
113c5f01b2fSopenharmony_ci
114c5f01b2fSopenharmony_ci        SECTION("A.2. Adding an Array Element")
115c5f01b2fSopenharmony_ci        {
116c5f01b2fSopenharmony_ci            // An example target JSON document:
117c5f01b2fSopenharmony_ci            json doc = R"(
118c5f01b2fSopenharmony_ci                    { "foo": [ "bar", "baz" ] }
119c5f01b2fSopenharmony_ci                )"_json;
120c5f01b2fSopenharmony_ci
121c5f01b2fSopenharmony_ci            // A JSON Patch document:
122c5f01b2fSopenharmony_ci            json patch = R"(
123c5f01b2fSopenharmony_ci                    [
124c5f01b2fSopenharmony_ci                        { "op": "add", "path": "/foo/1", "value": "qux" }
125c5f01b2fSopenharmony_ci                    ]
126c5f01b2fSopenharmony_ci                )"_json;
127c5f01b2fSopenharmony_ci
128c5f01b2fSopenharmony_ci            // The resulting JSON document:
129c5f01b2fSopenharmony_ci            json expected = R"(
130c5f01b2fSopenharmony_ci                    { "foo": [ "bar", "qux", "baz" ] }
131c5f01b2fSopenharmony_ci                )"_json;
132c5f01b2fSopenharmony_ci
133c5f01b2fSopenharmony_ci            // check if patched value is as expected
134c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
135c5f01b2fSopenharmony_ci
136c5f01b2fSopenharmony_ci            // check roundtrip
137c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
138c5f01b2fSopenharmony_ci        }
139c5f01b2fSopenharmony_ci
140c5f01b2fSopenharmony_ci        SECTION("A.3. Removing an Object Member")
141c5f01b2fSopenharmony_ci        {
142c5f01b2fSopenharmony_ci            // An example target JSON document:
143c5f01b2fSopenharmony_ci            json doc = R"(
144c5f01b2fSopenharmony_ci                    {
145c5f01b2fSopenharmony_ci                        "baz": "qux",
146c5f01b2fSopenharmony_ci                        "foo": "bar"
147c5f01b2fSopenharmony_ci                    }
148c5f01b2fSopenharmony_ci                )"_json;
149c5f01b2fSopenharmony_ci
150c5f01b2fSopenharmony_ci            // A JSON Patch document:
151c5f01b2fSopenharmony_ci            json patch = R"(
152c5f01b2fSopenharmony_ci                    [
153c5f01b2fSopenharmony_ci                        { "op": "remove", "path": "/baz" }
154c5f01b2fSopenharmony_ci                    ]
155c5f01b2fSopenharmony_ci                )"_json;
156c5f01b2fSopenharmony_ci
157c5f01b2fSopenharmony_ci            // The resulting JSON document:
158c5f01b2fSopenharmony_ci            json expected = R"(
159c5f01b2fSopenharmony_ci                    { "foo": "bar" }
160c5f01b2fSopenharmony_ci                )"_json;
161c5f01b2fSopenharmony_ci
162c5f01b2fSopenharmony_ci            // check if patched value is as expected
163c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
164c5f01b2fSopenharmony_ci
165c5f01b2fSopenharmony_ci            // check roundtrip
166c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
167c5f01b2fSopenharmony_ci        }
168c5f01b2fSopenharmony_ci
169c5f01b2fSopenharmony_ci        SECTION("A.4. Removing an Array Element")
170c5f01b2fSopenharmony_ci        {
171c5f01b2fSopenharmony_ci            // An example target JSON document:
172c5f01b2fSopenharmony_ci            json doc = R"(
173c5f01b2fSopenharmony_ci                    { "foo": [ "bar", "qux", "baz" ] }
174c5f01b2fSopenharmony_ci                )"_json;
175c5f01b2fSopenharmony_ci
176c5f01b2fSopenharmony_ci            // A JSON Patch document:
177c5f01b2fSopenharmony_ci            json patch = R"(
178c5f01b2fSopenharmony_ci                    [
179c5f01b2fSopenharmony_ci                        { "op": "remove", "path": "/foo/1" }
180c5f01b2fSopenharmony_ci                    ]
181c5f01b2fSopenharmony_ci                )"_json;
182c5f01b2fSopenharmony_ci
183c5f01b2fSopenharmony_ci            // The resulting JSON document:
184c5f01b2fSopenharmony_ci            json expected = R"(
185c5f01b2fSopenharmony_ci                    { "foo": [ "bar", "baz" ] }
186c5f01b2fSopenharmony_ci                )"_json;
187c5f01b2fSopenharmony_ci
188c5f01b2fSopenharmony_ci            // check if patched value is as expected
189c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
190c5f01b2fSopenharmony_ci
191c5f01b2fSopenharmony_ci            // check roundtrip
192c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
193c5f01b2fSopenharmony_ci        }
194c5f01b2fSopenharmony_ci
195c5f01b2fSopenharmony_ci        SECTION("A.5. Replacing a Value")
196c5f01b2fSopenharmony_ci        {
197c5f01b2fSopenharmony_ci            // An example target JSON document:
198c5f01b2fSopenharmony_ci            json doc = R"(
199c5f01b2fSopenharmony_ci                    {
200c5f01b2fSopenharmony_ci                        "baz": "qux",
201c5f01b2fSopenharmony_ci                        "foo": "bar"
202c5f01b2fSopenharmony_ci                    }
203c5f01b2fSopenharmony_ci                )"_json;
204c5f01b2fSopenharmony_ci
205c5f01b2fSopenharmony_ci            // A JSON Patch document:
206c5f01b2fSopenharmony_ci            json patch = R"(
207c5f01b2fSopenharmony_ci                    [
208c5f01b2fSopenharmony_ci                        { "op": "replace", "path": "/baz", "value": "boo" }
209c5f01b2fSopenharmony_ci                    ]
210c5f01b2fSopenharmony_ci                )"_json;
211c5f01b2fSopenharmony_ci
212c5f01b2fSopenharmony_ci            json expected = R"(
213c5f01b2fSopenharmony_ci                    {
214c5f01b2fSopenharmony_ci                        "baz": "boo",
215c5f01b2fSopenharmony_ci                        "foo": "bar"
216c5f01b2fSopenharmony_ci                    }
217c5f01b2fSopenharmony_ci                )"_json;
218c5f01b2fSopenharmony_ci
219c5f01b2fSopenharmony_ci            // check if patched value is as expected
220c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
221c5f01b2fSopenharmony_ci
222c5f01b2fSopenharmony_ci            // check roundtrip
223c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
224c5f01b2fSopenharmony_ci        }
225c5f01b2fSopenharmony_ci
226c5f01b2fSopenharmony_ci        SECTION("A.6. Moving a Value")
227c5f01b2fSopenharmony_ci        {
228c5f01b2fSopenharmony_ci            // An example target JSON document:
229c5f01b2fSopenharmony_ci            json doc = R"(
230c5f01b2fSopenharmony_ci                    {
231c5f01b2fSopenharmony_ci                        "foo": {
232c5f01b2fSopenharmony_ci                           "bar": "baz",
233c5f01b2fSopenharmony_ci                            "waldo": "fred"
234c5f01b2fSopenharmony_ci                        },
235c5f01b2fSopenharmony_ci                        "qux": {
236c5f01b2fSopenharmony_ci                            "corge": "grault"
237c5f01b2fSopenharmony_ci                        }
238c5f01b2fSopenharmony_ci                    }
239c5f01b2fSopenharmony_ci                )"_json;
240c5f01b2fSopenharmony_ci
241c5f01b2fSopenharmony_ci            // A JSON Patch document:
242c5f01b2fSopenharmony_ci            json patch = R"(
243c5f01b2fSopenharmony_ci                    [
244c5f01b2fSopenharmony_ci                        { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" }
245c5f01b2fSopenharmony_ci                    ]
246c5f01b2fSopenharmony_ci                )"_json;
247c5f01b2fSopenharmony_ci
248c5f01b2fSopenharmony_ci            // The resulting JSON document:
249c5f01b2fSopenharmony_ci            json expected = R"(
250c5f01b2fSopenharmony_ci                    {
251c5f01b2fSopenharmony_ci                        "foo": {
252c5f01b2fSopenharmony_ci                           "bar": "baz"
253c5f01b2fSopenharmony_ci                        },
254c5f01b2fSopenharmony_ci                        "qux": {
255c5f01b2fSopenharmony_ci                            "corge": "grault",
256c5f01b2fSopenharmony_ci                            "thud": "fred"
257c5f01b2fSopenharmony_ci                        }
258c5f01b2fSopenharmony_ci                    }
259c5f01b2fSopenharmony_ci                )"_json;
260c5f01b2fSopenharmony_ci
261c5f01b2fSopenharmony_ci            // check if patched value is as expected
262c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
263c5f01b2fSopenharmony_ci
264c5f01b2fSopenharmony_ci            // check roundtrip
265c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
266c5f01b2fSopenharmony_ci        }
267c5f01b2fSopenharmony_ci
268c5f01b2fSopenharmony_ci        SECTION("A.7. Moving a Value")
269c5f01b2fSopenharmony_ci        {
270c5f01b2fSopenharmony_ci            // An example target JSON document:
271c5f01b2fSopenharmony_ci            json doc = R"(
272c5f01b2fSopenharmony_ci                    { "foo": [ "all", "grass", "cows", "eat" ] }
273c5f01b2fSopenharmony_ci                )"_json;
274c5f01b2fSopenharmony_ci
275c5f01b2fSopenharmony_ci            // A JSON Patch document:
276c5f01b2fSopenharmony_ci            json patch = R"(
277c5f01b2fSopenharmony_ci                    [
278c5f01b2fSopenharmony_ci                        { "op": "move", "from": "/foo/1", "path": "/foo/3" }
279c5f01b2fSopenharmony_ci                    ]
280c5f01b2fSopenharmony_ci                )"_json;
281c5f01b2fSopenharmony_ci
282c5f01b2fSopenharmony_ci            // The resulting JSON document:
283c5f01b2fSopenharmony_ci            json expected = R"(
284c5f01b2fSopenharmony_ci                    { "foo": [ "all", "cows", "eat", "grass" ] }
285c5f01b2fSopenharmony_ci                )"_json;
286c5f01b2fSopenharmony_ci
287c5f01b2fSopenharmony_ci            // check if patched value is as expected
288c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
289c5f01b2fSopenharmony_ci
290c5f01b2fSopenharmony_ci            // check roundtrip
291c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
292c5f01b2fSopenharmony_ci        }
293c5f01b2fSopenharmony_ci
294c5f01b2fSopenharmony_ci        SECTION("A.8. Testing a Value: Success")
295c5f01b2fSopenharmony_ci        {
296c5f01b2fSopenharmony_ci            // An example target JSON document:
297c5f01b2fSopenharmony_ci            json doc = R"(
298c5f01b2fSopenharmony_ci                    {
299c5f01b2fSopenharmony_ci                         "baz": "qux",
300c5f01b2fSopenharmony_ci                         "foo": [ "a", 2, "c" ]
301c5f01b2fSopenharmony_ci                    }
302c5f01b2fSopenharmony_ci                )"_json;
303c5f01b2fSopenharmony_ci
304c5f01b2fSopenharmony_ci            // A JSON Patch document that will result in successful evaluation:
305c5f01b2fSopenharmony_ci            json patch = R"(
306c5f01b2fSopenharmony_ci                    [
307c5f01b2fSopenharmony_ci                        { "op": "test", "path": "/baz", "value": "qux" },
308c5f01b2fSopenharmony_ci                        { "op": "test", "path": "/foo/1", "value": 2 }
309c5f01b2fSopenharmony_ci                    ]
310c5f01b2fSopenharmony_ci                )"_json;
311c5f01b2fSopenharmony_ci
312c5f01b2fSopenharmony_ci            // check if evaluation does not throw
313c5f01b2fSopenharmony_ci            CHECK_NOTHROW(doc.patch(patch));
314c5f01b2fSopenharmony_ci            // check if patched document is unchanged
315c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == doc);
316c5f01b2fSopenharmony_ci        }
317c5f01b2fSopenharmony_ci
318c5f01b2fSopenharmony_ci        SECTION("A.9. Testing a Value: Error")
319c5f01b2fSopenharmony_ci        {
320c5f01b2fSopenharmony_ci            // An example target JSON document:
321c5f01b2fSopenharmony_ci            json doc = R"(
322c5f01b2fSopenharmony_ci                    { "baz": "qux" }
323c5f01b2fSopenharmony_ci                )"_json;
324c5f01b2fSopenharmony_ci
325c5f01b2fSopenharmony_ci            // A JSON Patch document that will result in an error condition:
326c5f01b2fSopenharmony_ci            json patch = R"(
327c5f01b2fSopenharmony_ci                    [
328c5f01b2fSopenharmony_ci                        { "op": "test", "path": "/baz", "value": "bar" }
329c5f01b2fSopenharmony_ci                    ]
330c5f01b2fSopenharmony_ci                )"_json;
331c5f01b2fSopenharmony_ci
332c5f01b2fSopenharmony_ci            // check that evaluation throws
333c5f01b2fSopenharmony_ci            CHECK_THROWS_AS(doc.patch(patch), json::other_error&);
334c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
335c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] (/0) unsuccessful: " + patch[0].dump());
336c5f01b2fSopenharmony_ci#else
337c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump());
338c5f01b2fSopenharmony_ci#endif
339c5f01b2fSopenharmony_ci        }
340c5f01b2fSopenharmony_ci
341c5f01b2fSopenharmony_ci        SECTION("A.10. Adding a Nested Member Object")
342c5f01b2fSopenharmony_ci        {
343c5f01b2fSopenharmony_ci            // An example target JSON document:
344c5f01b2fSopenharmony_ci            json doc = R"(
345c5f01b2fSopenharmony_ci                    { "foo": "bar" }
346c5f01b2fSopenharmony_ci                )"_json;
347c5f01b2fSopenharmony_ci
348c5f01b2fSopenharmony_ci            // A JSON Patch document:
349c5f01b2fSopenharmony_ci            json patch = R"(
350c5f01b2fSopenharmony_ci                    [
351c5f01b2fSopenharmony_ci                        { "op": "add", "path": "/child", "value": { "grandchild": { } } }
352c5f01b2fSopenharmony_ci                    ]
353c5f01b2fSopenharmony_ci                )"_json;
354c5f01b2fSopenharmony_ci
355c5f01b2fSopenharmony_ci            // The resulting JSON document:
356c5f01b2fSopenharmony_ci            json expected = R"(
357c5f01b2fSopenharmony_ci                {
358c5f01b2fSopenharmony_ci                    "foo": "bar",
359c5f01b2fSopenharmony_ci                    "child": {
360c5f01b2fSopenharmony_ci                        "grandchild": {
361c5f01b2fSopenharmony_ci                        }
362c5f01b2fSopenharmony_ci                    }
363c5f01b2fSopenharmony_ci                }
364c5f01b2fSopenharmony_ci                )"_json;
365c5f01b2fSopenharmony_ci
366c5f01b2fSopenharmony_ci            // check if patched value is as expected
367c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
368c5f01b2fSopenharmony_ci
369c5f01b2fSopenharmony_ci            // check roundtrip
370c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
371c5f01b2fSopenharmony_ci        }
372c5f01b2fSopenharmony_ci
373c5f01b2fSopenharmony_ci        SECTION("A.11. Ignoring Unrecognized Elements")
374c5f01b2fSopenharmony_ci        {
375c5f01b2fSopenharmony_ci            // An example target JSON document:
376c5f01b2fSopenharmony_ci            json doc = R"(
377c5f01b2fSopenharmony_ci                    { "foo": "bar" }
378c5f01b2fSopenharmony_ci                )"_json;
379c5f01b2fSopenharmony_ci
380c5f01b2fSopenharmony_ci            // A JSON Patch document:
381c5f01b2fSopenharmony_ci            json patch = R"(
382c5f01b2fSopenharmony_ci                    [
383c5f01b2fSopenharmony_ci                        { "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }
384c5f01b2fSopenharmony_ci                    ]
385c5f01b2fSopenharmony_ci                )"_json;
386c5f01b2fSopenharmony_ci
387c5f01b2fSopenharmony_ci            json expected = R"(
388c5f01b2fSopenharmony_ci                    {
389c5f01b2fSopenharmony_ci                        "foo": "bar",
390c5f01b2fSopenharmony_ci                        "baz": "qux"
391c5f01b2fSopenharmony_ci                    }
392c5f01b2fSopenharmony_ci                )"_json;
393c5f01b2fSopenharmony_ci
394c5f01b2fSopenharmony_ci            // check if patched value is as expected
395c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
396c5f01b2fSopenharmony_ci
397c5f01b2fSopenharmony_ci            // check roundtrip
398c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
399c5f01b2fSopenharmony_ci        }
400c5f01b2fSopenharmony_ci
401c5f01b2fSopenharmony_ci        SECTION("A.12. Adding to a Nonexistent Target")
402c5f01b2fSopenharmony_ci        {
403c5f01b2fSopenharmony_ci            // An example target JSON document:
404c5f01b2fSopenharmony_ci            json doc = R"(
405c5f01b2fSopenharmony_ci                    { "foo": "bar" }
406c5f01b2fSopenharmony_ci                )"_json;
407c5f01b2fSopenharmony_ci
408c5f01b2fSopenharmony_ci            // A JSON Patch document:
409c5f01b2fSopenharmony_ci            json patch = R"(
410c5f01b2fSopenharmony_ci                    [
411c5f01b2fSopenharmony_ci                        { "op": "add", "path": "/baz/bat", "value": "qux" }
412c5f01b2fSopenharmony_ci                    ]
413c5f01b2fSopenharmony_ci                )"_json;
414c5f01b2fSopenharmony_ci
415c5f01b2fSopenharmony_ci            // This JSON Patch document, applied to the target JSON document
416c5f01b2fSopenharmony_ci            // above, would result in an error (therefore, it would not be
417c5f01b2fSopenharmony_ci            // applied), because the "add" operation's target location that
418c5f01b2fSopenharmony_ci            // references neither the root of the document, nor a member of
419c5f01b2fSopenharmony_ci            // an existing object, nor a member of an existing array.
420c5f01b2fSopenharmony_ci
421c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found", json::out_of_range&);
422c5f01b2fSopenharmony_ci        }
423c5f01b2fSopenharmony_ci
424c5f01b2fSopenharmony_ci        // A.13. Invalid JSON Patch Document
425c5f01b2fSopenharmony_ci        // not applicable
426c5f01b2fSopenharmony_ci
427c5f01b2fSopenharmony_ci        SECTION("A.14. Escape Ordering")
428c5f01b2fSopenharmony_ci        {
429c5f01b2fSopenharmony_ci            // An example target JSON document:
430c5f01b2fSopenharmony_ci            json doc = R"(
431c5f01b2fSopenharmony_ci                    {
432c5f01b2fSopenharmony_ci                        "/": 9,
433c5f01b2fSopenharmony_ci                        "~1": 10
434c5f01b2fSopenharmony_ci                    }
435c5f01b2fSopenharmony_ci                )"_json;
436c5f01b2fSopenharmony_ci
437c5f01b2fSopenharmony_ci            // A JSON Patch document:
438c5f01b2fSopenharmony_ci            json patch = R"(
439c5f01b2fSopenharmony_ci                    [
440c5f01b2fSopenharmony_ci                        {"op": "test", "path": "/~01", "value": 10}
441c5f01b2fSopenharmony_ci                    ]
442c5f01b2fSopenharmony_ci                )"_json;
443c5f01b2fSopenharmony_ci
444c5f01b2fSopenharmony_ci            json expected = R"(
445c5f01b2fSopenharmony_ci                    {
446c5f01b2fSopenharmony_ci                        "/": 9,
447c5f01b2fSopenharmony_ci                        "~1": 10
448c5f01b2fSopenharmony_ci                    }
449c5f01b2fSopenharmony_ci                )"_json;
450c5f01b2fSopenharmony_ci
451c5f01b2fSopenharmony_ci            // check if patched value is as expected
452c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
453c5f01b2fSopenharmony_ci
454c5f01b2fSopenharmony_ci            // check roundtrip
455c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
456c5f01b2fSopenharmony_ci        }
457c5f01b2fSopenharmony_ci
458c5f01b2fSopenharmony_ci        SECTION("A.15. Comparing Strings and Numbers")
459c5f01b2fSopenharmony_ci        {
460c5f01b2fSopenharmony_ci            // An example target JSON document:
461c5f01b2fSopenharmony_ci            json doc = R"(
462c5f01b2fSopenharmony_ci                    {
463c5f01b2fSopenharmony_ci                        "/": 9,
464c5f01b2fSopenharmony_ci                        "~1": 10
465c5f01b2fSopenharmony_ci                    }
466c5f01b2fSopenharmony_ci                )"_json;
467c5f01b2fSopenharmony_ci
468c5f01b2fSopenharmony_ci            // A JSON Patch document that will result in an error condition:
469c5f01b2fSopenharmony_ci            json patch = R"(
470c5f01b2fSopenharmony_ci                    [
471c5f01b2fSopenharmony_ci                        {"op": "test", "path": "/~01", "value": "10"}
472c5f01b2fSopenharmony_ci                    ]
473c5f01b2fSopenharmony_ci                )"_json;
474c5f01b2fSopenharmony_ci
475c5f01b2fSopenharmony_ci            // check that evaluation throws
476c5f01b2fSopenharmony_ci            CHECK_THROWS_AS(doc.patch(patch), json::other_error&);
477c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
478c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] (/0) unsuccessful: " + patch[0].dump());
479c5f01b2fSopenharmony_ci#else
480c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump());
481c5f01b2fSopenharmony_ci#endif
482c5f01b2fSopenharmony_ci        }
483c5f01b2fSopenharmony_ci
484c5f01b2fSopenharmony_ci        SECTION("A.16. Adding an Array Value")
485c5f01b2fSopenharmony_ci        {
486c5f01b2fSopenharmony_ci            // An example target JSON document:
487c5f01b2fSopenharmony_ci            json doc = R"(
488c5f01b2fSopenharmony_ci                    { "foo": ["bar"] }
489c5f01b2fSopenharmony_ci                )"_json;
490c5f01b2fSopenharmony_ci
491c5f01b2fSopenharmony_ci            // A JSON Patch document:
492c5f01b2fSopenharmony_ci            json patch = R"(
493c5f01b2fSopenharmony_ci                    [
494c5f01b2fSopenharmony_ci                        { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }
495c5f01b2fSopenharmony_ci                    ]
496c5f01b2fSopenharmony_ci                )"_json;
497c5f01b2fSopenharmony_ci
498c5f01b2fSopenharmony_ci            // The resulting JSON document:
499c5f01b2fSopenharmony_ci            json expected = R"(
500c5f01b2fSopenharmony_ci                    { "foo": ["bar", ["abc", "def"]] }
501c5f01b2fSopenharmony_ci                )"_json;
502c5f01b2fSopenharmony_ci
503c5f01b2fSopenharmony_ci            // check if patched value is as expected
504c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
505c5f01b2fSopenharmony_ci
506c5f01b2fSopenharmony_ci            // check roundtrip
507c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
508c5f01b2fSopenharmony_ci        }
509c5f01b2fSopenharmony_ci    }
510c5f01b2fSopenharmony_ci
511c5f01b2fSopenharmony_ci    SECTION("own examples")
512c5f01b2fSopenharmony_ci    {
513c5f01b2fSopenharmony_ci        SECTION("add")
514c5f01b2fSopenharmony_ci        {
515c5f01b2fSopenharmony_ci            SECTION("add to the root element")
516c5f01b2fSopenharmony_ci            {
517c5f01b2fSopenharmony_ci                // If the path is the root of the target document - the
518c5f01b2fSopenharmony_ci                // specified value becomes the entire content of the target
519c5f01b2fSopenharmony_ci                // document.
520c5f01b2fSopenharmony_ci
521c5f01b2fSopenharmony_ci                // An example target JSON document:
522c5f01b2fSopenharmony_ci                json doc = 17;
523c5f01b2fSopenharmony_ci
524c5f01b2fSopenharmony_ci                // A JSON Patch document:
525c5f01b2fSopenharmony_ci                json patch = R"(
526c5f01b2fSopenharmony_ci                        [
527c5f01b2fSopenharmony_ci                            { "op": "add", "path": "", "value": [1,2,3] }
528c5f01b2fSopenharmony_ci                        ]
529c5f01b2fSopenharmony_ci                    )"_json;
530c5f01b2fSopenharmony_ci
531c5f01b2fSopenharmony_ci                // The resulting JSON document:
532c5f01b2fSopenharmony_ci                json expected = {1, 2, 3};
533c5f01b2fSopenharmony_ci
534c5f01b2fSopenharmony_ci                // check if patched value is as expected
535c5f01b2fSopenharmony_ci                CHECK(doc.patch(patch) == expected);
536c5f01b2fSopenharmony_ci
537c5f01b2fSopenharmony_ci                // check roundtrip
538c5f01b2fSopenharmony_ci                CHECK(doc.patch(json::diff(doc, expected)) == expected);
539c5f01b2fSopenharmony_ci            }
540c5f01b2fSopenharmony_ci
541c5f01b2fSopenharmony_ci            SECTION("add to end of the array")
542c5f01b2fSopenharmony_ci            {
543c5f01b2fSopenharmony_ci                // The specified index MUST NOT be greater than the number of
544c5f01b2fSopenharmony_ci                // elements in the array. The example below uses and index of
545c5f01b2fSopenharmony_ci                // exactly the number of elements in the array which is legal.
546c5f01b2fSopenharmony_ci
547c5f01b2fSopenharmony_ci                // An example target JSON document:
548c5f01b2fSopenharmony_ci                json doc = {0, 1, 2};
549c5f01b2fSopenharmony_ci
550c5f01b2fSopenharmony_ci                // A JSON Patch document:
551c5f01b2fSopenharmony_ci                json patch = R"(
552c5f01b2fSopenharmony_ci                    [
553c5f01b2fSopenharmony_ci                        { "op": "add", "path": "/3", "value": 3 }
554c5f01b2fSopenharmony_ci                    ]
555c5f01b2fSopenharmony_ci                )"_json;
556c5f01b2fSopenharmony_ci
557c5f01b2fSopenharmony_ci                // The resulting JSON document:
558c5f01b2fSopenharmony_ci                json expected = {0, 1, 2, 3};
559c5f01b2fSopenharmony_ci
560c5f01b2fSopenharmony_ci                // check if patched value is as expected
561c5f01b2fSopenharmony_ci                CHECK(doc.patch(patch) == expected);
562c5f01b2fSopenharmony_ci
563c5f01b2fSopenharmony_ci                // check roundtrip
564c5f01b2fSopenharmony_ci                CHECK(doc.patch(json::diff(doc, expected)) == expected);
565c5f01b2fSopenharmony_ci            }
566c5f01b2fSopenharmony_ci        }
567c5f01b2fSopenharmony_ci
568c5f01b2fSopenharmony_ci        SECTION("copy")
569c5f01b2fSopenharmony_ci        {
570c5f01b2fSopenharmony_ci            // An example target JSON document:
571c5f01b2fSopenharmony_ci            json doc = R"(
572c5f01b2fSopenharmony_ci                {
573c5f01b2fSopenharmony_ci                    "foo": {
574c5f01b2fSopenharmony_ci                        "bar": "baz",
575c5f01b2fSopenharmony_ci                        "waldo": "fred"
576c5f01b2fSopenharmony_ci                    },
577c5f01b2fSopenharmony_ci                    "qux": {
578c5f01b2fSopenharmony_ci                       "corge": "grault"
579c5f01b2fSopenharmony_ci                    }
580c5f01b2fSopenharmony_ci                }
581c5f01b2fSopenharmony_ci            )"_json;
582c5f01b2fSopenharmony_ci
583c5f01b2fSopenharmony_ci            // A JSON Patch document:
584c5f01b2fSopenharmony_ci            json patch = R"(
585c5f01b2fSopenharmony_ci                [
586c5f01b2fSopenharmony_ci                    { "op": "copy", "from": "/foo/waldo", "path": "/qux/thud" }
587c5f01b2fSopenharmony_ci                ]
588c5f01b2fSopenharmony_ci            )"_json;
589c5f01b2fSopenharmony_ci
590c5f01b2fSopenharmony_ci            // The resulting JSON document:
591c5f01b2fSopenharmony_ci            json expected = R"(
592c5f01b2fSopenharmony_ci                {
593c5f01b2fSopenharmony_ci                    "foo": {
594c5f01b2fSopenharmony_ci                        "bar": "baz",
595c5f01b2fSopenharmony_ci                        "waldo": "fred"
596c5f01b2fSopenharmony_ci                    },
597c5f01b2fSopenharmony_ci                    "qux": {
598c5f01b2fSopenharmony_ci                       "corge": "grault",
599c5f01b2fSopenharmony_ci                       "thud": "fred"
600c5f01b2fSopenharmony_ci                    }
601c5f01b2fSopenharmony_ci                }
602c5f01b2fSopenharmony_ci            )"_json;
603c5f01b2fSopenharmony_ci
604c5f01b2fSopenharmony_ci            // check if patched value is as expected
605c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == expected);
606c5f01b2fSopenharmony_ci
607c5f01b2fSopenharmony_ci            // check roundtrip
608c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, expected)) == expected);
609c5f01b2fSopenharmony_ci        }
610c5f01b2fSopenharmony_ci
611c5f01b2fSopenharmony_ci        SECTION("replace")
612c5f01b2fSopenharmony_ci        {
613c5f01b2fSopenharmony_ci            json j = "string";
614c5f01b2fSopenharmony_ci            json patch = {{{"op", "replace"}, {"path", ""}, {"value", 1}}};
615c5f01b2fSopenharmony_ci            CHECK(j.patch(patch) == json(1));
616c5f01b2fSopenharmony_ci        }
617c5f01b2fSopenharmony_ci
618c5f01b2fSopenharmony_ci        SECTION("documentation GIF")
619c5f01b2fSopenharmony_ci        {
620c5f01b2fSopenharmony_ci            {
621c5f01b2fSopenharmony_ci                // a JSON patch
622c5f01b2fSopenharmony_ci                json p1 = R"(
623c5f01b2fSopenharmony_ci                     [{"op": "add", "path": "/GB", "value": "London"}]
624c5f01b2fSopenharmony_ci                    )"_json;
625c5f01b2fSopenharmony_ci
626c5f01b2fSopenharmony_ci                // a JSON value
627c5f01b2fSopenharmony_ci                json source = R"(
628c5f01b2fSopenharmony_ci                      {"D": "Berlin", "F": "Paris"}
629c5f01b2fSopenharmony_ci                    )"_json;
630c5f01b2fSopenharmony_ci
631c5f01b2fSopenharmony_ci                // apply the patch
632c5f01b2fSopenharmony_ci                json target = source.patch(p1);
633c5f01b2fSopenharmony_ci                // target = { "D": "Berlin", "F": "Paris", "GB": "London" }
634c5f01b2fSopenharmony_ci                CHECK(target == R"({ "D": "Berlin", "F": "Paris", "GB": "London" })"_json);
635c5f01b2fSopenharmony_ci
636c5f01b2fSopenharmony_ci                // create a diff from two JSONs
637c5f01b2fSopenharmony_ci                json p2 = json::diff(target, source); // NOLINT(readability-suspicious-call-argument)
638c5f01b2fSopenharmony_ci                // p2 = [{"op": "delete", "path": "/GB"}]
639c5f01b2fSopenharmony_ci                CHECK(p2 == R"([{"op":"remove","path":"/GB"}])"_json);
640c5f01b2fSopenharmony_ci            }
641c5f01b2fSopenharmony_ci            {
642c5f01b2fSopenharmony_ci                // a JSON value
643c5f01b2fSopenharmony_ci                json j = {"good", "bad", "ugly"};
644c5f01b2fSopenharmony_ci
645c5f01b2fSopenharmony_ci                // a JSON pointer
646c5f01b2fSopenharmony_ci                auto ptr = json::json_pointer("/2");
647c5f01b2fSopenharmony_ci
648c5f01b2fSopenharmony_ci                // use to access elements
649c5f01b2fSopenharmony_ci                j[ptr] = {{"it", "cattivo"}};
650c5f01b2fSopenharmony_ci                CHECK(j == R"(["good","bad",{"it":"cattivo"}])"_json);
651c5f01b2fSopenharmony_ci
652c5f01b2fSopenharmony_ci                // use user-defined string literal
653c5f01b2fSopenharmony_ci                j["/2/en"_json_pointer] = "ugly";
654c5f01b2fSopenharmony_ci                CHECK(j == R"(["good","bad",{"en":"ugly","it":"cattivo"}])"_json);
655c5f01b2fSopenharmony_ci
656c5f01b2fSopenharmony_ci                json flat = j.flatten();
657c5f01b2fSopenharmony_ci                CHECK(flat == R"({"/0":"good","/1":"bad","/2/en":"ugly","/2/it":"cattivo"})"_json);
658c5f01b2fSopenharmony_ci            }
659c5f01b2fSopenharmony_ci        }
660c5f01b2fSopenharmony_ci    }
661c5f01b2fSopenharmony_ci
662c5f01b2fSopenharmony_ci    SECTION("errors")
663c5f01b2fSopenharmony_ci    {
664c5f01b2fSopenharmony_ci        SECTION("unknown operation")
665c5f01b2fSopenharmony_ci        {
666c5f01b2fSopenharmony_ci            SECTION("not an array")
667c5f01b2fSopenharmony_ci            {
668c5f01b2fSopenharmony_ci                json j;
669c5f01b2fSopenharmony_ci                json patch = {{"op", "add"}, {"path", ""}, {"value", 1}};
670c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.104] parse error: JSON patch must be an array of objects", json::parse_error&);
671c5f01b2fSopenharmony_ci            }
672c5f01b2fSopenharmony_ci
673c5f01b2fSopenharmony_ci            SECTION("not an array of objects")
674c5f01b2fSopenharmony_ci            {
675c5f01b2fSopenharmony_ci                json j;
676c5f01b2fSopenharmony_ci                json patch = {"op", "add", "path", "", "value", 1};
677c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
678c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.104] parse error: (/0) JSON patch must be an array of objects", json::parse_error&);
679c5f01b2fSopenharmony_ci#else
680c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.104] parse error: JSON patch must be an array of objects", json::parse_error&);
681c5f01b2fSopenharmony_ci#endif
682c5f01b2fSopenharmony_ci            }
683c5f01b2fSopenharmony_ci
684c5f01b2fSopenharmony_ci            SECTION("missing 'op'")
685c5f01b2fSopenharmony_ci            {
686c5f01b2fSopenharmony_ci                json j;
687c5f01b2fSopenharmony_ci                json patch = {{{"foo", "bar"}}};
688c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
689c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation must have member 'op'", json::parse_error&);
690c5f01b2fSopenharmony_ci#else
691c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation must have member 'op'", json::parse_error&);
692c5f01b2fSopenharmony_ci#endif
693c5f01b2fSopenharmony_ci            }
694c5f01b2fSopenharmony_ci
695c5f01b2fSopenharmony_ci            SECTION("non-string 'op'")
696c5f01b2fSopenharmony_ci            {
697c5f01b2fSopenharmony_ci                json j;
698c5f01b2fSopenharmony_ci                json patch = {{{"op", 1}}};
699c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
700c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation must have string member 'op'", json::parse_error&);
701c5f01b2fSopenharmony_ci#else
702c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation must have string member 'op'", json::parse_error&);
703c5f01b2fSopenharmony_ci#endif
704c5f01b2fSopenharmony_ci            }
705c5f01b2fSopenharmony_ci
706c5f01b2fSopenharmony_ci            SECTION("invalid operation")
707c5f01b2fSopenharmony_ci            {
708c5f01b2fSopenharmony_ci                json j;
709c5f01b2fSopenharmony_ci                json patch = {{{"op", "foo"}, {"path", ""}}};
710c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
711c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation value 'foo' is invalid", json::parse_error&);
712c5f01b2fSopenharmony_ci#else
713c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation value 'foo' is invalid", json::parse_error&);
714c5f01b2fSopenharmony_ci#endif
715c5f01b2fSopenharmony_ci            }
716c5f01b2fSopenharmony_ci        }
717c5f01b2fSopenharmony_ci
718c5f01b2fSopenharmony_ci        SECTION("add")
719c5f01b2fSopenharmony_ci        {
720c5f01b2fSopenharmony_ci            SECTION("missing 'path'")
721c5f01b2fSopenharmony_ci            {
722c5f01b2fSopenharmony_ci                json j;
723c5f01b2fSopenharmony_ci                json patch = {{{"op", "add"}}};
724c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
725c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'add' must have member 'path'", json::parse_error&);
726c5f01b2fSopenharmony_ci#else
727c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'add' must have member 'path'", json::parse_error&);
728c5f01b2fSopenharmony_ci#endif
729c5f01b2fSopenharmony_ci            }
730c5f01b2fSopenharmony_ci
731c5f01b2fSopenharmony_ci            SECTION("non-string 'path'")
732c5f01b2fSopenharmony_ci            {
733c5f01b2fSopenharmony_ci                json j;
734c5f01b2fSopenharmony_ci                json patch = {{{"op", "add"}, {"path", 1}}};
735c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
736c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'add' must have string member 'path'", json::parse_error&);
737c5f01b2fSopenharmony_ci#else
738c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'add' must have string member 'path'", json::parse_error&);
739c5f01b2fSopenharmony_ci#endif
740c5f01b2fSopenharmony_ci            }
741c5f01b2fSopenharmony_ci
742c5f01b2fSopenharmony_ci            SECTION("missing 'value'")
743c5f01b2fSopenharmony_ci            {
744c5f01b2fSopenharmony_ci                json j;
745c5f01b2fSopenharmony_ci                json patch = {{{"op", "add"}, {"path", ""}}};
746c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
747c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'add' must have member 'value'", json::parse_error&);
748c5f01b2fSopenharmony_ci#else
749c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'add' must have member 'value'", json::parse_error&);
750c5f01b2fSopenharmony_ci#endif
751c5f01b2fSopenharmony_ci            }
752c5f01b2fSopenharmony_ci
753c5f01b2fSopenharmony_ci            SECTION("invalid array index")
754c5f01b2fSopenharmony_ci            {
755c5f01b2fSopenharmony_ci                json j = {1, 2};
756c5f01b2fSopenharmony_ci                json patch = {{{"op", "add"}, {"path", "/4"}, {"value", 4}}};
757c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.401] array index 4 is out of range", json::out_of_range&);
758c5f01b2fSopenharmony_ci            }
759c5f01b2fSopenharmony_ci        }
760c5f01b2fSopenharmony_ci
761c5f01b2fSopenharmony_ci        SECTION("remove")
762c5f01b2fSopenharmony_ci        {
763c5f01b2fSopenharmony_ci            SECTION("missing 'path'")
764c5f01b2fSopenharmony_ci            {
765c5f01b2fSopenharmony_ci                json j;
766c5f01b2fSopenharmony_ci                json patch = {{{"op", "remove"}}};
767c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
768c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'remove' must have member 'path'", json::parse_error&);
769c5f01b2fSopenharmony_ci#else
770c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'remove' must have member 'path'", json::parse_error&);
771c5f01b2fSopenharmony_ci#endif
772c5f01b2fSopenharmony_ci            }
773c5f01b2fSopenharmony_ci
774c5f01b2fSopenharmony_ci            SECTION("non-string 'path'")
775c5f01b2fSopenharmony_ci            {
776c5f01b2fSopenharmony_ci                json j;
777c5f01b2fSopenharmony_ci                json patch = {{{"op", "remove"}, {"path", 1}}};
778c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
779c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'remove' must have string member 'path'", json::parse_error&);
780c5f01b2fSopenharmony_ci#else
781c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'remove' must have string member 'path'", json::parse_error&);
782c5f01b2fSopenharmony_ci#endif
783c5f01b2fSopenharmony_ci            }
784c5f01b2fSopenharmony_ci
785c5f01b2fSopenharmony_ci            SECTION("nonexisting target location (array)")
786c5f01b2fSopenharmony_ci            {
787c5f01b2fSopenharmony_ci                json j = {1, 2, 3};
788c5f01b2fSopenharmony_ci                json patch = {{{"op", "remove"}, {"path", "/17"}}};
789c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.401] array index 17 is out of range", json::out_of_range&);
790c5f01b2fSopenharmony_ci            }
791c5f01b2fSopenharmony_ci
792c5f01b2fSopenharmony_ci            SECTION("nonexisting target location (object)")
793c5f01b2fSopenharmony_ci            {
794c5f01b2fSopenharmony_ci                json j = {{"foo", 1}, {"bar", 2}};
795c5f01b2fSopenharmony_ci                json patch = {{{"op", "remove"}, {"path", "/baz"}}};
796c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found", json::out_of_range&);
797c5f01b2fSopenharmony_ci            }
798c5f01b2fSopenharmony_ci
799c5f01b2fSopenharmony_ci            SECTION("root element as target location")
800c5f01b2fSopenharmony_ci            {
801c5f01b2fSopenharmony_ci                json j = "string";
802c5f01b2fSopenharmony_ci                json patch = {{{"op", "remove"}, {"path", ""}}};
803c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.405] JSON pointer has no parent", json::out_of_range&);
804c5f01b2fSopenharmony_ci            }
805c5f01b2fSopenharmony_ci        }
806c5f01b2fSopenharmony_ci
807c5f01b2fSopenharmony_ci        SECTION("replace")
808c5f01b2fSopenharmony_ci        {
809c5f01b2fSopenharmony_ci            SECTION("missing 'path'")
810c5f01b2fSopenharmony_ci            {
811c5f01b2fSopenharmony_ci                json j;
812c5f01b2fSopenharmony_ci                json patch = {{{"op", "replace"}}};
813c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
814c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'replace' must have member 'path'", json::parse_error&);
815c5f01b2fSopenharmony_ci#else
816c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'path'", json::parse_error&);
817c5f01b2fSopenharmony_ci#endif
818c5f01b2fSopenharmony_ci            }
819c5f01b2fSopenharmony_ci
820c5f01b2fSopenharmony_ci            SECTION("non-string 'path'")
821c5f01b2fSopenharmony_ci            {
822c5f01b2fSopenharmony_ci                json j;
823c5f01b2fSopenharmony_ci                json patch = {{{"op", "replace"}, {"path", 1}}};
824c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
825c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'replace' must have string member 'path'", json::parse_error&);
826c5f01b2fSopenharmony_ci#else
827c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'replace' must have string member 'path'", json::parse_error&);
828c5f01b2fSopenharmony_ci#endif
829c5f01b2fSopenharmony_ci            }
830c5f01b2fSopenharmony_ci
831c5f01b2fSopenharmony_ci            SECTION("missing 'value'")
832c5f01b2fSopenharmony_ci            {
833c5f01b2fSopenharmony_ci                json j;
834c5f01b2fSopenharmony_ci                json patch = {{{"op", "replace"}, {"path", ""}}};
835c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
836c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'replace' must have member 'value'", json::parse_error&);
837c5f01b2fSopenharmony_ci#else
838c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'value'", json::parse_error&);
839c5f01b2fSopenharmony_ci#endif
840c5f01b2fSopenharmony_ci            }
841c5f01b2fSopenharmony_ci
842c5f01b2fSopenharmony_ci            SECTION("nonexisting target location (array)")
843c5f01b2fSopenharmony_ci            {
844c5f01b2fSopenharmony_ci                json j = {1, 2, 3};
845c5f01b2fSopenharmony_ci                json patch = {{{"op", "replace"}, {"path", "/17"}, {"value", 19}}};
846c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.401] array index 17 is out of range", json::out_of_range&);
847c5f01b2fSopenharmony_ci            }
848c5f01b2fSopenharmony_ci
849c5f01b2fSopenharmony_ci            SECTION("nonexisting target location (object)")
850c5f01b2fSopenharmony_ci            {
851c5f01b2fSopenharmony_ci                json j = {{"foo", 1}, {"bar", 2}};
852c5f01b2fSopenharmony_ci                json patch = {{{"op", "replace"}, {"path", "/baz"}, {"value", 3}}};
853c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found", json::out_of_range&);
854c5f01b2fSopenharmony_ci            }
855c5f01b2fSopenharmony_ci        }
856c5f01b2fSopenharmony_ci
857c5f01b2fSopenharmony_ci        SECTION("move")
858c5f01b2fSopenharmony_ci        {
859c5f01b2fSopenharmony_ci            SECTION("missing 'path'")
860c5f01b2fSopenharmony_ci            {
861c5f01b2fSopenharmony_ci                json j;
862c5f01b2fSopenharmony_ci                json patch = {{{"op", "move"}}};
863c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
864c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'move' must have member 'path'", json::parse_error&);
865c5f01b2fSopenharmony_ci#else
866c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have member 'path'", json::parse_error&);
867c5f01b2fSopenharmony_ci#endif
868c5f01b2fSopenharmony_ci            }
869c5f01b2fSopenharmony_ci
870c5f01b2fSopenharmony_ci            SECTION("non-string 'path'")
871c5f01b2fSopenharmony_ci            {
872c5f01b2fSopenharmony_ci                json j;
873c5f01b2fSopenharmony_ci                json patch = {{{"op", "move"}, {"path", 1}}};
874c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
875c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'move' must have string member 'path'", json::parse_error&);
876c5f01b2fSopenharmony_ci#else
877c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'path'", json::parse_error&);
878c5f01b2fSopenharmony_ci#endif
879c5f01b2fSopenharmony_ci            }
880c5f01b2fSopenharmony_ci
881c5f01b2fSopenharmony_ci            SECTION("missing 'from'")
882c5f01b2fSopenharmony_ci            {
883c5f01b2fSopenharmony_ci                json j;
884c5f01b2fSopenharmony_ci                json patch = {{{"op", "move"}, {"path", ""}}};
885c5f01b2fSopenharmony_ci                CHECK_THROWS_AS(j.patch(patch), json::parse_error&);
886c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
887c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'move' must have member 'from'", json::parse_error&);
888c5f01b2fSopenharmony_ci#else
889c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have member 'from'", json::parse_error&);
890c5f01b2fSopenharmony_ci#endif
891c5f01b2fSopenharmony_ci            }
892c5f01b2fSopenharmony_ci
893c5f01b2fSopenharmony_ci            SECTION("non-string 'from'")
894c5f01b2fSopenharmony_ci            {
895c5f01b2fSopenharmony_ci                json j;
896c5f01b2fSopenharmony_ci                json patch = {{{"op", "move"}, {"path", ""}, {"from", 1}}};
897c5f01b2fSopenharmony_ci                CHECK_THROWS_AS(j.patch(patch), json::parse_error&);
898c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
899c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'move' must have string member 'from'", json::parse_error&);
900c5f01b2fSopenharmony_ci#else
901c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'from'", json::parse_error&);
902c5f01b2fSopenharmony_ci#endif
903c5f01b2fSopenharmony_ci            }
904c5f01b2fSopenharmony_ci
905c5f01b2fSopenharmony_ci            SECTION("nonexisting from location (array)")
906c5f01b2fSopenharmony_ci            {
907c5f01b2fSopenharmony_ci                json j = {1, 2, 3};
908c5f01b2fSopenharmony_ci                json patch = {{{"op", "move"}, {"path", "/0"}, {"from", "/5"}}};
909c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.401] array index 5 is out of range", json::out_of_range&);
910c5f01b2fSopenharmony_ci            }
911c5f01b2fSopenharmony_ci
912c5f01b2fSopenharmony_ci            SECTION("nonexisting from location (object)")
913c5f01b2fSopenharmony_ci            {
914c5f01b2fSopenharmony_ci                json j = {{"foo", 1}, {"bar", 2}};
915c5f01b2fSopenharmony_ci                json patch = {{{"op", "move"}, {"path", "/baz"}, {"from", "/baz"}}};
916c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found", json::out_of_range&);
917c5f01b2fSopenharmony_ci            }
918c5f01b2fSopenharmony_ci        }
919c5f01b2fSopenharmony_ci
920c5f01b2fSopenharmony_ci        SECTION("copy")
921c5f01b2fSopenharmony_ci        {
922c5f01b2fSopenharmony_ci            SECTION("missing 'path'")
923c5f01b2fSopenharmony_ci            {
924c5f01b2fSopenharmony_ci                json j;
925c5f01b2fSopenharmony_ci                json patch = {{{"op", "copy"}}};
926c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
927c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'copy' must have member 'path'", json::parse_error&);
928c5f01b2fSopenharmony_ci#else
929c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'path'", json::parse_error&);
930c5f01b2fSopenharmony_ci#endif
931c5f01b2fSopenharmony_ci            }
932c5f01b2fSopenharmony_ci
933c5f01b2fSopenharmony_ci            SECTION("non-string 'path'")
934c5f01b2fSopenharmony_ci            {
935c5f01b2fSopenharmony_ci                json j;
936c5f01b2fSopenharmony_ci                json patch = {{{"op", "copy"}, {"path", 1}}};
937c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
938c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'copy' must have string member 'path'", json::parse_error&);
939c5f01b2fSopenharmony_ci#else
940c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'path'", json::parse_error&);
941c5f01b2fSopenharmony_ci#endif
942c5f01b2fSopenharmony_ci            }
943c5f01b2fSopenharmony_ci
944c5f01b2fSopenharmony_ci            SECTION("missing 'from'")
945c5f01b2fSopenharmony_ci            {
946c5f01b2fSopenharmony_ci                json j;
947c5f01b2fSopenharmony_ci                json patch = {{{"op", "copy"}, {"path", ""}}};
948c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
949c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'copy' must have member 'from'", json::parse_error&);
950c5f01b2fSopenharmony_ci#else
951c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'from'", json::parse_error&);
952c5f01b2fSopenharmony_ci#endif
953c5f01b2fSopenharmony_ci            }
954c5f01b2fSopenharmony_ci
955c5f01b2fSopenharmony_ci            SECTION("non-string 'from'")
956c5f01b2fSopenharmony_ci            {
957c5f01b2fSopenharmony_ci                json j;
958c5f01b2fSopenharmony_ci                json patch = {{{"op", "copy"}, {"path", ""}, {"from", 1}}};
959c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
960c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'copy' must have string member 'from'", json::parse_error&);
961c5f01b2fSopenharmony_ci#else
962c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'from'", json::parse_error&);
963c5f01b2fSopenharmony_ci#endif
964c5f01b2fSopenharmony_ci            }
965c5f01b2fSopenharmony_ci
966c5f01b2fSopenharmony_ci            SECTION("nonexisting from location (array)")
967c5f01b2fSopenharmony_ci            {
968c5f01b2fSopenharmony_ci                json j = {1, 2, 3};
969c5f01b2fSopenharmony_ci                json patch = {{{"op", "copy"}, {"path", "/0"}, {"from", "/5"}}};
970c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.401] array index 5 is out of range", json::out_of_range&);
971c5f01b2fSopenharmony_ci            }
972c5f01b2fSopenharmony_ci
973c5f01b2fSopenharmony_ci            SECTION("nonexisting from location (object)")
974c5f01b2fSopenharmony_ci            {
975c5f01b2fSopenharmony_ci                json j = {{"foo", 1}, {"bar", 2}};
976c5f01b2fSopenharmony_ci                json patch = {{{"op", "copy"}, {"path", "/fob"}, {"from", "/baz"}}};
977c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found", json::out_of_range&);
978c5f01b2fSopenharmony_ci            }
979c5f01b2fSopenharmony_ci        }
980c5f01b2fSopenharmony_ci
981c5f01b2fSopenharmony_ci        SECTION("test")
982c5f01b2fSopenharmony_ci        {
983c5f01b2fSopenharmony_ci            SECTION("missing 'path'")
984c5f01b2fSopenharmony_ci            {
985c5f01b2fSopenharmony_ci                json j;
986c5f01b2fSopenharmony_ci                json patch = {{{"op", "test"}}};
987c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
988c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'test' must have member 'path'", json::parse_error&);
989c5f01b2fSopenharmony_ci#else
990c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'test' must have member 'path'", json::parse_error&);
991c5f01b2fSopenharmony_ci#endif
992c5f01b2fSopenharmony_ci            }
993c5f01b2fSopenharmony_ci
994c5f01b2fSopenharmony_ci            SECTION("non-string 'path'")
995c5f01b2fSopenharmony_ci            {
996c5f01b2fSopenharmony_ci                json j;
997c5f01b2fSopenharmony_ci                json patch = {{{"op", "test"}, {"path", 1}}};
998c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
999c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'test' must have string member 'path'", json::parse_error&);
1000c5f01b2fSopenharmony_ci#else
1001c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'test' must have string member 'path'", json::parse_error&);
1002c5f01b2fSopenharmony_ci#endif
1003c5f01b2fSopenharmony_ci            }
1004c5f01b2fSopenharmony_ci
1005c5f01b2fSopenharmony_ci            SECTION("missing 'value'")
1006c5f01b2fSopenharmony_ci            {
1007c5f01b2fSopenharmony_ci                json j;
1008c5f01b2fSopenharmony_ci                json patch = {{{"op", "test"}, {"path", ""}}};
1009c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
1010c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: (/0) operation 'test' must have member 'value'", json::parse_error&);
1011c5f01b2fSopenharmony_ci#else
1012c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'test' must have member 'value'", json::parse_error&);
1013c5f01b2fSopenharmony_ci#endif
1014c5f01b2fSopenharmony_ci            }
1015c5f01b2fSopenharmony_ci        }
1016c5f01b2fSopenharmony_ci    }
1017c5f01b2fSopenharmony_ci
1018c5f01b2fSopenharmony_ci    SECTION("Examples from jsonpatch.com")
1019c5f01b2fSopenharmony_ci    {
1020c5f01b2fSopenharmony_ci        SECTION("Simple Example")
1021c5f01b2fSopenharmony_ci        {
1022c5f01b2fSopenharmony_ci            // The original document
1023c5f01b2fSopenharmony_ci            json doc = R"(
1024c5f01b2fSopenharmony_ci                {
1025c5f01b2fSopenharmony_ci                  "baz": "qux",
1026c5f01b2fSopenharmony_ci                  "foo": "bar"
1027c5f01b2fSopenharmony_ci                }
1028c5f01b2fSopenharmony_ci            )"_json;
1029c5f01b2fSopenharmony_ci
1030c5f01b2fSopenharmony_ci            // The patch
1031c5f01b2fSopenharmony_ci            json patch = R"(
1032c5f01b2fSopenharmony_ci                [
1033c5f01b2fSopenharmony_ci                  { "op": "replace", "path": "/baz", "value": "boo" },
1034c5f01b2fSopenharmony_ci                  { "op": "add", "path": "/hello", "value": ["world"] },
1035c5f01b2fSopenharmony_ci                  { "op": "remove", "path": "/foo"}
1036c5f01b2fSopenharmony_ci                ]
1037c5f01b2fSopenharmony_ci            )"_json;
1038c5f01b2fSopenharmony_ci
1039c5f01b2fSopenharmony_ci            // The result
1040c5f01b2fSopenharmony_ci            json result = R"(
1041c5f01b2fSopenharmony_ci                {
1042c5f01b2fSopenharmony_ci                   "baz": "boo",
1043c5f01b2fSopenharmony_ci                   "hello": ["world"]
1044c5f01b2fSopenharmony_ci                }
1045c5f01b2fSopenharmony_ci            )"_json;
1046c5f01b2fSopenharmony_ci
1047c5f01b2fSopenharmony_ci            // check if patched value is as expected
1048c5f01b2fSopenharmony_ci            CHECK(doc.patch(patch) == result);
1049c5f01b2fSopenharmony_ci
1050c5f01b2fSopenharmony_ci            // check roundtrip
1051c5f01b2fSopenharmony_ci            CHECK(doc.patch(json::diff(doc, result)) == result);
1052c5f01b2fSopenharmony_ci        }
1053c5f01b2fSopenharmony_ci
1054c5f01b2fSopenharmony_ci        SECTION("Operations")
1055c5f01b2fSopenharmony_ci        {
1056c5f01b2fSopenharmony_ci            // The original document
1057c5f01b2fSopenharmony_ci            json doc = R"(
1058c5f01b2fSopenharmony_ci                {
1059c5f01b2fSopenharmony_ci                  "biscuits": [
1060c5f01b2fSopenharmony_ci                    {"name":"Digestive"},
1061c5f01b2fSopenharmony_ci                    {"name": "Choco Liebniz"}
1062c5f01b2fSopenharmony_ci                  ]
1063c5f01b2fSopenharmony_ci                }
1064c5f01b2fSopenharmony_ci            )"_json;
1065c5f01b2fSopenharmony_ci
1066c5f01b2fSopenharmony_ci            SECTION("add")
1067c5f01b2fSopenharmony_ci            {
1068c5f01b2fSopenharmony_ci                // The patch
1069c5f01b2fSopenharmony_ci                json patch = R"(
1070c5f01b2fSopenharmony_ci                    [
1071c5f01b2fSopenharmony_ci                        {"op": "add", "path": "/biscuits/1", "value": {"name": "Ginger Nut"}}
1072c5f01b2fSopenharmony_ci                    ]
1073c5f01b2fSopenharmony_ci                )"_json;
1074c5f01b2fSopenharmony_ci
1075c5f01b2fSopenharmony_ci                // The result
1076c5f01b2fSopenharmony_ci                json result = R"(
1077c5f01b2fSopenharmony_ci                    {
1078c5f01b2fSopenharmony_ci                      "biscuits": [
1079c5f01b2fSopenharmony_ci                        {"name": "Digestive"},
1080c5f01b2fSopenharmony_ci                        {"name": "Ginger Nut"},
1081c5f01b2fSopenharmony_ci                        {"name": "Choco Liebniz"}
1082c5f01b2fSopenharmony_ci                      ]
1083c5f01b2fSopenharmony_ci                    }
1084c5f01b2fSopenharmony_ci                )"_json;
1085c5f01b2fSopenharmony_ci
1086c5f01b2fSopenharmony_ci                // check if patched value is as expected
1087c5f01b2fSopenharmony_ci                CHECK(doc.patch(patch) == result);
1088c5f01b2fSopenharmony_ci
1089c5f01b2fSopenharmony_ci                // check roundtrip
1090c5f01b2fSopenharmony_ci                CHECK(doc.patch(json::diff(doc, result)) == result);
1091c5f01b2fSopenharmony_ci            }
1092c5f01b2fSopenharmony_ci
1093c5f01b2fSopenharmony_ci            SECTION("remove")
1094c5f01b2fSopenharmony_ci            {
1095c5f01b2fSopenharmony_ci                // The patch
1096c5f01b2fSopenharmony_ci                json patch = R"(
1097c5f01b2fSopenharmony_ci                    [
1098c5f01b2fSopenharmony_ci                        {"op": "remove", "path": "/biscuits"}
1099c5f01b2fSopenharmony_ci                    ]
1100c5f01b2fSopenharmony_ci                )"_json;
1101c5f01b2fSopenharmony_ci
1102c5f01b2fSopenharmony_ci                // The result
1103c5f01b2fSopenharmony_ci                json result = R"(
1104c5f01b2fSopenharmony_ci                    {}
1105c5f01b2fSopenharmony_ci                )"_json;
1106c5f01b2fSopenharmony_ci
1107c5f01b2fSopenharmony_ci                // check if patched value is as expected
1108c5f01b2fSopenharmony_ci                CHECK(doc.patch(patch) == result);
1109c5f01b2fSopenharmony_ci
1110c5f01b2fSopenharmony_ci                // check roundtrip
1111c5f01b2fSopenharmony_ci                CHECK(doc.patch(json::diff(doc, result)) == result);
1112c5f01b2fSopenharmony_ci            }
1113c5f01b2fSopenharmony_ci
1114c5f01b2fSopenharmony_ci            SECTION("replace")
1115c5f01b2fSopenharmony_ci            {
1116c5f01b2fSopenharmony_ci                // The patch
1117c5f01b2fSopenharmony_ci                json patch = R"(
1118c5f01b2fSopenharmony_ci                    [
1119c5f01b2fSopenharmony_ci                        {"op": "replace", "path": "/biscuits/0/name", "value": "Chocolate Digestive"}
1120c5f01b2fSopenharmony_ci                    ]
1121c5f01b2fSopenharmony_ci                )"_json;
1122c5f01b2fSopenharmony_ci
1123c5f01b2fSopenharmony_ci                // The result
1124c5f01b2fSopenharmony_ci                json result = R"(
1125c5f01b2fSopenharmony_ci                    {
1126c5f01b2fSopenharmony_ci                      "biscuits": [
1127c5f01b2fSopenharmony_ci                        {"name": "Chocolate Digestive"},
1128c5f01b2fSopenharmony_ci                        {"name": "Choco Liebniz"}
1129c5f01b2fSopenharmony_ci                      ]
1130c5f01b2fSopenharmony_ci                    }
1131c5f01b2fSopenharmony_ci                )"_json;
1132c5f01b2fSopenharmony_ci
1133c5f01b2fSopenharmony_ci                // check if patched value is as expected
1134c5f01b2fSopenharmony_ci                CHECK(doc.patch(patch) == result);
1135c5f01b2fSopenharmony_ci
1136c5f01b2fSopenharmony_ci                // check roundtrip
1137c5f01b2fSopenharmony_ci                CHECK(doc.patch(json::diff(doc, result)) == result);
1138c5f01b2fSopenharmony_ci            }
1139c5f01b2fSopenharmony_ci
1140c5f01b2fSopenharmony_ci            SECTION("copy")
1141c5f01b2fSopenharmony_ci            {
1142c5f01b2fSopenharmony_ci                // The patch
1143c5f01b2fSopenharmony_ci                json patch = R"(
1144c5f01b2fSopenharmony_ci                    [
1145c5f01b2fSopenharmony_ci                        {"op": "copy", "from": "/biscuits/0", "path": "/best_biscuit"}
1146c5f01b2fSopenharmony_ci                    ]
1147c5f01b2fSopenharmony_ci                )"_json;
1148c5f01b2fSopenharmony_ci
1149c5f01b2fSopenharmony_ci                // The result
1150c5f01b2fSopenharmony_ci                json result = R"(
1151c5f01b2fSopenharmony_ci                    {
1152c5f01b2fSopenharmony_ci                      "biscuits": [
1153c5f01b2fSopenharmony_ci                        {"name": "Digestive"},
1154c5f01b2fSopenharmony_ci                        {"name": "Choco Liebniz"}
1155c5f01b2fSopenharmony_ci                      ],
1156c5f01b2fSopenharmony_ci                      "best_biscuit": {
1157c5f01b2fSopenharmony_ci                        "name": "Digestive"
1158c5f01b2fSopenharmony_ci                      }
1159c5f01b2fSopenharmony_ci                    }
1160c5f01b2fSopenharmony_ci                )"_json;
1161c5f01b2fSopenharmony_ci
1162c5f01b2fSopenharmony_ci                // check if patched value is as expected
1163c5f01b2fSopenharmony_ci                CHECK(doc.patch(patch) == result);
1164c5f01b2fSopenharmony_ci
1165c5f01b2fSopenharmony_ci                // check roundtrip
1166c5f01b2fSopenharmony_ci                CHECK(doc.patch(json::diff(doc, result)) == result);
1167c5f01b2fSopenharmony_ci            }
1168c5f01b2fSopenharmony_ci
1169c5f01b2fSopenharmony_ci            SECTION("move")
1170c5f01b2fSopenharmony_ci            {
1171c5f01b2fSopenharmony_ci                // The patch
1172c5f01b2fSopenharmony_ci                json patch = R"(
1173c5f01b2fSopenharmony_ci                    [
1174c5f01b2fSopenharmony_ci                        {"op": "move", "from": "/biscuits", "path": "/cookies"}
1175c5f01b2fSopenharmony_ci                    ]
1176c5f01b2fSopenharmony_ci                )"_json;
1177c5f01b2fSopenharmony_ci
1178c5f01b2fSopenharmony_ci                // The result
1179c5f01b2fSopenharmony_ci                json result = R"(
1180c5f01b2fSopenharmony_ci                    {
1181c5f01b2fSopenharmony_ci                      "cookies": [
1182c5f01b2fSopenharmony_ci                        {"name": "Digestive"},
1183c5f01b2fSopenharmony_ci                        {"name": "Choco Liebniz"}
1184c5f01b2fSopenharmony_ci                      ]
1185c5f01b2fSopenharmony_ci                    }
1186c5f01b2fSopenharmony_ci                )"_json;
1187c5f01b2fSopenharmony_ci
1188c5f01b2fSopenharmony_ci                // check if patched value is as expected
1189c5f01b2fSopenharmony_ci                CHECK(doc.patch(patch) == result);
1190c5f01b2fSopenharmony_ci
1191c5f01b2fSopenharmony_ci                // check roundtrip
1192c5f01b2fSopenharmony_ci                CHECK(doc.patch(json::diff(doc, result)) == result);
1193c5f01b2fSopenharmony_ci            }
1194c5f01b2fSopenharmony_ci
1195c5f01b2fSopenharmony_ci            SECTION("test")
1196c5f01b2fSopenharmony_ci            {
1197c5f01b2fSopenharmony_ci                // The patch
1198c5f01b2fSopenharmony_ci                json patch = R"(
1199c5f01b2fSopenharmony_ci                    [
1200c5f01b2fSopenharmony_ci                        {"op": "test", "path": "/best_biscuit/name", "value": "Choco Liebniz"}
1201c5f01b2fSopenharmony_ci                    ]
1202c5f01b2fSopenharmony_ci                )"_json;
1203c5f01b2fSopenharmony_ci
1204c5f01b2fSopenharmony_ci                // the test will fail
1205c5f01b2fSopenharmony_ci                CHECK_THROWS_AS(doc.patch(patch), json::other_error&);
1206c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
1207c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] (/0) unsuccessful: " + patch[0].dump());
1208c5f01b2fSopenharmony_ci#else
1209c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump());
1210c5f01b2fSopenharmony_ci#endif
1211c5f01b2fSopenharmony_ci            }
1212c5f01b2fSopenharmony_ci        }
1213c5f01b2fSopenharmony_ci    }
1214c5f01b2fSopenharmony_ci
1215c5f01b2fSopenharmony_ci    SECTION("Examples from bruth.github.io/jsonpatch-js")
1216c5f01b2fSopenharmony_ci    {
1217c5f01b2fSopenharmony_ci        SECTION("add")
1218c5f01b2fSopenharmony_ci        {
1219c5f01b2fSopenharmony_ci            CHECK(R"( {} )"_json.patch(
1220c5f01b2fSopenharmony_ci                      R"( [{"op": "add", "path": "/foo", "value": "bar"}] )"_json
1221c5f01b2fSopenharmony_ci                  ) == R"( {"foo": "bar"} )"_json);
1222c5f01b2fSopenharmony_ci
1223c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": [1, 3]} )"_json.patch(
1224c5f01b2fSopenharmony_ci                      R"( [{"op": "add", "path": "/foo", "value": "bar"}] )"_json
1225c5f01b2fSopenharmony_ci                  ) == R"( {"foo": "bar"} )"_json);
1226c5f01b2fSopenharmony_ci
1227c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": [{}]} )"_json.patch(
1228c5f01b2fSopenharmony_ci                      R"( [{"op": "add", "path": "/foo/0/bar", "value": "baz"}] )"_json
1229c5f01b2fSopenharmony_ci                  ) == R"( {"foo": [{"bar": "baz"}]} )"_json);
1230c5f01b2fSopenharmony_ci        }
1231c5f01b2fSopenharmony_ci
1232c5f01b2fSopenharmony_ci        SECTION("remove")
1233c5f01b2fSopenharmony_ci        {
1234c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": "bar"} )"_json.patch(
1235c5f01b2fSopenharmony_ci                      R"( [{"op": "remove", "path": "/foo"}] )"_json
1236c5f01b2fSopenharmony_ci                  ) == R"( {} )"_json);
1237c5f01b2fSopenharmony_ci
1238c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch(
1239c5f01b2fSopenharmony_ci                      R"( [{"op": "remove", "path": "/foo/1"}] )"_json
1240c5f01b2fSopenharmony_ci                  ) == R"( {"foo": [1, 3]} )"_json);
1241c5f01b2fSopenharmony_ci
1242c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": [{"bar": "baz"}]} )"_json.patch(
1243c5f01b2fSopenharmony_ci                      R"( [{"op": "remove", "path": "/foo/0/bar"}] )"_json
1244c5f01b2fSopenharmony_ci                  ) == R"( {"foo": [{}]} )"_json);
1245c5f01b2fSopenharmony_ci        }
1246c5f01b2fSopenharmony_ci
1247c5f01b2fSopenharmony_ci        SECTION("replace")
1248c5f01b2fSopenharmony_ci        {
1249c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": "bar"} )"_json.patch(
1250c5f01b2fSopenharmony_ci                      R"( [{"op": "replace", "path": "/foo", "value": 1}] )"_json
1251c5f01b2fSopenharmony_ci                  ) == R"( {"foo": 1} )"_json);
1252c5f01b2fSopenharmony_ci
1253c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch(
1254c5f01b2fSopenharmony_ci                      R"( [{"op": "replace", "path": "/foo/1", "value": 4}] )"_json
1255c5f01b2fSopenharmony_ci                  ) == R"( {"foo": [1, 4, 3]} )"_json);
1256c5f01b2fSopenharmony_ci
1257c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": [{"bar": "baz"}]} )"_json.patch(
1258c5f01b2fSopenharmony_ci                      R"( [{"op": "replace", "path": "/foo/0/bar", "value": 1}] )"_json
1259c5f01b2fSopenharmony_ci                  ) == R"( {"foo": [{"bar": 1}]} )"_json);
1260c5f01b2fSopenharmony_ci        }
1261c5f01b2fSopenharmony_ci
1262c5f01b2fSopenharmony_ci        SECTION("move")
1263c5f01b2fSopenharmony_ci        {
1264c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch(
1265c5f01b2fSopenharmony_ci                      R"( [{"op": "move", "from": "/foo", "path": "/bar"}] )"_json
1266c5f01b2fSopenharmony_ci                  ) == R"( {"bar": [1, 2, 3]} )"_json);
1267c5f01b2fSopenharmony_ci        }
1268c5f01b2fSopenharmony_ci
1269c5f01b2fSopenharmony_ci        SECTION("copy")
1270c5f01b2fSopenharmony_ci        {
1271c5f01b2fSopenharmony_ci            CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch(
1272c5f01b2fSopenharmony_ci                      R"( [{"op": "copy", "from": "/foo/1", "path": "/bar"}] )"_json
1273c5f01b2fSopenharmony_ci                  ) == R"( {"foo": [1, 2, 3], "bar": 2} )"_json);
1274c5f01b2fSopenharmony_ci        }
1275c5f01b2fSopenharmony_ci
1276c5f01b2fSopenharmony_ci        SECTION("copy")
1277c5f01b2fSopenharmony_ci        {
1278c5f01b2fSopenharmony_ci            CHECK_NOTHROW(R"( {"foo": "bar"} )"_json.patch(
1279c5f01b2fSopenharmony_ci                              R"( [{"op": "test", "path": "/foo", "value": "bar"}] )"_json));
1280c5f01b2fSopenharmony_ci        }
1281c5f01b2fSopenharmony_ci    }
1282c5f01b2fSopenharmony_ci
1283c5f01b2fSopenharmony_ci    SECTION("Tests from github.com/json-patch/json-patch-tests")
1284c5f01b2fSopenharmony_ci    {
1285c5f01b2fSopenharmony_ci        for (const auto* filename :
1286c5f01b2fSopenharmony_ci                {
1287c5f01b2fSopenharmony_ci                    TEST_DATA_DIRECTORY "/json-patch-tests/spec_tests.json",
1288c5f01b2fSopenharmony_ci                    TEST_DATA_DIRECTORY "/json-patch-tests/tests.json"
1289c5f01b2fSopenharmony_ci                })
1290c5f01b2fSopenharmony_ci        {
1291c5f01b2fSopenharmony_ci            CAPTURE(filename)
1292c5f01b2fSopenharmony_ci            std::ifstream f(filename);
1293c5f01b2fSopenharmony_ci            json suite = json::parse(f);
1294c5f01b2fSopenharmony_ci
1295c5f01b2fSopenharmony_ci            for (const auto& test : suite)
1296c5f01b2fSopenharmony_ci            {
1297c5f01b2fSopenharmony_ci                INFO_WITH_TEMP(test.value("comment", ""));
1298c5f01b2fSopenharmony_ci
1299c5f01b2fSopenharmony_ci                // skip tests marked as disabled
1300c5f01b2fSopenharmony_ci                if (test.value("disabled", false))
1301c5f01b2fSopenharmony_ci                {
1302c5f01b2fSopenharmony_ci                    continue;
1303c5f01b2fSopenharmony_ci                }
1304c5f01b2fSopenharmony_ci
1305c5f01b2fSopenharmony_ci                const auto& doc = test["doc"];
1306c5f01b2fSopenharmony_ci                const auto& patch = test["patch"];
1307c5f01b2fSopenharmony_ci
1308c5f01b2fSopenharmony_ci                if (test.count("error") == 0)
1309c5f01b2fSopenharmony_ci                {
1310c5f01b2fSopenharmony_ci                    // if an expected value is given, use it; use doc otherwise
1311c5f01b2fSopenharmony_ci                    const auto& expected = test.value("expected", doc);
1312c5f01b2fSopenharmony_ci                    CHECK(doc.patch(patch) == expected);
1313c5f01b2fSopenharmony_ci                }
1314c5f01b2fSopenharmony_ci                else
1315c5f01b2fSopenharmony_ci                {
1316c5f01b2fSopenharmony_ci                    CHECK_THROWS(doc.patch(patch));
1317c5f01b2fSopenharmony_ci                }
1318c5f01b2fSopenharmony_ci            }
1319c5f01b2fSopenharmony_ci        }
1320c5f01b2fSopenharmony_ci    }
1321c5f01b2fSopenharmony_ci}
1322