]>
Commit | Line | Data |
---|---|---|
31f18b77 FG |
1 | // Tencent is pleased to support the open source community by making RapidJSON available. |
2 | // | |
1e59de90 | 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. |
31f18b77 FG |
4 | // |
5 | // Licensed under the MIT License (the "License"); you may not use this file except | |
6 | // in compliance with the License. You may obtain a copy of the License at | |
7 | // | |
8 | // http://opensource.org/licenses/MIT | |
9 | // | |
10 | // Unless required by applicable law or agreed to in writing, software distributed | |
11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | |
12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the | |
13 | // specific language governing permissions and limitations under the License. | |
14 | ||
15 | #include "unittest.h" | |
16 | #include "rapidjson/pointer.h" | |
17 | #include "rapidjson/stringbuffer.h" | |
1e59de90 | 18 | #include "rapidjson/ostreamwrapper.h" |
31f18b77 | 19 | #include <sstream> |
1e59de90 TL |
20 | #include <map> |
21 | #include <algorithm> | |
31f18b77 FG |
22 | |
23 | using namespace rapidjson; | |
24 | ||
25 | static const char kJson[] = "{\n" | |
26 | " \"foo\":[\"bar\", \"baz\"],\n" | |
27 | " \"\" : 0,\n" | |
28 | " \"a/b\" : 1,\n" | |
29 | " \"c%d\" : 2,\n" | |
30 | " \"e^f\" : 3,\n" | |
31 | " \"g|h\" : 4,\n" | |
32 | " \"i\\\\j\" : 5,\n" | |
33 | " \"k\\\"l\" : 6,\n" | |
34 | " \" \" : 7,\n" | |
35 | " \"m~n\" : 8\n" | |
36 | "}"; | |
37 | ||
38 | TEST(Pointer, DefaultConstructor) { | |
39 | Pointer p; | |
40 | EXPECT_TRUE(p.IsValid()); | |
41 | EXPECT_EQ(0u, p.GetTokenCount()); | |
42 | } | |
43 | ||
44 | TEST(Pointer, Parse) { | |
45 | { | |
46 | Pointer p(""); | |
47 | EXPECT_TRUE(p.IsValid()); | |
48 | EXPECT_EQ(0u, p.GetTokenCount()); | |
49 | } | |
50 | ||
51 | { | |
52 | Pointer p("/"); | |
53 | EXPECT_TRUE(p.IsValid()); | |
54 | EXPECT_EQ(1u, p.GetTokenCount()); | |
55 | EXPECT_EQ(0u, p.GetTokens()[0].length); | |
56 | EXPECT_STREQ("", p.GetTokens()[0].name); | |
57 | EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index); | |
58 | } | |
59 | ||
60 | { | |
61 | Pointer p("/foo"); | |
62 | EXPECT_TRUE(p.IsValid()); | |
63 | EXPECT_EQ(1u, p.GetTokenCount()); | |
64 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
65 | EXPECT_STREQ("foo", p.GetTokens()[0].name); | |
66 | EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index); | |
67 | } | |
68 | ||
69 | #if RAPIDJSON_HAS_STDSTRING | |
70 | { | |
71 | Pointer p(std::string("/foo")); | |
72 | EXPECT_TRUE(p.IsValid()); | |
73 | EXPECT_EQ(1u, p.GetTokenCount()); | |
74 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
75 | EXPECT_STREQ("foo", p.GetTokens()[0].name); | |
76 | EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index); | |
77 | } | |
78 | #endif | |
79 | ||
80 | { | |
81 | Pointer p("/foo/0"); | |
82 | EXPECT_TRUE(p.IsValid()); | |
83 | EXPECT_EQ(2u, p.GetTokenCount()); | |
84 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
85 | EXPECT_STREQ("foo", p.GetTokens()[0].name); | |
86 | EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index); | |
87 | EXPECT_EQ(1u, p.GetTokens()[1].length); | |
88 | EXPECT_STREQ("0", p.GetTokens()[1].name); | |
89 | EXPECT_EQ(0u, p.GetTokens()[1].index); | |
90 | } | |
91 | ||
92 | { | |
93 | // Unescape ~1 | |
94 | Pointer p("/a~1b"); | |
95 | EXPECT_TRUE(p.IsValid()); | |
96 | EXPECT_EQ(1u, p.GetTokenCount()); | |
97 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
98 | EXPECT_STREQ("a/b", p.GetTokens()[0].name); | |
99 | } | |
100 | ||
101 | { | |
102 | // Unescape ~0 | |
103 | Pointer p("/m~0n"); | |
104 | EXPECT_TRUE(p.IsValid()); | |
105 | EXPECT_EQ(1u, p.GetTokenCount()); | |
106 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
107 | EXPECT_STREQ("m~n", p.GetTokens()[0].name); | |
108 | } | |
109 | ||
110 | { | |
111 | // empty name | |
112 | Pointer p("/"); | |
113 | EXPECT_TRUE(p.IsValid()); | |
114 | EXPECT_EQ(1u, p.GetTokenCount()); | |
115 | EXPECT_EQ(0u, p.GetTokens()[0].length); | |
116 | EXPECT_STREQ("", p.GetTokens()[0].name); | |
117 | } | |
118 | ||
119 | { | |
120 | // empty and non-empty name | |
121 | Pointer p("//a"); | |
122 | EXPECT_TRUE(p.IsValid()); | |
123 | EXPECT_EQ(2u, p.GetTokenCount()); | |
124 | EXPECT_EQ(0u, p.GetTokens()[0].length); | |
125 | EXPECT_STREQ("", p.GetTokens()[0].name); | |
126 | EXPECT_EQ(1u, p.GetTokens()[1].length); | |
127 | EXPECT_STREQ("a", p.GetTokens()[1].name); | |
128 | } | |
129 | ||
130 | { | |
131 | // Null characters | |
132 | Pointer p("/\0\0", 3); | |
133 | EXPECT_TRUE(p.IsValid()); | |
134 | EXPECT_EQ(1u, p.GetTokenCount()); | |
135 | EXPECT_EQ(2u, p.GetTokens()[0].length); | |
136 | EXPECT_EQ('\0', p.GetTokens()[0].name[0]); | |
137 | EXPECT_EQ('\0', p.GetTokens()[0].name[1]); | |
138 | EXPECT_EQ('\0', p.GetTokens()[0].name[2]); | |
139 | } | |
140 | ||
141 | { | |
142 | // Valid index | |
143 | Pointer p("/123"); | |
144 | EXPECT_TRUE(p.IsValid()); | |
145 | EXPECT_EQ(1u, p.GetTokenCount()); | |
146 | EXPECT_STREQ("123", p.GetTokens()[0].name); | |
147 | EXPECT_EQ(123u, p.GetTokens()[0].index); | |
148 | } | |
149 | ||
150 | { | |
151 | // Invalid index (with leading zero) | |
152 | Pointer p("/01"); | |
153 | EXPECT_TRUE(p.IsValid()); | |
154 | EXPECT_EQ(1u, p.GetTokenCount()); | |
155 | EXPECT_STREQ("01", p.GetTokens()[0].name); | |
156 | EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index); | |
157 | } | |
158 | ||
159 | if (sizeof(SizeType) == 4) { | |
160 | // Invalid index (overflow) | |
161 | Pointer p("/4294967296"); | |
162 | EXPECT_TRUE(p.IsValid()); | |
163 | EXPECT_EQ(1u, p.GetTokenCount()); | |
164 | EXPECT_STREQ("4294967296", p.GetTokens()[0].name); | |
165 | EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index); | |
166 | } | |
167 | ||
168 | { | |
169 | // kPointerParseErrorTokenMustBeginWithSolidus | |
170 | Pointer p(" "); | |
171 | EXPECT_FALSE(p.IsValid()); | |
172 | EXPECT_EQ(kPointerParseErrorTokenMustBeginWithSolidus, p.GetParseErrorCode()); | |
173 | EXPECT_EQ(0u, p.GetParseErrorOffset()); | |
174 | } | |
175 | ||
176 | { | |
177 | // kPointerParseErrorInvalidEscape | |
178 | Pointer p("/~"); | |
179 | EXPECT_FALSE(p.IsValid()); | |
180 | EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode()); | |
181 | EXPECT_EQ(2u, p.GetParseErrorOffset()); | |
182 | } | |
183 | ||
184 | { | |
185 | // kPointerParseErrorInvalidEscape | |
186 | Pointer p("/~2"); | |
187 | EXPECT_FALSE(p.IsValid()); | |
188 | EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode()); | |
189 | EXPECT_EQ(2u, p.GetParseErrorOffset()); | |
190 | } | |
191 | } | |
192 | ||
193 | TEST(Pointer, Parse_URIFragment) { | |
194 | { | |
195 | Pointer p("#"); | |
196 | EXPECT_TRUE(p.IsValid()); | |
197 | EXPECT_EQ(0u, p.GetTokenCount()); | |
198 | } | |
199 | ||
200 | { | |
201 | Pointer p("#/foo"); | |
202 | EXPECT_TRUE(p.IsValid()); | |
203 | EXPECT_EQ(1u, p.GetTokenCount()); | |
204 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
205 | EXPECT_STREQ("foo", p.GetTokens()[0].name); | |
206 | } | |
207 | ||
208 | { | |
209 | Pointer p("#/foo/0"); | |
210 | EXPECT_TRUE(p.IsValid()); | |
211 | EXPECT_EQ(2u, p.GetTokenCount()); | |
212 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
213 | EXPECT_STREQ("foo", p.GetTokens()[0].name); | |
214 | EXPECT_EQ(1u, p.GetTokens()[1].length); | |
215 | EXPECT_STREQ("0", p.GetTokens()[1].name); | |
216 | EXPECT_EQ(0u, p.GetTokens()[1].index); | |
217 | } | |
218 | ||
219 | { | |
220 | // Unescape ~1 | |
221 | Pointer p("#/a~1b"); | |
222 | EXPECT_TRUE(p.IsValid()); | |
223 | EXPECT_EQ(1u, p.GetTokenCount()); | |
224 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
225 | EXPECT_STREQ("a/b", p.GetTokens()[0].name); | |
226 | } | |
227 | ||
228 | { | |
229 | // Unescape ~0 | |
230 | Pointer p("#/m~0n"); | |
231 | EXPECT_TRUE(p.IsValid()); | |
232 | EXPECT_EQ(1u, p.GetTokenCount()); | |
233 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
234 | EXPECT_STREQ("m~n", p.GetTokens()[0].name); | |
235 | } | |
236 | ||
237 | { | |
238 | // empty name | |
239 | Pointer p("#/"); | |
240 | EXPECT_TRUE(p.IsValid()); | |
241 | EXPECT_EQ(1u, p.GetTokenCount()); | |
242 | EXPECT_EQ(0u, p.GetTokens()[0].length); | |
243 | EXPECT_STREQ("", p.GetTokens()[0].name); | |
244 | } | |
245 | ||
246 | { | |
247 | // empty and non-empty name | |
248 | Pointer p("#//a"); | |
249 | EXPECT_TRUE(p.IsValid()); | |
250 | EXPECT_EQ(2u, p.GetTokenCount()); | |
251 | EXPECT_EQ(0u, p.GetTokens()[0].length); | |
252 | EXPECT_STREQ("", p.GetTokens()[0].name); | |
253 | EXPECT_EQ(1u, p.GetTokens()[1].length); | |
254 | EXPECT_STREQ("a", p.GetTokens()[1].name); | |
255 | } | |
256 | ||
257 | { | |
258 | // Null characters | |
259 | Pointer p("#/%00%00"); | |
260 | EXPECT_TRUE(p.IsValid()); | |
261 | EXPECT_EQ(1u, p.GetTokenCount()); | |
262 | EXPECT_EQ(2u, p.GetTokens()[0].length); | |
263 | EXPECT_EQ('\0', p.GetTokens()[0].name[0]); | |
264 | EXPECT_EQ('\0', p.GetTokens()[0].name[1]); | |
265 | EXPECT_EQ('\0', p.GetTokens()[0].name[2]); | |
266 | } | |
267 | ||
268 | { | |
269 | // Percentage Escapes | |
270 | EXPECT_STREQ("c%d", Pointer("#/c%25d").GetTokens()[0].name); | |
271 | EXPECT_STREQ("e^f", Pointer("#/e%5Ef").GetTokens()[0].name); | |
272 | EXPECT_STREQ("g|h", Pointer("#/g%7Ch").GetTokens()[0].name); | |
273 | EXPECT_STREQ("i\\j", Pointer("#/i%5Cj").GetTokens()[0].name); | |
274 | EXPECT_STREQ("k\"l", Pointer("#/k%22l").GetTokens()[0].name); | |
275 | EXPECT_STREQ(" ", Pointer("#/%20").GetTokens()[0].name); | |
276 | } | |
277 | ||
278 | { | |
279 | // Valid index | |
280 | Pointer p("#/123"); | |
281 | EXPECT_TRUE(p.IsValid()); | |
282 | EXPECT_EQ(1u, p.GetTokenCount()); | |
283 | EXPECT_STREQ("123", p.GetTokens()[0].name); | |
284 | EXPECT_EQ(123u, p.GetTokens()[0].index); | |
285 | } | |
286 | ||
287 | { | |
288 | // Invalid index (with leading zero) | |
289 | Pointer p("#/01"); | |
290 | EXPECT_TRUE(p.IsValid()); | |
291 | EXPECT_EQ(1u, p.GetTokenCount()); | |
292 | EXPECT_STREQ("01", p.GetTokens()[0].name); | |
293 | EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index); | |
294 | } | |
295 | ||
296 | if (sizeof(SizeType) == 4) { | |
297 | // Invalid index (overflow) | |
298 | Pointer p("#/4294967296"); | |
299 | EXPECT_TRUE(p.IsValid()); | |
300 | EXPECT_EQ(1u, p.GetTokenCount()); | |
301 | EXPECT_STREQ("4294967296", p.GetTokens()[0].name); | |
302 | EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index); | |
303 | } | |
304 | ||
305 | { | |
306 | // Decode UTF-8 perecent encoding to UTF-8 | |
307 | Pointer p("#/%C2%A2"); | |
308 | EXPECT_TRUE(p.IsValid()); | |
309 | EXPECT_EQ(1u, p.GetTokenCount()); | |
310 | EXPECT_STREQ("\xC2\xA2", p.GetTokens()[0].name); | |
311 | } | |
312 | ||
313 | { | |
314 | // Decode UTF-8 perecent encoding to UTF-16 | |
315 | GenericPointer<GenericValue<UTF16<> > > p(L"#/%C2%A2"); | |
316 | EXPECT_TRUE(p.IsValid()); | |
317 | EXPECT_EQ(1u, p.GetTokenCount()); | |
318 | EXPECT_EQ(static_cast<UTF16<>::Ch>(0x00A2), p.GetTokens()[0].name[0]); | |
319 | EXPECT_EQ(1u, p.GetTokens()[0].length); | |
320 | } | |
321 | ||
322 | { | |
323 | // Decode UTF-8 perecent encoding to UTF-16 | |
324 | GenericPointer<GenericValue<UTF16<> > > p(L"#/%E2%82%AC"); | |
325 | EXPECT_TRUE(p.IsValid()); | |
326 | EXPECT_EQ(1u, p.GetTokenCount()); | |
327 | EXPECT_EQ(static_cast<UTF16<>::Ch>(0x20AC), p.GetTokens()[0].name[0]); | |
328 | EXPECT_EQ(1u, p.GetTokens()[0].length); | |
329 | } | |
330 | ||
331 | { | |
332 | // kPointerParseErrorTokenMustBeginWithSolidus | |
333 | Pointer p("# "); | |
334 | EXPECT_FALSE(p.IsValid()); | |
335 | EXPECT_EQ(kPointerParseErrorTokenMustBeginWithSolidus, p.GetParseErrorCode()); | |
336 | EXPECT_EQ(1u, p.GetParseErrorOffset()); | |
337 | } | |
338 | ||
339 | { | |
340 | // kPointerParseErrorInvalidEscape | |
341 | Pointer p("#/~"); | |
342 | EXPECT_FALSE(p.IsValid()); | |
343 | EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode()); | |
344 | EXPECT_EQ(3u, p.GetParseErrorOffset()); | |
345 | } | |
346 | ||
347 | { | |
348 | // kPointerParseErrorInvalidEscape | |
349 | Pointer p("#/~2"); | |
350 | EXPECT_FALSE(p.IsValid()); | |
351 | EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode()); | |
352 | EXPECT_EQ(3u, p.GetParseErrorOffset()); | |
353 | } | |
354 | ||
355 | { | |
356 | // kPointerParseErrorInvalidPercentEncoding | |
357 | Pointer p("#/%"); | |
358 | EXPECT_FALSE(p.IsValid()); | |
359 | EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode()); | |
360 | EXPECT_EQ(2u, p.GetParseErrorOffset()); | |
361 | } | |
362 | ||
363 | { | |
364 | // kPointerParseErrorInvalidPercentEncoding (invalid hex) | |
365 | Pointer p("#/%g0"); | |
366 | EXPECT_FALSE(p.IsValid()); | |
367 | EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode()); | |
368 | EXPECT_EQ(2u, p.GetParseErrorOffset()); | |
369 | } | |
370 | ||
371 | { | |
372 | // kPointerParseErrorInvalidPercentEncoding (invalid hex) | |
373 | Pointer p("#/%0g"); | |
374 | EXPECT_FALSE(p.IsValid()); | |
375 | EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode()); | |
376 | EXPECT_EQ(2u, p.GetParseErrorOffset()); | |
377 | } | |
378 | ||
379 | { | |
380 | // kPointerParseErrorInvalidPercentEncoding (incomplete UTF-8 sequence) | |
381 | Pointer p("#/%C2"); | |
382 | EXPECT_FALSE(p.IsValid()); | |
383 | EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode()); | |
384 | EXPECT_EQ(2u, p.GetParseErrorOffset()); | |
385 | } | |
386 | ||
387 | { | |
388 | // kPointerParseErrorCharacterMustPercentEncode | |
389 | Pointer p("#/ "); | |
390 | EXPECT_FALSE(p.IsValid()); | |
391 | EXPECT_EQ(kPointerParseErrorCharacterMustPercentEncode, p.GetParseErrorCode()); | |
392 | EXPECT_EQ(2u, p.GetParseErrorOffset()); | |
393 | } | |
394 | ||
395 | { | |
396 | // kPointerParseErrorCharacterMustPercentEncode | |
397 | Pointer p("#/\n"); | |
398 | EXPECT_FALSE(p.IsValid()); | |
399 | EXPECT_EQ(kPointerParseErrorCharacterMustPercentEncode, p.GetParseErrorCode()); | |
400 | EXPECT_EQ(2u, p.GetParseErrorOffset()); | |
401 | } | |
402 | } | |
403 | ||
404 | TEST(Pointer, Stringify) { | |
405 | // Test by roundtrip | |
406 | const char* sources[] = { | |
407 | "", | |
408 | "/foo", | |
409 | "/foo/0", | |
410 | "/", | |
411 | "/a~1b", | |
412 | "/c%d", | |
413 | "/e^f", | |
414 | "/g|h", | |
415 | "/i\\j", | |
416 | "/k\"l", | |
417 | "/ ", | |
418 | "/m~0n", | |
419 | "/\xC2\xA2", | |
420 | "/\xE2\x82\xAC", | |
421 | "/\xF0\x9D\x84\x9E" | |
422 | }; | |
423 | ||
424 | for (size_t i = 0; i < sizeof(sources) / sizeof(sources[0]); i++) { | |
425 | Pointer p(sources[i]); | |
426 | StringBuffer s; | |
427 | EXPECT_TRUE(p.Stringify(s)); | |
428 | EXPECT_STREQ(sources[i], s.GetString()); | |
429 | ||
430 | // Stringify to URI fragment | |
431 | StringBuffer s2; | |
432 | EXPECT_TRUE(p.StringifyUriFragment(s2)); | |
433 | Pointer p2(s2.GetString(), s2.GetSize()); | |
434 | EXPECT_TRUE(p2.IsValid()); | |
435 | EXPECT_TRUE(p == p2); | |
436 | } | |
437 | ||
438 | { | |
439 | // Strigify to URI fragment with an invalid UTF-8 sequence | |
440 | Pointer p("/\xC2"); | |
441 | StringBuffer s; | |
442 | EXPECT_FALSE(p.StringifyUriFragment(s)); | |
443 | } | |
444 | } | |
445 | ||
446 | // Construct a Pointer with static tokens, no dynamic allocation involved. | |
1e59de90 TL |
447 | #define NAME(s) { s, static_cast<SizeType>(sizeof(s) / sizeof(s[0]) - 1), kPointerInvalidIndex } |
448 | #define INDEX(i) { #i, static_cast<SizeType>(sizeof(#i) - 1), i } | |
31f18b77 FG |
449 | |
450 | static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(0) }; // equivalent to "/foo/0" | |
451 | ||
452 | #undef NAME | |
453 | #undef INDEX | |
454 | ||
455 | TEST(Pointer, ConstructorWithToken) { | |
456 | Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); | |
457 | EXPECT_TRUE(p.IsValid()); | |
458 | EXPECT_EQ(2u, p.GetTokenCount()); | |
459 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
460 | EXPECT_STREQ("foo", p.GetTokens()[0].name); | |
461 | EXPECT_EQ(1u, p.GetTokens()[1].length); | |
462 | EXPECT_STREQ("0", p.GetTokens()[1].name); | |
463 | EXPECT_EQ(0u, p.GetTokens()[1].index); | |
464 | } | |
465 | ||
466 | TEST(Pointer, CopyConstructor) { | |
467 | { | |
1e59de90 TL |
468 | CrtAllocator allocator; |
469 | Pointer p("/foo/0", &allocator); | |
31f18b77 FG |
470 | Pointer q(p); |
471 | EXPECT_TRUE(q.IsValid()); | |
472 | EXPECT_EQ(2u, q.GetTokenCount()); | |
473 | EXPECT_EQ(3u, q.GetTokens()[0].length); | |
474 | EXPECT_STREQ("foo", q.GetTokens()[0].name); | |
475 | EXPECT_EQ(1u, q.GetTokens()[1].length); | |
476 | EXPECT_STREQ("0", q.GetTokens()[1].name); | |
477 | EXPECT_EQ(0u, q.GetTokens()[1].index); | |
1e59de90 TL |
478 | |
479 | // Copied pointer needs to have its own allocator | |
480 | EXPECT_NE(&p.GetAllocator(), &q.GetAllocator()); | |
31f18b77 FG |
481 | } |
482 | ||
483 | // Static tokens | |
484 | { | |
485 | Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); | |
486 | Pointer q(p); | |
487 | EXPECT_TRUE(q.IsValid()); | |
488 | EXPECT_EQ(2u, q.GetTokenCount()); | |
489 | EXPECT_EQ(3u, q.GetTokens()[0].length); | |
490 | EXPECT_STREQ("foo", q.GetTokens()[0].name); | |
491 | EXPECT_EQ(1u, q.GetTokens()[1].length); | |
492 | EXPECT_STREQ("0", q.GetTokens()[1].name); | |
493 | EXPECT_EQ(0u, q.GetTokens()[1].index); | |
494 | } | |
495 | } | |
496 | ||
497 | TEST(Pointer, Assignment) { | |
498 | { | |
1e59de90 TL |
499 | CrtAllocator allocator; |
500 | Pointer p("/foo/0", &allocator); | |
31f18b77 FG |
501 | Pointer q; |
502 | q = p; | |
503 | EXPECT_TRUE(q.IsValid()); | |
504 | EXPECT_EQ(2u, q.GetTokenCount()); | |
505 | EXPECT_EQ(3u, q.GetTokens()[0].length); | |
506 | EXPECT_STREQ("foo", q.GetTokens()[0].name); | |
507 | EXPECT_EQ(1u, q.GetTokens()[1].length); | |
508 | EXPECT_STREQ("0", q.GetTokens()[1].name); | |
509 | EXPECT_EQ(0u, q.GetTokens()[1].index); | |
1e59de90 TL |
510 | EXPECT_NE(&p.GetAllocator(), &q.GetAllocator()); |
511 | q = static_cast<const Pointer &>(q); | |
31f18b77 FG |
512 | EXPECT_TRUE(q.IsValid()); |
513 | EXPECT_EQ(2u, q.GetTokenCount()); | |
514 | EXPECT_EQ(3u, q.GetTokens()[0].length); | |
515 | EXPECT_STREQ("foo", q.GetTokens()[0].name); | |
516 | EXPECT_EQ(1u, q.GetTokens()[1].length); | |
517 | EXPECT_STREQ("0", q.GetTokens()[1].name); | |
518 | EXPECT_EQ(0u, q.GetTokens()[1].index); | |
1e59de90 | 519 | EXPECT_NE(&p.GetAllocator(), &q.GetAllocator()); |
31f18b77 FG |
520 | } |
521 | ||
522 | // Static tokens | |
523 | { | |
524 | Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); | |
525 | Pointer q; | |
526 | q = p; | |
527 | EXPECT_TRUE(q.IsValid()); | |
528 | EXPECT_EQ(2u, q.GetTokenCount()); | |
529 | EXPECT_EQ(3u, q.GetTokens()[0].length); | |
530 | EXPECT_STREQ("foo", q.GetTokens()[0].name); | |
531 | EXPECT_EQ(1u, q.GetTokens()[1].length); | |
532 | EXPECT_STREQ("0", q.GetTokens()[1].name); | |
533 | EXPECT_EQ(0u, q.GetTokens()[1].index); | |
534 | } | |
535 | } | |
536 | ||
1e59de90 TL |
537 | TEST(Pointer, Swap) { |
538 | Pointer p("/foo/0"); | |
539 | Pointer q(&p.GetAllocator()); | |
540 | ||
541 | q.Swap(p); | |
542 | EXPECT_EQ(&q.GetAllocator(), &p.GetAllocator()); | |
543 | EXPECT_TRUE(p.IsValid()); | |
544 | EXPECT_TRUE(q.IsValid()); | |
545 | EXPECT_EQ(0u, p.GetTokenCount()); | |
546 | EXPECT_EQ(2u, q.GetTokenCount()); | |
547 | EXPECT_EQ(3u, q.GetTokens()[0].length); | |
548 | EXPECT_STREQ("foo", q.GetTokens()[0].name); | |
549 | EXPECT_EQ(1u, q.GetTokens()[1].length); | |
550 | EXPECT_STREQ("0", q.GetTokens()[1].name); | |
551 | EXPECT_EQ(0u, q.GetTokens()[1].index); | |
552 | ||
553 | // std::swap compatibility | |
554 | std::swap(p, q); | |
555 | EXPECT_EQ(&p.GetAllocator(), &q.GetAllocator()); | |
556 | EXPECT_TRUE(q.IsValid()); | |
557 | EXPECT_TRUE(p.IsValid()); | |
558 | EXPECT_EQ(0u, q.GetTokenCount()); | |
559 | EXPECT_EQ(2u, p.GetTokenCount()); | |
560 | EXPECT_EQ(3u, p.GetTokens()[0].length); | |
561 | EXPECT_STREQ("foo", p.GetTokens()[0].name); | |
562 | EXPECT_EQ(1u, p.GetTokens()[1].length); | |
563 | EXPECT_STREQ("0", p.GetTokens()[1].name); | |
564 | EXPECT_EQ(0u, p.GetTokens()[1].index); | |
565 | } | |
566 | ||
31f18b77 FG |
567 | TEST(Pointer, Append) { |
568 | { | |
569 | Pointer p; | |
570 | Pointer q = p.Append("foo"); | |
571 | EXPECT_TRUE(Pointer("/foo") == q); | |
572 | q = q.Append(1234); | |
573 | EXPECT_TRUE(Pointer("/foo/1234") == q); | |
574 | q = q.Append(""); | |
575 | EXPECT_TRUE(Pointer("/foo/1234/") == q); | |
576 | } | |
577 | ||
578 | { | |
579 | Pointer p; | |
580 | Pointer q = p.Append(Value("foo").Move()); | |
581 | EXPECT_TRUE(Pointer("/foo") == q); | |
582 | q = q.Append(Value(1234).Move()); | |
583 | EXPECT_TRUE(Pointer("/foo/1234") == q); | |
584 | q = q.Append(Value(kStringType).Move()); | |
585 | EXPECT_TRUE(Pointer("/foo/1234/") == q); | |
586 | } | |
587 | ||
588 | #if RAPIDJSON_HAS_STDSTRING | |
589 | { | |
590 | Pointer p; | |
591 | Pointer q = p.Append(std::string("foo")); | |
592 | EXPECT_TRUE(Pointer("/foo") == q); | |
593 | } | |
594 | #endif | |
595 | } | |
596 | ||
597 | TEST(Pointer, Equality) { | |
598 | EXPECT_TRUE(Pointer("/foo/0") == Pointer("/foo/0")); | |
599 | EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/1")); | |
600 | EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/0/1")); | |
601 | EXPECT_FALSE(Pointer("/foo/0") == Pointer("a")); | |
602 | EXPECT_FALSE(Pointer("a") == Pointer("a")); // Invalid always not equal | |
603 | } | |
604 | ||
605 | TEST(Pointer, Inequality) { | |
606 | EXPECT_FALSE(Pointer("/foo/0") != Pointer("/foo/0")); | |
607 | EXPECT_TRUE(Pointer("/foo/0") != Pointer("/foo/1")); | |
608 | EXPECT_TRUE(Pointer("/foo/0") != Pointer("/foo/0/1")); | |
609 | EXPECT_TRUE(Pointer("/foo/0") != Pointer("a")); | |
610 | EXPECT_TRUE(Pointer("a") != Pointer("a")); // Invalid always not equal | |
611 | } | |
612 | ||
613 | TEST(Pointer, Create) { | |
614 | Document d; | |
615 | { | |
616 | Value* v = &Pointer("").Create(d, d.GetAllocator()); | |
617 | EXPECT_EQ(&d, v); | |
618 | } | |
619 | { | |
620 | Value* v = &Pointer("/foo").Create(d, d.GetAllocator()); | |
621 | EXPECT_EQ(&d["foo"], v); | |
622 | } | |
623 | { | |
624 | Value* v = &Pointer("/foo/0").Create(d, d.GetAllocator()); | |
625 | EXPECT_EQ(&d["foo"][0], v); | |
626 | } | |
627 | { | |
628 | Value* v = &Pointer("/foo/-").Create(d, d.GetAllocator()); | |
629 | EXPECT_EQ(&d["foo"][1], v); | |
630 | } | |
631 | ||
632 | { | |
633 | Value* v = &Pointer("/foo/-/-").Create(d, d.GetAllocator()); | |
634 | // "foo/-" is a newly created null value x. | |
635 | // "foo/-/-" finds that x is not an array, it converts x to empty object | |
636 | // and treats - as "-" member name | |
637 | EXPECT_EQ(&d["foo"][2]["-"], v); | |
638 | } | |
639 | ||
640 | { | |
641 | // Document with no allocator | |
642 | Value* v = &Pointer("/foo/-").Create(d); | |
643 | EXPECT_EQ(&d["foo"][3], v); | |
644 | } | |
645 | ||
646 | { | |
647 | // Value (not document) must give allocator | |
648 | Value* v = &Pointer("/-").Create(d["foo"], d.GetAllocator()); | |
649 | EXPECT_EQ(&d["foo"][4], v); | |
650 | } | |
651 | } | |
652 | ||
1e59de90 TL |
653 | static const char kJsonIds[] = "{\n" |
654 | " \"id\": \"/root/\"," | |
655 | " \"foo\":[\"bar\", \"baz\", {\"id\": \"inarray\", \"child\": 1}],\n" | |
656 | " \"int\" : 2,\n" | |
657 | " \"str\" : \"val\",\n" | |
658 | " \"obj\": {\"id\": \"inobj\", \"child\": 3},\n" | |
659 | " \"jbo\": {\"id\": true, \"child\": 4}\n" | |
660 | "}"; | |
661 | ||
662 | ||
663 | TEST(Pointer, GetUri) { | |
664 | CrtAllocator allocator; | |
665 | Document d; | |
666 | d.Parse(kJsonIds); | |
667 | Pointer::UriType doc("http://doc"); | |
668 | Pointer::UriType root("http://doc/root/"); | |
669 | Pointer::UriType empty = Pointer::UriType(); | |
670 | ||
671 | EXPECT_TRUE(Pointer("").GetUri(d, doc) == doc); | |
672 | EXPECT_TRUE(Pointer("/foo").GetUri(d, doc) == root); | |
673 | EXPECT_TRUE(Pointer("/foo/0").GetUri(d, doc) == root); | |
674 | EXPECT_TRUE(Pointer("/foo/2").GetUri(d, doc) == root); | |
675 | EXPECT_TRUE(Pointer("/foo/2/child").GetUri(d, doc) == Pointer::UriType("http://doc/root/inarray")); | |
676 | EXPECT_TRUE(Pointer("/int").GetUri(d, doc) == root); | |
677 | EXPECT_TRUE(Pointer("/str").GetUri(d, doc) == root); | |
678 | EXPECT_TRUE(Pointer("/obj").GetUri(d, doc) == root); | |
679 | EXPECT_TRUE(Pointer("/obj/child").GetUri(d, doc) == Pointer::UriType("http://doc/root/inobj")); | |
680 | EXPECT_TRUE(Pointer("/jbo").GetUri(d, doc) == root); | |
681 | EXPECT_TRUE(Pointer("/jbo/child").GetUri(d, doc) == root); // id not string | |
682 | ||
683 | size_t unresolvedTokenIndex; | |
684 | EXPECT_TRUE(Pointer("/abc").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // Out of boundary | |
685 | EXPECT_EQ(0u, unresolvedTokenIndex); | |
686 | EXPECT_TRUE(Pointer("/foo/3").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // Out of boundary | |
687 | EXPECT_EQ(1u, unresolvedTokenIndex); | |
688 | EXPECT_TRUE(Pointer("/foo/a").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // "/foo" is an array, cannot query by "a" | |
689 | EXPECT_EQ(1u, unresolvedTokenIndex); | |
690 | EXPECT_TRUE(Pointer("/foo/0/0").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // "/foo/0" is an string, cannot further query | |
691 | EXPECT_EQ(2u, unresolvedTokenIndex); | |
692 | EXPECT_TRUE(Pointer("/foo/0/a").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // "/foo/0" is an string, cannot further query | |
693 | EXPECT_EQ(2u, unresolvedTokenIndex); | |
694 | ||
695 | Pointer::Token tokens[] = { { "foo ...", 3, kPointerInvalidIndex } }; | |
696 | EXPECT_TRUE(Pointer(tokens, 1).GetUri(d, doc) == root); | |
697 | } | |
698 | ||
31f18b77 FG |
699 | TEST(Pointer, Get) { |
700 | Document d; | |
701 | d.Parse(kJson); | |
702 | ||
703 | EXPECT_EQ(&d, Pointer("").Get(d)); | |
704 | EXPECT_EQ(&d["foo"], Pointer("/foo").Get(d)); | |
705 | EXPECT_EQ(&d["foo"][0], Pointer("/foo/0").Get(d)); | |
706 | EXPECT_EQ(&d[""], Pointer("/").Get(d)); | |
707 | EXPECT_EQ(&d["a/b"], Pointer("/a~1b").Get(d)); | |
708 | EXPECT_EQ(&d["c%d"], Pointer("/c%d").Get(d)); | |
709 | EXPECT_EQ(&d["e^f"], Pointer("/e^f").Get(d)); | |
710 | EXPECT_EQ(&d["g|h"], Pointer("/g|h").Get(d)); | |
711 | EXPECT_EQ(&d["i\\j"], Pointer("/i\\j").Get(d)); | |
712 | EXPECT_EQ(&d["k\"l"], Pointer("/k\"l").Get(d)); | |
713 | EXPECT_EQ(&d[" "], Pointer("/ ").Get(d)); | |
714 | EXPECT_EQ(&d["m~n"], Pointer("/m~0n").Get(d)); | |
1e59de90 TL |
715 | |
716 | EXPECT_TRUE(Pointer("/abc").Get(d) == 0); // Out of boundary | |
31f18b77 FG |
717 | size_t unresolvedTokenIndex; |
718 | EXPECT_TRUE(Pointer("/foo/2").Get(d, &unresolvedTokenIndex) == 0); // Out of boundary | |
1e59de90 | 719 | EXPECT_EQ(1u, unresolvedTokenIndex); |
31f18b77 | 720 | EXPECT_TRUE(Pointer("/foo/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a" |
1e59de90 | 721 | EXPECT_EQ(1u, unresolvedTokenIndex); |
31f18b77 | 722 | EXPECT_TRUE(Pointer("/foo/0/0").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query |
1e59de90 | 723 | EXPECT_EQ(2u, unresolvedTokenIndex); |
31f18b77 | 724 | EXPECT_TRUE(Pointer("/foo/0/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query |
1e59de90 TL |
725 | EXPECT_EQ(2u, unresolvedTokenIndex); |
726 | ||
727 | Pointer::Token tokens[] = { { "foo ...", 3, kPointerInvalidIndex } }; | |
728 | EXPECT_EQ(&d["foo"], Pointer(tokens, 1).Get(d)); | |
31f18b77 FG |
729 | } |
730 | ||
731 | TEST(Pointer, GetWithDefault) { | |
732 | Document d; | |
733 | d.Parse(kJson); | |
734 | ||
735 | // Value version | |
736 | Document::AllocatorType& a = d.GetAllocator(); | |
737 | const Value v("qux"); | |
738 | EXPECT_TRUE(Value("bar") == Pointer("/foo/0").GetWithDefault(d, v, a)); | |
739 | EXPECT_TRUE(Value("baz") == Pointer("/foo/1").GetWithDefault(d, v, a)); | |
740 | EXPECT_TRUE(Value("qux") == Pointer("/foo/2").GetWithDefault(d, v, a)); | |
741 | EXPECT_TRUE(Value("last") == Pointer("/foo/-").GetWithDefault(d, Value("last").Move(), a)); | |
742 | EXPECT_STREQ("last", d["foo"][3].GetString()); | |
743 | ||
744 | EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, Value().Move(), a).IsNull()); | |
745 | EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, "x", a).IsNull()); | |
746 | ||
747 | // Generic version | |
748 | EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -1, a).GetInt()); | |
749 | EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -2, a).GetInt()); | |
750 | EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x87654321, a).GetUint()); | |
751 | EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x12345678, a).GetUint()); | |
752 | ||
753 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
754 | EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64, a).GetInt64()); | |
755 | EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64 + 1, a).GetInt64()); | |
756 | ||
757 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
758 | EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64, a).GetUint64()); | |
759 | EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64 - 1, a).GetUint64()); | |
760 | ||
761 | EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, true, a).IsTrue()); | |
762 | EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, false, a).IsTrue()); | |
763 | ||
764 | EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, false, a).IsFalse()); | |
765 | EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, true, a).IsFalse()); | |
766 | ||
767 | // StringRef version | |
768 | EXPECT_STREQ("Hello", Pointer("/foo/hello").GetWithDefault(d, "Hello", a).GetString()); | |
769 | ||
770 | // Copy string version | |
771 | { | |
772 | char buffer[256]; | |
773 | strcpy(buffer, "World"); | |
774 | EXPECT_STREQ("World", Pointer("/foo/world").GetWithDefault(d, buffer, a).GetString()); | |
775 | memset(buffer, 0, sizeof(buffer)); | |
776 | } | |
777 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
778 | ||
779 | #if RAPIDJSON_HAS_STDSTRING | |
780 | EXPECT_STREQ("C++", Pointer("/foo/C++").GetWithDefault(d, std::string("C++"), a).GetString()); | |
781 | #endif | |
782 | } | |
783 | ||
784 | TEST(Pointer, GetWithDefault_NoAllocator) { | |
785 | Document d; | |
786 | d.Parse(kJson); | |
787 | ||
788 | // Value version | |
789 | const Value v("qux"); | |
790 | EXPECT_TRUE(Value("bar") == Pointer("/foo/0").GetWithDefault(d, v)); | |
791 | EXPECT_TRUE(Value("baz") == Pointer("/foo/1").GetWithDefault(d, v)); | |
792 | EXPECT_TRUE(Value("qux") == Pointer("/foo/2").GetWithDefault(d, v)); | |
793 | EXPECT_TRUE(Value("last") == Pointer("/foo/-").GetWithDefault(d, Value("last").Move())); | |
794 | EXPECT_STREQ("last", d["foo"][3].GetString()); | |
795 | ||
796 | EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, Value().Move()).IsNull()); | |
797 | EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, "x").IsNull()); | |
798 | ||
799 | // Generic version | |
800 | EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -1).GetInt()); | |
801 | EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -2).GetInt()); | |
802 | EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x87654321).GetUint()); | |
803 | EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x12345678).GetUint()); | |
804 | ||
805 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
806 | EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64).GetInt64()); | |
807 | EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64 + 1).GetInt64()); | |
808 | ||
809 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
810 | EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64).GetUint64()); | |
811 | EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64 - 1).GetUint64()); | |
812 | ||
813 | EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, true).IsTrue()); | |
814 | EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, false).IsTrue()); | |
815 | ||
816 | EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, false).IsFalse()); | |
817 | EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, true).IsFalse()); | |
818 | ||
819 | // StringRef version | |
820 | EXPECT_STREQ("Hello", Pointer("/foo/hello").GetWithDefault(d, "Hello").GetString()); | |
821 | ||
822 | // Copy string version | |
823 | { | |
824 | char buffer[256]; | |
825 | strcpy(buffer, "World"); | |
826 | EXPECT_STREQ("World", Pointer("/foo/world").GetWithDefault(d, buffer).GetString()); | |
827 | memset(buffer, 0, sizeof(buffer)); | |
828 | } | |
829 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
830 | ||
831 | #if RAPIDJSON_HAS_STDSTRING | |
832 | EXPECT_STREQ("C++", Pointer("/foo/C++").GetWithDefault(d, std::string("C++")).GetString()); | |
833 | #endif | |
834 | } | |
835 | ||
836 | TEST(Pointer, Set) { | |
837 | Document d; | |
838 | d.Parse(kJson); | |
839 | Document::AllocatorType& a = d.GetAllocator(); | |
840 | ||
841 | // Value version | |
842 | Pointer("/foo/0").Set(d, Value(123).Move(), a); | |
843 | EXPECT_EQ(123, d["foo"][0].GetInt()); | |
844 | ||
845 | Pointer("/foo/-").Set(d, Value(456).Move(), a); | |
846 | EXPECT_EQ(456, d["foo"][2].GetInt()); | |
847 | ||
848 | Pointer("/foo/null").Set(d, Value().Move(), a); | |
849 | EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull()); | |
850 | ||
851 | // Const Value version | |
852 | const Value foo(d["foo"], a); | |
853 | Pointer("/clone").Set(d, foo, a); | |
854 | EXPECT_EQ(foo, *GetValueByPointer(d, "/clone")); | |
855 | ||
856 | // Generic version | |
857 | Pointer("/foo/int").Set(d, -1, a); | |
858 | EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt()); | |
859 | ||
860 | Pointer("/foo/uint").Set(d, 0x87654321, a); | |
861 | EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint()); | |
862 | ||
863 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
864 | Pointer("/foo/int64").Set(d, i64, a); | |
865 | EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64()); | |
866 | ||
867 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
868 | Pointer("/foo/uint64").Set(d, u64, a); | |
869 | EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64()); | |
870 | ||
871 | Pointer("/foo/true").Set(d, true, a); | |
872 | EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue()); | |
873 | ||
874 | Pointer("/foo/false").Set(d, false, a); | |
875 | EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse()); | |
876 | ||
877 | // StringRef version | |
878 | Pointer("/foo/hello").Set(d, "Hello", a); | |
879 | EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString()); | |
880 | ||
881 | // Copy string version | |
882 | { | |
883 | char buffer[256]; | |
884 | strcpy(buffer, "World"); | |
885 | Pointer("/foo/world").Set(d, buffer, a); | |
886 | memset(buffer, 0, sizeof(buffer)); | |
887 | } | |
888 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
889 | ||
890 | #if RAPIDJSON_HAS_STDSTRING | |
891 | Pointer("/foo/c++").Set(d, std::string("C++"), a); | |
892 | EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString()); | |
893 | #endif | |
894 | } | |
895 | ||
896 | TEST(Pointer, Set_NoAllocator) { | |
897 | Document d; | |
898 | d.Parse(kJson); | |
899 | ||
900 | // Value version | |
901 | Pointer("/foo/0").Set(d, Value(123).Move()); | |
902 | EXPECT_EQ(123, d["foo"][0].GetInt()); | |
903 | ||
904 | Pointer("/foo/-").Set(d, Value(456).Move()); | |
905 | EXPECT_EQ(456, d["foo"][2].GetInt()); | |
906 | ||
907 | Pointer("/foo/null").Set(d, Value().Move()); | |
908 | EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull()); | |
909 | ||
910 | // Const Value version | |
911 | const Value foo(d["foo"], d.GetAllocator()); | |
912 | Pointer("/clone").Set(d, foo); | |
913 | EXPECT_EQ(foo, *GetValueByPointer(d, "/clone")); | |
914 | ||
915 | // Generic version | |
916 | Pointer("/foo/int").Set(d, -1); | |
917 | EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt()); | |
918 | ||
919 | Pointer("/foo/uint").Set(d, 0x87654321); | |
920 | EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint()); | |
921 | ||
922 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
923 | Pointer("/foo/int64").Set(d, i64); | |
924 | EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64()); | |
925 | ||
926 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
927 | Pointer("/foo/uint64").Set(d, u64); | |
928 | EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64()); | |
929 | ||
930 | Pointer("/foo/true").Set(d, true); | |
931 | EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue()); | |
932 | ||
933 | Pointer("/foo/false").Set(d, false); | |
934 | EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse()); | |
935 | ||
936 | // StringRef version | |
937 | Pointer("/foo/hello").Set(d, "Hello"); | |
938 | EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString()); | |
939 | ||
940 | // Copy string version | |
941 | { | |
942 | char buffer[256]; | |
943 | strcpy(buffer, "World"); | |
944 | Pointer("/foo/world").Set(d, buffer); | |
945 | memset(buffer, 0, sizeof(buffer)); | |
946 | } | |
947 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
948 | ||
949 | #if RAPIDJSON_HAS_STDSTRING | |
950 | Pointer("/foo/c++").Set(d, std::string("C++")); | |
951 | EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString()); | |
952 | #endif | |
953 | } | |
954 | ||
1e59de90 | 955 | TEST(Pointer, Swap_Value) { |
31f18b77 FG |
956 | Document d; |
957 | d.Parse(kJson); | |
958 | Document::AllocatorType& a = d.GetAllocator(); | |
959 | Pointer("/foo/0").Swap(d, *Pointer("/foo/1").Get(d), a); | |
960 | EXPECT_STREQ("baz", d["foo"][0].GetString()); | |
961 | EXPECT_STREQ("bar", d["foo"][1].GetString()); | |
962 | } | |
963 | ||
1e59de90 | 964 | TEST(Pointer, Swap_Value_NoAllocator) { |
31f18b77 FG |
965 | Document d; |
966 | d.Parse(kJson); | |
967 | Pointer("/foo/0").Swap(d, *Pointer("/foo/1").Get(d)); | |
968 | EXPECT_STREQ("baz", d["foo"][0].GetString()); | |
969 | EXPECT_STREQ("bar", d["foo"][1].GetString()); | |
970 | } | |
971 | ||
972 | TEST(Pointer, Erase) { | |
973 | Document d; | |
974 | d.Parse(kJson); | |
975 | ||
976 | EXPECT_FALSE(Pointer("").Erase(d)); | |
977 | EXPECT_FALSE(Pointer("/nonexist").Erase(d)); | |
978 | EXPECT_FALSE(Pointer("/nonexist/nonexist").Erase(d)); | |
979 | EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d)); | |
980 | EXPECT_FALSE(Pointer("/foo/nonexist/nonexist").Erase(d)); | |
981 | EXPECT_FALSE(Pointer("/foo/0/nonexist").Erase(d)); | |
982 | EXPECT_FALSE(Pointer("/foo/0/nonexist/nonexist").Erase(d)); | |
983 | EXPECT_FALSE(Pointer("/foo/2/nonexist").Erase(d)); | |
984 | EXPECT_TRUE(Pointer("/foo/0").Erase(d)); | |
985 | EXPECT_EQ(1u, d["foo"].Size()); | |
986 | EXPECT_STREQ("baz", d["foo"][0].GetString()); | |
987 | EXPECT_TRUE(Pointer("/foo/0").Erase(d)); | |
988 | EXPECT_TRUE(d["foo"].Empty()); | |
989 | EXPECT_TRUE(Pointer("/foo").Erase(d)); | |
990 | EXPECT_TRUE(Pointer("/foo").Get(d) == 0); | |
991 | ||
992 | Pointer("/a/0/b/0").Create(d); | |
993 | ||
994 | EXPECT_TRUE(Pointer("/a/0/b/0").Get(d) != 0); | |
995 | EXPECT_TRUE(Pointer("/a/0/b/0").Erase(d)); | |
996 | EXPECT_TRUE(Pointer("/a/0/b/0").Get(d) == 0); | |
997 | ||
998 | EXPECT_TRUE(Pointer("/a/0/b").Get(d) != 0); | |
999 | EXPECT_TRUE(Pointer("/a/0/b").Erase(d)); | |
1000 | EXPECT_TRUE(Pointer("/a/0/b").Get(d) == 0); | |
1001 | ||
1002 | EXPECT_TRUE(Pointer("/a/0").Get(d) != 0); | |
1003 | EXPECT_TRUE(Pointer("/a/0").Erase(d)); | |
1004 | EXPECT_TRUE(Pointer("/a/0").Get(d) == 0); | |
1005 | ||
1006 | EXPECT_TRUE(Pointer("/a").Get(d) != 0); | |
1007 | EXPECT_TRUE(Pointer("/a").Erase(d)); | |
1008 | EXPECT_TRUE(Pointer("/a").Get(d) == 0); | |
1009 | } | |
1010 | ||
1011 | TEST(Pointer, CreateValueByPointer) { | |
1012 | Document d; | |
1013 | Document::AllocatorType& a = d.GetAllocator(); | |
1014 | ||
1015 | { | |
1016 | Value& v = CreateValueByPointer(d, Pointer("/foo/0"), a); | |
1017 | EXPECT_EQ(&d["foo"][0], &v); | |
1018 | } | |
1019 | { | |
1020 | Value& v = CreateValueByPointer(d, "/foo/1", a); | |
1021 | EXPECT_EQ(&d["foo"][1], &v); | |
1022 | } | |
1023 | } | |
1024 | ||
1025 | TEST(Pointer, CreateValueByPointer_NoAllocator) { | |
1026 | Document d; | |
1027 | ||
1028 | { | |
1029 | Value& v = CreateValueByPointer(d, Pointer("/foo/0")); | |
1030 | EXPECT_EQ(&d["foo"][0], &v); | |
1031 | } | |
1032 | { | |
1033 | Value& v = CreateValueByPointer(d, "/foo/1"); | |
1034 | EXPECT_EQ(&d["foo"][1], &v); | |
1035 | } | |
1036 | } | |
1037 | ||
1038 | TEST(Pointer, GetValueByPointer) { | |
1039 | Document d; | |
1040 | d.Parse(kJson); | |
1041 | ||
1042 | EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, Pointer("/foo/0"))); | |
1043 | EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, "/foo/0")); | |
1044 | ||
1045 | size_t unresolvedTokenIndex; | |
1046 | EXPECT_TRUE(GetValueByPointer(d, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary | |
1e59de90 | 1047 | EXPECT_EQ(1u, unresolvedTokenIndex); |
31f18b77 | 1048 | EXPECT_TRUE(GetValueByPointer(d, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a" |
1e59de90 | 1049 | EXPECT_EQ(1u, unresolvedTokenIndex); |
31f18b77 | 1050 | EXPECT_TRUE(GetValueByPointer(d, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query |
1e59de90 | 1051 | EXPECT_EQ(2u, unresolvedTokenIndex); |
31f18b77 | 1052 | EXPECT_TRUE(GetValueByPointer(d, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query |
1e59de90 | 1053 | EXPECT_EQ(2u, unresolvedTokenIndex); |
31f18b77 FG |
1054 | |
1055 | // const version | |
1056 | const Value& v = d; | |
1057 | EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, Pointer("/foo/0"))); | |
1058 | EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, "/foo/0")); | |
1059 | ||
1060 | EXPECT_TRUE(GetValueByPointer(v, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary | |
1e59de90 | 1061 | EXPECT_EQ(1u, unresolvedTokenIndex); |
31f18b77 | 1062 | EXPECT_TRUE(GetValueByPointer(v, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a" |
1e59de90 | 1063 | EXPECT_EQ(1u, unresolvedTokenIndex); |
31f18b77 | 1064 | EXPECT_TRUE(GetValueByPointer(v, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query |
1e59de90 | 1065 | EXPECT_EQ(2u, unresolvedTokenIndex); |
31f18b77 | 1066 | EXPECT_TRUE(GetValueByPointer(v, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query |
1e59de90 | 1067 | EXPECT_EQ(2u, unresolvedTokenIndex); |
31f18b77 FG |
1068 | |
1069 | } | |
1070 | ||
1071 | TEST(Pointer, GetValueByPointerWithDefault_Pointer) { | |
1072 | Document d; | |
1073 | d.Parse(kJson); | |
1074 | ||
1075 | Document::AllocatorType& a = d.GetAllocator(); | |
1076 | const Value v("qux"); | |
1077 | EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v, a)); | |
1078 | EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v, a)); | |
1079 | EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, Pointer("/foo/1"), v, a)); | |
1080 | EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, Pointer("/foo/2"), v, a)); | |
1081 | EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, Pointer("/foo/-"), Value("last").Move(), a)); | |
1082 | EXPECT_STREQ("last", d["foo"][3].GetString()); | |
1083 | ||
1084 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), Value().Move(), a).IsNull()); | |
1085 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), "x", a).IsNull()); | |
1086 | ||
1087 | // Generic version | |
1088 | EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -1, a).GetInt()); | |
1089 | EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -2, a).GetInt()); | |
1090 | EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x87654321, a).GetUint()); | |
1091 | EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x12345678, a).GetUint()); | |
1092 | ||
1093 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
1094 | EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64, a).GetInt64()); | |
1095 | EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64 + 1, a).GetInt64()); | |
1096 | ||
1097 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
1098 | EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64, a).GetUint64()); | |
1099 | EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64 - 1, a).GetUint64()); | |
1100 | ||
1101 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), true, a).IsTrue()); | |
1102 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), false, a).IsTrue()); | |
1103 | ||
1104 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), false, a).IsFalse()); | |
1105 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), true, a).IsFalse()); | |
1106 | ||
1107 | // StringRef version | |
1108 | EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, Pointer("/foo/hello"), "Hello", a).GetString()); | |
1109 | ||
1110 | // Copy string version | |
1111 | { | |
1112 | char buffer[256]; | |
1113 | strcpy(buffer, "World"); | |
1114 | EXPECT_STREQ("World", GetValueByPointerWithDefault(d, Pointer("/foo/world"), buffer, a).GetString()); | |
1115 | memset(buffer, 0, sizeof(buffer)); | |
1116 | } | |
1117 | EXPECT_STREQ("World", GetValueByPointer(d, Pointer("/foo/world"))->GetString()); | |
1118 | ||
1119 | #if RAPIDJSON_HAS_STDSTRING | |
1120 | EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, Pointer("/foo/C++"), std::string("C++"), a).GetString()); | |
1121 | #endif | |
1122 | } | |
1123 | ||
1124 | TEST(Pointer, GetValueByPointerWithDefault_String) { | |
1125 | Document d; | |
1126 | d.Parse(kJson); | |
1127 | ||
1128 | Document::AllocatorType& a = d.GetAllocator(); | |
1129 | const Value v("qux"); | |
1130 | EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v, a)); | |
1131 | EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v, a)); | |
1132 | EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, "/foo/1", v, a)); | |
1133 | EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, "/foo/2", v, a)); | |
1134 | EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, "/foo/-", Value("last").Move(), a)); | |
1135 | EXPECT_STREQ("last", d["foo"][3].GetString()); | |
1136 | ||
1137 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", Value().Move(), a).IsNull()); | |
1138 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", "x", a).IsNull()); | |
1139 | ||
1140 | // Generic version | |
1141 | EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -1, a).GetInt()); | |
1142 | EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -2, a).GetInt()); | |
1143 | EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x87654321, a).GetUint()); | |
1144 | EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x12345678, a).GetUint()); | |
1145 | ||
1146 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
1147 | EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64, a).GetInt64()); | |
1148 | EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64 + 1, a).GetInt64()); | |
1149 | ||
1150 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
1151 | EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64, a).GetUint64()); | |
1152 | EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64 - 1, a).GetUint64()); | |
1153 | ||
1154 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", true, a).IsTrue()); | |
1155 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", false, a).IsTrue()); | |
1156 | ||
1157 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", false, a).IsFalse()); | |
1158 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", true, a).IsFalse()); | |
1159 | ||
1160 | // StringRef version | |
1161 | EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, "/foo/hello", "Hello", a).GetString()); | |
1162 | ||
1163 | // Copy string version | |
1164 | { | |
1165 | char buffer[256]; | |
1166 | strcpy(buffer, "World"); | |
1167 | EXPECT_STREQ("World", GetValueByPointerWithDefault(d, "/foo/world", buffer, a).GetString()); | |
1168 | memset(buffer, 0, sizeof(buffer)); | |
1169 | } | |
1170 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
1171 | ||
1172 | #if RAPIDJSON_HAS_STDSTRING | |
1173 | EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, "/foo/C++", std::string("C++"), a).GetString()); | |
1174 | #endif | |
1175 | } | |
1176 | ||
1177 | TEST(Pointer, GetValueByPointerWithDefault_Pointer_NoAllocator) { | |
1178 | Document d; | |
1179 | d.Parse(kJson); | |
1180 | ||
1181 | const Value v("qux"); | |
1182 | EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v)); | |
1183 | EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v)); | |
1184 | EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, Pointer("/foo/1"), v)); | |
1185 | EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, Pointer("/foo/2"), v)); | |
1186 | EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, Pointer("/foo/-"), Value("last").Move())); | |
1187 | EXPECT_STREQ("last", d["foo"][3].GetString()); | |
1188 | ||
1189 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), Value().Move()).IsNull()); | |
1190 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), "x").IsNull()); | |
1191 | ||
1192 | // Generic version | |
1193 | EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -1).GetInt()); | |
1194 | EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -2).GetInt()); | |
1195 | EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x87654321).GetUint()); | |
1196 | EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x12345678).GetUint()); | |
1197 | ||
1198 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
1199 | EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64).GetInt64()); | |
1200 | EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64 + 1).GetInt64()); | |
1201 | ||
1202 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
1203 | EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64).GetUint64()); | |
1204 | EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64 - 1).GetUint64()); | |
1205 | ||
1206 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), true).IsTrue()); | |
1207 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), false).IsTrue()); | |
1208 | ||
1209 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), false).IsFalse()); | |
1210 | EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), true).IsFalse()); | |
1211 | ||
1212 | // StringRef version | |
1213 | EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, Pointer("/foo/hello"), "Hello").GetString()); | |
1214 | ||
1215 | // Copy string version | |
1216 | { | |
1217 | char buffer[256]; | |
1218 | strcpy(buffer, "World"); | |
1219 | EXPECT_STREQ("World", GetValueByPointerWithDefault(d, Pointer("/foo/world"), buffer).GetString()); | |
1220 | memset(buffer, 0, sizeof(buffer)); | |
1221 | } | |
1222 | EXPECT_STREQ("World", GetValueByPointer(d, Pointer("/foo/world"))->GetString()); | |
1223 | ||
1224 | #if RAPIDJSON_HAS_STDSTRING | |
1225 | EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, Pointer("/foo/C++"), std::string("C++")).GetString()); | |
1226 | #endif | |
1227 | } | |
1228 | ||
1229 | TEST(Pointer, GetValueByPointerWithDefault_String_NoAllocator) { | |
1230 | Document d; | |
1231 | d.Parse(kJson); | |
1232 | ||
1233 | const Value v("qux"); | |
1234 | EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v)); | |
1235 | EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v)); | |
1236 | EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, "/foo/1", v)); | |
1237 | EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, "/foo/2", v)); | |
1238 | EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, "/foo/-", Value("last").Move())); | |
1239 | EXPECT_STREQ("last", d["foo"][3].GetString()); | |
1240 | ||
1241 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", Value().Move()).IsNull()); | |
1242 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", "x").IsNull()); | |
1243 | ||
1244 | // Generic version | |
1245 | EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -1).GetInt()); | |
1246 | EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -2).GetInt()); | |
1247 | EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x87654321).GetUint()); | |
1248 | EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x12345678).GetUint()); | |
1249 | ||
1250 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
1251 | EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64).GetInt64()); | |
1252 | EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64 + 1).GetInt64()); | |
1253 | ||
1254 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
1255 | EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64).GetUint64()); | |
1256 | EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64 - 1).GetUint64()); | |
1257 | ||
1258 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", true).IsTrue()); | |
1259 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", false).IsTrue()); | |
1260 | ||
1261 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", false).IsFalse()); | |
1262 | EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", true).IsFalse()); | |
1263 | ||
1264 | // StringRef version | |
1265 | EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, "/foo/hello", "Hello").GetString()); | |
1266 | ||
1267 | // Copy string version | |
1268 | { | |
1269 | char buffer[256]; | |
1270 | strcpy(buffer, "World"); | |
1271 | EXPECT_STREQ("World", GetValueByPointerWithDefault(d, "/foo/world", buffer).GetString()); | |
1272 | memset(buffer, 0, sizeof(buffer)); | |
1273 | } | |
1274 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
1275 | ||
1276 | #if RAPIDJSON_HAS_STDSTRING | |
1277 | EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, Pointer("/foo/C++"), std::string("C++")).GetString()); | |
1278 | #endif | |
1279 | } | |
1280 | ||
1281 | TEST(Pointer, SetValueByPointer_Pointer) { | |
1282 | Document d; | |
1283 | d.Parse(kJson); | |
1284 | Document::AllocatorType& a = d.GetAllocator(); | |
1285 | ||
1286 | // Value version | |
1287 | SetValueByPointer(d, Pointer("/foo/0"), Value(123).Move(), a); | |
1288 | EXPECT_EQ(123, d["foo"][0].GetInt()); | |
1289 | ||
1290 | SetValueByPointer(d, Pointer("/foo/null"), Value().Move(), a); | |
1291 | EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull()); | |
1292 | ||
1293 | // Const Value version | |
1294 | const Value foo(d["foo"], d.GetAllocator()); | |
1295 | SetValueByPointer(d, Pointer("/clone"), foo, a); | |
1296 | EXPECT_EQ(foo, *GetValueByPointer(d, "/clone")); | |
1297 | ||
1298 | // Generic version | |
1299 | SetValueByPointer(d, Pointer("/foo/int"), -1, a); | |
1300 | EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt()); | |
1301 | ||
1302 | SetValueByPointer(d, Pointer("/foo/uint"), 0x87654321, a); | |
1303 | EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint()); | |
1304 | ||
1305 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
1306 | SetValueByPointer(d, Pointer("/foo/int64"), i64, a); | |
1307 | EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64()); | |
1308 | ||
1309 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
1310 | SetValueByPointer(d, Pointer("/foo/uint64"), u64, a); | |
1311 | EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64()); | |
1312 | ||
1313 | SetValueByPointer(d, Pointer("/foo/true"), true, a); | |
1314 | EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue()); | |
1315 | ||
1316 | SetValueByPointer(d, Pointer("/foo/false"), false, a); | |
1317 | EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse()); | |
1318 | ||
1319 | // StringRef version | |
1320 | SetValueByPointer(d, Pointer("/foo/hello"), "Hello", a); | |
1321 | EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString()); | |
1322 | ||
1323 | // Copy string version | |
1324 | { | |
1325 | char buffer[256]; | |
1326 | strcpy(buffer, "World"); | |
1327 | SetValueByPointer(d, Pointer("/foo/world"), buffer, a); | |
1328 | memset(buffer, 0, sizeof(buffer)); | |
1329 | } | |
1330 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
1331 | ||
1332 | #if RAPIDJSON_HAS_STDSTRING | |
1333 | SetValueByPointer(d, Pointer("/foo/c++"), std::string("C++"), a); | |
1334 | EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString()); | |
1335 | #endif | |
1336 | } | |
1337 | ||
1338 | TEST(Pointer, SetValueByPointer_String) { | |
1339 | Document d; | |
1340 | d.Parse(kJson); | |
1341 | Document::AllocatorType& a = d.GetAllocator(); | |
1342 | ||
1343 | // Value version | |
1344 | SetValueByPointer(d, "/foo/0", Value(123).Move(), a); | |
1345 | EXPECT_EQ(123, d["foo"][0].GetInt()); | |
1346 | ||
1347 | SetValueByPointer(d, "/foo/null", Value().Move(), a); | |
1348 | EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull()); | |
1349 | ||
1350 | // Const Value version | |
1351 | const Value foo(d["foo"], d.GetAllocator()); | |
1352 | SetValueByPointer(d, "/clone", foo, a); | |
1353 | EXPECT_EQ(foo, *GetValueByPointer(d, "/clone")); | |
1354 | ||
1355 | // Generic version | |
1356 | SetValueByPointer(d, "/foo/int", -1, a); | |
1357 | EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt()); | |
1358 | ||
1359 | SetValueByPointer(d, "/foo/uint", 0x87654321, a); | |
1360 | EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint()); | |
1361 | ||
1362 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
1363 | SetValueByPointer(d, "/foo/int64", i64, a); | |
1364 | EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64()); | |
1365 | ||
1366 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
1367 | SetValueByPointer(d, "/foo/uint64", u64, a); | |
1368 | EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64()); | |
1369 | ||
1370 | SetValueByPointer(d, "/foo/true", true, a); | |
1371 | EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue()); | |
1372 | ||
1373 | SetValueByPointer(d, "/foo/false", false, a); | |
1374 | EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse()); | |
1375 | ||
1376 | // StringRef version | |
1377 | SetValueByPointer(d, "/foo/hello", "Hello", a); | |
1378 | EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString()); | |
1379 | ||
1380 | // Copy string version | |
1381 | { | |
1382 | char buffer[256]; | |
1383 | strcpy(buffer, "World"); | |
1384 | SetValueByPointer(d, "/foo/world", buffer, a); | |
1385 | memset(buffer, 0, sizeof(buffer)); | |
1386 | } | |
1387 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
1388 | ||
1389 | #if RAPIDJSON_HAS_STDSTRING | |
1390 | SetValueByPointer(d, "/foo/c++", std::string("C++"), a); | |
1391 | EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString()); | |
1392 | #endif | |
1393 | } | |
1394 | ||
1395 | TEST(Pointer, SetValueByPointer_Pointer_NoAllocator) { | |
1396 | Document d; | |
1397 | d.Parse(kJson); | |
1398 | ||
1399 | // Value version | |
1400 | SetValueByPointer(d, Pointer("/foo/0"), Value(123).Move()); | |
1401 | EXPECT_EQ(123, d["foo"][0].GetInt()); | |
1402 | ||
1403 | SetValueByPointer(d, Pointer("/foo/null"), Value().Move()); | |
1404 | EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull()); | |
1405 | ||
1406 | // Const Value version | |
1407 | const Value foo(d["foo"], d.GetAllocator()); | |
1408 | SetValueByPointer(d, Pointer("/clone"), foo); | |
1409 | EXPECT_EQ(foo, *GetValueByPointer(d, "/clone")); | |
1410 | ||
1411 | // Generic version | |
1412 | SetValueByPointer(d, Pointer("/foo/int"), -1); | |
1413 | EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt()); | |
1414 | ||
1415 | SetValueByPointer(d, Pointer("/foo/uint"), 0x87654321); | |
1416 | EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint()); | |
1417 | ||
1418 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
1419 | SetValueByPointer(d, Pointer("/foo/int64"), i64); | |
1420 | EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64()); | |
1421 | ||
1422 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
1423 | SetValueByPointer(d, Pointer("/foo/uint64"), u64); | |
1424 | EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64()); | |
1425 | ||
1426 | SetValueByPointer(d, Pointer("/foo/true"), true); | |
1427 | EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue()); | |
1428 | ||
1429 | SetValueByPointer(d, Pointer("/foo/false"), false); | |
1430 | EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse()); | |
1431 | ||
1432 | // StringRef version | |
1433 | SetValueByPointer(d, Pointer("/foo/hello"), "Hello"); | |
1434 | EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString()); | |
1435 | ||
1436 | // Copy string version | |
1437 | { | |
1438 | char buffer[256]; | |
1439 | strcpy(buffer, "World"); | |
1440 | SetValueByPointer(d, Pointer("/foo/world"), buffer); | |
1441 | memset(buffer, 0, sizeof(buffer)); | |
1442 | } | |
1443 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
1444 | ||
1445 | #if RAPIDJSON_HAS_STDSTRING | |
1446 | SetValueByPointer(d, Pointer("/foo/c++"), std::string("C++")); | |
1447 | EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString()); | |
1448 | #endif | |
1449 | } | |
1450 | ||
1451 | TEST(Pointer, SetValueByPointer_String_NoAllocator) { | |
1452 | Document d; | |
1453 | d.Parse(kJson); | |
1454 | ||
1455 | // Value version | |
1456 | SetValueByPointer(d, "/foo/0", Value(123).Move()); | |
1457 | EXPECT_EQ(123, d["foo"][0].GetInt()); | |
1458 | ||
1459 | SetValueByPointer(d, "/foo/null", Value().Move()); | |
1460 | EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull()); | |
1461 | ||
1462 | // Const Value version | |
1463 | const Value foo(d["foo"], d.GetAllocator()); | |
1464 | SetValueByPointer(d, "/clone", foo); | |
1465 | EXPECT_EQ(foo, *GetValueByPointer(d, "/clone")); | |
1466 | ||
1467 | // Generic version | |
1468 | SetValueByPointer(d, "/foo/int", -1); | |
1469 | EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt()); | |
1470 | ||
1471 | SetValueByPointer(d, "/foo/uint", 0x87654321); | |
1472 | EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint()); | |
1473 | ||
1474 | const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0)); | |
1475 | SetValueByPointer(d, "/foo/int64", i64); | |
1476 | EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64()); | |
1477 | ||
1478 | const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF); | |
1479 | SetValueByPointer(d, "/foo/uint64", u64); | |
1480 | EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64()); | |
1481 | ||
1482 | SetValueByPointer(d, "/foo/true", true); | |
1483 | EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue()); | |
1484 | ||
1485 | SetValueByPointer(d, "/foo/false", false); | |
1486 | EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse()); | |
1487 | ||
1488 | // StringRef version | |
1489 | SetValueByPointer(d, "/foo/hello", "Hello"); | |
1490 | EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString()); | |
1491 | ||
1492 | // Copy string version | |
1493 | { | |
1494 | char buffer[256]; | |
1495 | strcpy(buffer, "World"); | |
1496 | SetValueByPointer(d, "/foo/world", buffer); | |
1497 | memset(buffer, 0, sizeof(buffer)); | |
1498 | } | |
1499 | EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString()); | |
1500 | ||
1501 | #if RAPIDJSON_HAS_STDSTRING | |
1502 | SetValueByPointer(d, "/foo/c++", std::string("C++")); | |
1503 | EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString()); | |
1504 | #endif | |
1505 | } | |
1506 | ||
1507 | TEST(Pointer, SwapValueByPointer) { | |
1508 | Document d; | |
1509 | d.Parse(kJson); | |
1510 | Document::AllocatorType& a = d.GetAllocator(); | |
1511 | SwapValueByPointer(d, Pointer("/foo/0"), *GetValueByPointer(d, "/foo/1"), a); | |
1512 | EXPECT_STREQ("baz", d["foo"][0].GetString()); | |
1513 | EXPECT_STREQ("bar", d["foo"][1].GetString()); | |
1514 | ||
1515 | SwapValueByPointer(d, "/foo/0", *GetValueByPointer(d, "/foo/1"), a); | |
1516 | EXPECT_STREQ("bar", d["foo"][0].GetString()); | |
1517 | EXPECT_STREQ("baz", d["foo"][1].GetString()); | |
1518 | } | |
1519 | ||
1520 | TEST(Pointer, SwapValueByPointer_NoAllocator) { | |
1521 | Document d; | |
1522 | d.Parse(kJson); | |
1523 | SwapValueByPointer(d, Pointer("/foo/0"), *GetValueByPointer(d, "/foo/1")); | |
1524 | EXPECT_STREQ("baz", d["foo"][0].GetString()); | |
1525 | EXPECT_STREQ("bar", d["foo"][1].GetString()); | |
1526 | ||
1527 | SwapValueByPointer(d, "/foo/0", *GetValueByPointer(d, "/foo/1")); | |
1528 | EXPECT_STREQ("bar", d["foo"][0].GetString()); | |
1529 | EXPECT_STREQ("baz", d["foo"][1].GetString()); | |
1530 | } | |
1531 | ||
1532 | TEST(Pointer, EraseValueByPointer_Pointer) { | |
1533 | Document d; | |
1534 | d.Parse(kJson); | |
1535 | ||
1536 | EXPECT_FALSE(EraseValueByPointer(d, Pointer(""))); | |
1537 | EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d)); | |
1538 | EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0"))); | |
1539 | EXPECT_EQ(1u, d["foo"].Size()); | |
1540 | EXPECT_STREQ("baz", d["foo"][0].GetString()); | |
1541 | EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0"))); | |
1542 | EXPECT_TRUE(d["foo"].Empty()); | |
1543 | EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo"))); | |
1544 | EXPECT_TRUE(Pointer("/foo").Get(d) == 0); | |
1545 | } | |
1546 | ||
1547 | TEST(Pointer, EraseValueByPointer_String) { | |
1548 | Document d; | |
1549 | d.Parse(kJson); | |
1550 | ||
1551 | EXPECT_FALSE(EraseValueByPointer(d, "")); | |
1552 | EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d)); | |
1553 | EXPECT_TRUE(EraseValueByPointer(d, "/foo/0")); | |
1554 | EXPECT_EQ(1u, d["foo"].Size()); | |
1555 | EXPECT_STREQ("baz", d["foo"][0].GetString()); | |
1556 | EXPECT_TRUE(EraseValueByPointer(d, "/foo/0")); | |
1557 | EXPECT_TRUE(d["foo"].Empty()); | |
1558 | EXPECT_TRUE(EraseValueByPointer(d, "/foo")); | |
1559 | EXPECT_TRUE(Pointer("/foo").Get(d) == 0); | |
1560 | } | |
1561 | ||
1562 | TEST(Pointer, Ambiguity) { | |
1563 | { | |
1564 | Document d; | |
1565 | d.Parse("{\"0\" : [123]}"); | |
1566 | EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt()); | |
1567 | Pointer("/0/a").Set(d, 456); // Change array [123] to object {456} | |
1568 | EXPECT_EQ(456, Pointer("/0/a").Get(d)->GetInt()); | |
1569 | } | |
1570 | ||
1571 | { | |
1572 | Document d; | |
1573 | EXPECT_FALSE(d.Parse("[{\"0\": 123}]").HasParseError()); | |
1574 | EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt()); | |
1575 | Pointer("/0/1").Set(d, 456); // 1 is treated as "1" to index object | |
1576 | EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt()); | |
1577 | EXPECT_EQ(456, Pointer("/0/1").Get(d)->GetInt()); | |
1578 | } | |
1579 | } | |
1580 | ||
1e59de90 TL |
1581 | TEST(Pointer, ResolveOnObject) { |
1582 | Document d; | |
1583 | EXPECT_FALSE(d.Parse("{\"a\": 123}").HasParseError()); | |
1584 | ||
1585 | { | |
1586 | Value::ConstObject o = static_cast<const Document&>(d).GetObject(); | |
1587 | EXPECT_EQ(123, Pointer("/a").Get(o)->GetInt()); | |
1588 | } | |
1589 | ||
1590 | { | |
1591 | Value::Object o = d.GetObject(); | |
1592 | Pointer("/a").Set(o, 456, d.GetAllocator()); | |
1593 | EXPECT_EQ(456, Pointer("/a").Get(o)->GetInt()); | |
1594 | } | |
1595 | } | |
1596 | ||
1597 | TEST(Pointer, ResolveOnArray) { | |
1598 | Document d; | |
1599 | EXPECT_FALSE(d.Parse("[1, 2, 3]").HasParseError()); | |
1600 | ||
1601 | { | |
1602 | Value::ConstArray a = static_cast<const Document&>(d).GetArray(); | |
1603 | EXPECT_EQ(2, Pointer("/1").Get(a)->GetInt()); | |
1604 | } | |
1605 | ||
1606 | { | |
1607 | Value::Array a = d.GetArray(); | |
1608 | Pointer("/1").Set(a, 123, d.GetAllocator()); | |
1609 | EXPECT_EQ(123, Pointer("/1").Get(a)->GetInt()); | |
1610 | } | |
1611 | } | |
1612 | ||
1613 | TEST(Pointer, LessThan) { | |
1614 | static const struct { | |
1615 | const char *str; | |
1616 | bool valid; | |
1617 | } pointers[] = { | |
1618 | { "/a/b", true }, | |
1619 | { "/a", true }, | |
1620 | { "/d/1", true }, | |
1621 | { "/d/2/z", true }, | |
1622 | { "/d/2/3", true }, | |
1623 | { "/d/2", true }, | |
1624 | { "/a/c", true }, | |
1625 | { "/e/f~g", false }, | |
1626 | { "/d/2/zz", true }, | |
1627 | { "/d/1", true }, | |
1628 | { "/d/2/z", true }, | |
1629 | { "/e/f~~g", false }, | |
1630 | { "/e/f~0g", true }, | |
1631 | { "/e/f~1g", true }, | |
1632 | { "/e/f.g", true }, | |
1633 | { "", true } | |
1634 | }; | |
1635 | static const char *ordered_pointers[] = { | |
1636 | "", | |
1637 | "/a", | |
1638 | "/a/b", | |
1639 | "/a/c", | |
1640 | "/d/1", | |
1641 | "/d/1", | |
1642 | "/d/2", | |
1643 | "/e/f.g", | |
1644 | "/e/f~1g", | |
1645 | "/e/f~0g", | |
1646 | "/d/2/3", | |
1647 | "/d/2/z", | |
1648 | "/d/2/z", | |
1649 | "/d/2/zz", | |
1650 | NULL, // was invalid "/e/f~g" | |
1651 | NULL // was invalid "/e/f~~g" | |
1652 | }; | |
1653 | typedef MemoryPoolAllocator<> AllocatorType; | |
1654 | typedef GenericPointer<Value, AllocatorType> PointerType; | |
1655 | typedef std::multimap<PointerType, size_t> PointerMap; | |
1656 | PointerMap map; | |
1657 | PointerMap::iterator it; | |
1658 | AllocatorType allocator; | |
1659 | size_t i; | |
1660 | ||
1661 | EXPECT_EQ(sizeof(pointers) / sizeof(pointers[0]), | |
1662 | sizeof(ordered_pointers) / sizeof(ordered_pointers[0])); | |
1663 | ||
1664 | for (i = 0; i < sizeof(pointers) / sizeof(pointers[0]); ++i) { | |
1665 | it = map.insert(PointerMap::value_type(PointerType(pointers[i].str, &allocator), i)); | |
1666 | if (!it->first.IsValid()) { | |
1667 | EXPECT_EQ(++it, map.end()); | |
1668 | } | |
1669 | } | |
1670 | ||
1671 | for (i = 0, it = map.begin(); it != map.end(); ++it, ++i) { | |
1672 | EXPECT_TRUE(it->second < sizeof(pointers) / sizeof(pointers[0])); | |
1673 | EXPECT_EQ(it->first.IsValid(), pointers[it->second].valid); | |
1674 | EXPECT_TRUE(i < sizeof(ordered_pointers) / sizeof(ordered_pointers[0])); | |
1675 | EXPECT_EQ(it->first.IsValid(), !!ordered_pointers[i]); | |
1676 | if (it->first.IsValid()) { | |
1677 | std::stringstream ss; | |
1678 | OStreamWrapper os(ss); | |
1679 | EXPECT_TRUE(it->first.Stringify(os)); | |
1680 | EXPECT_EQ(ss.str(), pointers[it->second].str); | |
1681 | EXPECT_EQ(ss.str(), ordered_pointers[i]); | |
1682 | } | |
1683 | } | |
1684 | } | |
1685 | ||
1686 | // https://github.com/Tencent/rapidjson/issues/483 | |
31f18b77 FG |
1687 | namespace myjson { |
1688 | ||
1689 | class MyAllocator | |
1690 | { | |
1691 | public: | |
1692 | static const bool kNeedFree = true; | |
1693 | void * Malloc(size_t _size) { return malloc(_size); } | |
1694 | void * Realloc(void *_org_p, size_t _org_size, size_t _new_size) { (void)_org_size; return realloc(_org_p, _new_size); } | |
1695 | static void Free(void *_p) { return free(_p); } | |
1696 | }; | |
1697 | ||
1698 | typedef rapidjson::GenericDocument< | |
1699 | rapidjson::UTF8<>, | |
1700 | rapidjson::MemoryPoolAllocator< MyAllocator >, | |
1701 | MyAllocator | |
1702 | > Document; | |
1703 | ||
1704 | typedef rapidjson::GenericPointer< | |
1705 | ::myjson::Document::ValueType, | |
1706 | MyAllocator | |
1707 | > Pointer; | |
1708 | ||
1709 | typedef ::myjson::Document::ValueType Value; | |
1710 | ||
1711 | } | |
1712 | ||
1713 | TEST(Pointer, Issue483) { | |
1714 | std::string mystr, path; | |
1715 | myjson::Document document; | |
1716 | myjson::Value value(rapidjson::kStringType); | |
1717 | value.SetString(mystr.c_str(), static_cast<SizeType>(mystr.length()), document.GetAllocator()); | |
1718 | myjson::Pointer(path.c_str()).Set(document, value, document.GetAllocator()); | |
1719 | } | |
1e59de90 TL |
1720 | |
1721 | TEST(Pointer, Issue1899) { | |
1722 | typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType; | |
1723 | PointerType p; | |
1724 | PointerType q = p.Append("foo"); | |
1725 | EXPECT_TRUE(PointerType("/foo") == q); | |
1726 | q = q.Append(1234); | |
1727 | EXPECT_TRUE(PointerType("/foo/1234") == q); | |
1728 | q = q.Append(""); | |
1729 | EXPECT_TRUE(PointerType("/foo/1234/") == q); | |
1730 | } |