]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // |
2 | // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com) | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/json | |
8 | // | |
9 | ||
10 | #include <boost/json/value.hpp> | |
11 | ||
12 | #include "test_suite.hpp" | |
13 | ||
14 | BOOST_JSON_NS_BEGIN | |
15 | ||
16 | ||
17 | class pointer_test | |
18 | { | |
19 | bool | |
20 | hasLocation(error_code const& ec) | |
21 | { | |
22 | return ec.has_location(); | |
23 | } | |
24 | ||
25 | bool | |
26 | hasLocation(std::error_code const&) | |
27 | { | |
28 | return true; | |
29 | } | |
30 | ||
31 | value | |
32 | testValue() const | |
33 | { | |
34 | return value{ | |
35 | {"foo", {"bar", "baz", "baf"}}, | |
36 | {"", 0}, | |
37 | {"a/b", 1}, | |
38 | {"c%d", 2}, | |
39 | {"e^f", 3}, | |
40 | {"g|h", 4}, | |
41 | {"i\\j", 5}, | |
42 | {"k\"l", 6}, | |
43 | {" ", 7}, | |
44 | {"m~n", 8}, | |
45 | {"x", object{{"y", "z"}}}, | |
46 | }; | |
47 | } | |
48 | ||
49 | value | |
50 | bigObject() const | |
51 | { | |
52 | object result; | |
53 | for (int i = 0; i < 50; ++i) | |
54 | { | |
55 | result.emplace(std::to_string(i), i); | |
56 | } | |
57 | return result; | |
58 | } | |
59 | ||
60 | public: | |
61 | void | |
62 | testRootPointer() | |
63 | { | |
64 | value const jv = testValue(); | |
65 | BOOST_TEST(&jv.at_pointer("") == &jv); | |
66 | } | |
67 | ||
68 | void | |
69 | testChildPointer() | |
70 | { | |
71 | value const jv = testValue(); | |
72 | BOOST_TEST(&jv.at_pointer("/foo")== &jv.at("foo")); | |
73 | BOOST_TEST(&jv.at_pointer("/c%d")== &jv.at("c%d")); | |
74 | BOOST_TEST(&jv.at_pointer("/e^f")== &jv.at("e^f")); | |
75 | BOOST_TEST(&jv.at_pointer("/g|h")== &jv.at("g|h")); | |
76 | BOOST_TEST(&jv.at_pointer("/")== &jv.at("")); | |
77 | BOOST_TEST(&jv.at_pointer("/i\\j")== &jv.at("i\\j")); | |
78 | BOOST_TEST(&jv.at_pointer("/k\"l")== &jv.at("k\"l")); | |
79 | BOOST_TEST(&jv.at_pointer("/ ")== &jv.at(" ")); | |
80 | } | |
81 | ||
82 | void | |
83 | testEscaped() | |
84 | { | |
85 | value const jv = testValue(); | |
86 | BOOST_TEST(&jv.at_pointer("/a~1b")== &jv.at("a/b")); | |
87 | BOOST_TEST(&jv.at_pointer("/m~0n")== &jv.at("m~n")); | |
88 | } | |
89 | ||
90 | void | |
91 | testNested() | |
92 | { | |
93 | value const jv = testValue(); | |
94 | BOOST_TEST(&jv.at_pointer("/foo/0") == &jv.at("foo").at(0)); | |
95 | BOOST_TEST(&jv.at_pointer("/foo/1") == &jv.at("foo").at(1)); | |
96 | BOOST_TEST(&jv.at_pointer("/x/y") == &jv.at("x").at("y")); | |
97 | ||
98 | { | |
99 | value v1; | |
100 | object& o1 = v1.emplace_object(); | |
101 | object& o2 = (o1["very"] = value()).emplace_object(); | |
102 | object& o3 = (o2["deep"] = value()).emplace_object(); | |
103 | ||
104 | array& a1 = (o3["path"] = value()).emplace_array(); | |
105 | a1.emplace_back(value()); | |
106 | ||
107 | array& a2 = a1.emplace_back(value()).emplace_array(); | |
108 | a2.emplace_back(value()); | |
109 | a2.emplace_back(value()); | |
110 | ||
111 | array& a3 = a2.emplace_back(value()).emplace_array(); | |
112 | object& o4 = a3.emplace_back(value()).emplace_object(); | |
113 | object& o5 = (o4["0"] = value()).emplace_object(); | |
114 | value& v2 = o5["fin"] = value(); | |
115 | ||
116 | BOOST_TEST(&v1.at_pointer("/very/deep/path/1/2/0/0/fin") == &v2); | |
117 | } | |
118 | } | |
119 | ||
120 | void | |
121 | testErrors() | |
122 | { | |
123 | value const jv = testValue(); | |
124 | BOOST_TEST_THROWS(jv.at_pointer("foo"), system_error); | |
125 | BOOST_TEST_THROWS(jv.at_pointer("/fo"), system_error); | |
126 | BOOST_TEST_THROWS(jv.at_pointer("/m~"), system_error); | |
127 | BOOST_TEST_THROWS(jv.at_pointer("/m~n"), system_error); | |
128 | BOOST_TEST_THROWS(jv.at_pointer("/foo/bar"), system_error); | |
129 | BOOST_TEST_THROWS(jv.at_pointer("/foo/"), system_error); | |
130 | BOOST_TEST_THROWS(jv.at_pointer("/foo/01"), system_error); | |
131 | BOOST_TEST_THROWS(jv.at_pointer("/foo/2b"), system_error); | |
132 | BOOST_TEST_THROWS(jv.at_pointer("/x/y/z"), system_error); | |
133 | } | |
134 | ||
135 | template<class ErrorCode> | |
136 | void | |
137 | testNonThrowing() | |
138 | { | |
139 | value jv = testValue(); | |
140 | ErrorCode ec = error::syntax; | |
141 | BOOST_TEST(jv.find_pointer("/foo/0", ec) == &jv.at("foo").at(0)); | |
142 | BOOST_TEST(!ec); | |
143 | ||
144 | auto const& cjv = jv; | |
145 | ec = error::syntax; | |
146 | BOOST_TEST(cjv.find_pointer("/foo/1", ec) == &jv.at("foo").at(1)); | |
147 | BOOST_TEST(!ec); | |
148 | ||
149 | jv.find_pointer("foo", ec); | |
150 | BOOST_TEST(ec == error::missing_slash); | |
151 | BOOST_TEST(hasLocation(ec)); | |
152 | ||
153 | jv.find_pointer("/fo", ec); | |
154 | BOOST_TEST(ec == error::not_found); | |
155 | BOOST_TEST(hasLocation(ec)); | |
156 | ||
157 | jv.find_pointer("/foo/25", ec); | |
158 | BOOST_TEST(ec == error::not_found); | |
159 | BOOST_TEST(hasLocation(ec)); | |
160 | ||
161 | value(object()).find_pointer("/foo", ec); | |
162 | BOOST_TEST(ec == error::not_found); | |
163 | BOOST_TEST(hasLocation(ec)); | |
164 | ||
165 | bigObject().find_pointer("/foo", ec); | |
166 | BOOST_TEST(ec == error::not_found); | |
167 | BOOST_TEST(hasLocation(ec)); | |
168 | ||
169 | jv.find_pointer("/m~", ec); | |
170 | BOOST_TEST(ec == error::invalid_escape); | |
171 | BOOST_TEST(hasLocation(ec)); | |
172 | ||
173 | jv.find_pointer("/m~n", ec); | |
174 | BOOST_TEST(ec == error::invalid_escape); | |
175 | BOOST_TEST(hasLocation(ec)); | |
176 | ||
177 | jv.find_pointer("/foo/bar", ec); | |
178 | BOOST_TEST(ec == error::token_not_number); | |
179 | BOOST_TEST(hasLocation(ec)); | |
180 | ||
181 | jv.find_pointer("/foo/", ec); | |
182 | BOOST_TEST(ec == error::token_not_number); | |
183 | BOOST_TEST(hasLocation(ec)); | |
184 | ||
185 | jv.find_pointer("/foo/01", ec); | |
186 | BOOST_TEST(ec == error::token_not_number); | |
187 | BOOST_TEST(hasLocation(ec)); | |
188 | ||
189 | jv.find_pointer("/foo/2b", ec); | |
190 | BOOST_TEST(ec == error::token_not_number); | |
191 | BOOST_TEST(hasLocation(ec)); | |
192 | ||
193 | jv.find_pointer("/foo/2.", ec); | |
194 | BOOST_TEST(ec == error::token_not_number); | |
195 | BOOST_TEST(hasLocation(ec)); | |
196 | ||
197 | jv.find_pointer("/foo/-", ec); | |
198 | BOOST_TEST(ec == error::past_the_end); | |
199 | BOOST_TEST(hasLocation(ec)); | |
200 | ||
201 | jv.find_pointer("/foo/-/x", ec); | |
202 | BOOST_TEST(ec == error::past_the_end); | |
203 | BOOST_TEST(hasLocation(ec)); | |
204 | ||
205 | jv.find_pointer("/foo/-1", ec); | |
206 | BOOST_TEST(ec == error::token_not_number); | |
207 | BOOST_TEST(hasLocation(ec)); | |
208 | ||
209 | jv.find_pointer("/x/y/z", ec); | |
210 | BOOST_TEST(ec == error::value_is_scalar); | |
211 | BOOST_TEST(hasLocation(ec)); | |
212 | ||
213 | string s = "/foo/"; | |
214 | s += std::to_string((std::numeric_limits<std::size_t>::max)()); | |
215 | if ( '9' == s[s.size() - 1] ) | |
216 | { | |
217 | for (std::size_t i = 6; i < s.size(); ++i) | |
218 | { | |
219 | s[i] = '0'; | |
220 | } | |
221 | s[5] = '1'; | |
222 | s += "0"; | |
223 | } | |
224 | else | |
225 | { | |
226 | ++s[s.size() - 1]; | |
227 | } | |
228 | jv.find_pointer(s, ec); | |
229 | BOOST_TEST(ec == error::token_overflow); | |
230 | BOOST_TEST(hasLocation(ec)); | |
231 | } | |
232 | ||
233 | void | |
234 | run() | |
235 | { | |
236 | testRootPointer(); | |
237 | testChildPointer(); | |
238 | testEscaped(); | |
239 | testNested(); | |
240 | testErrors(); | |
241 | testNonThrowing<error_code>(); | |
242 | testNonThrowing<std::error_code>(); | |
243 | } | |
244 | }; | |
245 | ||
246 | TEST_SUITE(pointer_test, "boost.json.pointer"); | |
247 | ||
248 | BOOST_JSON_NS_END |