rippled
Loading...
Searching...
No Matches
STParsedJSON_test.cpp
1#include <test/jtx.h>
2
3#include <xrpl/beast/unit_test.h>
4#include <xrpl/json/json_reader.h>
5#include <xrpl/protocol/STNumber.h>
6#include <xrpl/protocol/STParsedJSON.h>
7#include <xrpl/protocol/STXChainBridge.h>
8#include <xrpl/protocol/st.h>
9
10namespace xrpl {
11
13{
14 bool
16 {
17 Json::Reader reader;
18 return reader.parse(json, to) && to.isObject();
19 }
20
21 void
23 {
24 testcase("UInt8");
25 {
27 j[sfCloseResolution] = 255;
28 STParsedJSONObject obj("Test", j);
29 BEAST_EXPECT(obj.object.has_value());
30 BEAST_EXPECT(obj.object->isFieldPresent(sfCloseResolution));
31 BEAST_EXPECT(obj.object->getFieldU8(sfCloseResolution) == 255);
32 }
33
34 // test with uint value
35 {
37 j[sfCloseResolution] = 255u;
38 STParsedJSONObject obj("Test", j);
39 BEAST_EXPECT(obj.object.has_value());
40 BEAST_EXPECT(obj.object->isFieldPresent(sfCloseResolution));
41 BEAST_EXPECT(obj.object->getFieldU8(sfCloseResolution) == 255);
42 }
43
44 // Test with string value
45 {
47 j[sfCloseResolution] = "255";
48 STParsedJSONObject obj("Test", j);
49 BEAST_EXPECT(obj.object.has_value());
50 BEAST_EXPECT(obj.object->isFieldPresent(sfCloseResolution));
51 BEAST_EXPECT(obj.object->getFieldU8(sfCloseResolution) == 255);
52 }
53
54 // Test min value for uint8
55 {
57 j[sfCloseResolution] = 0;
58 STParsedJSONObject obj("Test", j);
59 BEAST_EXPECT(obj.object.has_value());
60 BEAST_EXPECT(obj.object->getFieldU8(sfCloseResolution) == 0);
61 }
62
63 // Test out of range value for UInt8 (negative)
64 {
66 j[sfCloseResolution] = -1;
67 STParsedJSONObject obj("Test", j);
68 BEAST_EXPECT(!obj.object.has_value());
69 }
70
71 // Test out of range value for UInt8 (too large)
72 {
74 j[sfCloseResolution] = 256;
75 STParsedJSONObject obj("Test", j);
76 BEAST_EXPECT(!obj.object.has_value());
77 }
78
79 // Test bad_type (not a string/int/uint)
80 {
82 j[sfCloseResolution] = Json::Value(Json::arrayValue);
83 STParsedJSONObject obj("Test", j);
84 BEAST_EXPECT(!obj.object.has_value());
85 }
86
87 // Test bad_type (not a string/int/uint)
88 {
90 j[sfCloseResolution] = Json::Value(Json::objectValue);
91 STParsedJSONObject obj("Test", j);
92 BEAST_EXPECT(!obj.object.has_value());
93 }
94 }
95
96 void
98 {
99 testcase("UInt16");
100 // Test with int value
101 {
102 Json::Value j;
103 j[sfLedgerEntryType] = 65535;
104 STParsedJSONObject obj("Test", j);
105 BEAST_EXPECT(obj.object.has_value());
106 BEAST_EXPECT(obj.object->isFieldPresent(sfLedgerEntryType));
107 BEAST_EXPECT(obj.object->getFieldU16(sfLedgerEntryType) == 65535);
108 }
109
110 // Test with uint value
111 {
112 Json::Value j;
113 j[sfLedgerEntryType] = 65535u;
114 STParsedJSONObject obj("Test", j);
115 BEAST_EXPECT(obj.object.has_value());
116 BEAST_EXPECT(obj.object->isFieldPresent(sfLedgerEntryType));
117 BEAST_EXPECT(obj.object->getFieldU16(sfLedgerEntryType) == 65535);
118 }
119
120 // Test with string value
121 {
122 Json::Value j;
123 j[sfLedgerEntryType] = "65535";
124 STParsedJSONObject obj("Test", j);
125 BEAST_EXPECT(obj.object.has_value());
126 BEAST_EXPECT(obj.object->isFieldPresent(sfLedgerEntryType));
127 BEAST_EXPECT(obj.object->getFieldU16(sfLedgerEntryType) == 65535);
128 }
129
130 // Test min value for uint16
131 {
132 Json::Value j;
133 j[sfLedgerEntryType] = 0;
134 STParsedJSONObject obj("Test", j);
135 BEAST_EXPECT(obj.object.has_value());
136 BEAST_EXPECT(obj.object->getFieldU16(sfLedgerEntryType) == 0);
137 }
138
139 // Test out of range value for UInt16 (negative)
140 {
141 Json::Value j;
142 j[sfLedgerEntryType] = -1;
143 STParsedJSONObject obj("Test", j);
144 BEAST_EXPECT(!obj.object.has_value());
145 }
146
147 // Test out of range value for UInt16 (too large)
148 {
149 Json::Value j;
150 j[sfLedgerEntryType] = 65536;
151 STParsedJSONObject obj("Test", j);
152 BEAST_EXPECT(!obj.object.has_value());
153 }
154
155 // Test string value out of range
156 {
157 Json::Value j;
158 j[sfLedgerEntryType] = "65536";
159 STParsedJSONObject obj("Test", j);
160 BEAST_EXPECT(!obj.object.has_value());
161 }
162
163 // Test bad_type (not a string/int/uint)
164 {
165 Json::Value j;
166 j[sfLedgerEntryType] = Json::Value(Json::arrayValue);
167 STParsedJSONObject obj("Test", j);
168 BEAST_EXPECT(!obj.object.has_value());
169 }
170
171 // Test bad_type (not a string/int/uint)
172 {
173 Json::Value j;
174 j[sfLedgerEntryType] = Json::Value(Json::objectValue);
175 STParsedJSONObject obj("Test", j);
176 BEAST_EXPECT(!obj.object.has_value());
177 }
178
179 // Invalid input for other field
180 {
181 Json::Value j;
182 j[sfTransferFee] = "Payment";
183 STParsedJSONObject obj("Test", j);
184 BEAST_EXPECT(!obj.object.has_value());
185 }
186 }
187
188 void
190 {
191 testcase("UInt32");
192 {
193 Json::Value j;
194 j[sfNetworkID] = 4294967295u;
195 STParsedJSONObject obj("Test", j);
196 BEAST_EXPECT(obj.object.has_value());
197 BEAST_EXPECT(obj.object->isFieldPresent(sfNetworkID));
198 BEAST_EXPECT(obj.object->getFieldU32(sfNetworkID) == 4294967295u);
199 }
200
201 // Test with string value
202 {
203 Json::Value j;
204 j[sfNetworkID] = "4294967295";
205 STParsedJSONObject obj("Test", j);
206 BEAST_EXPECT(obj.object.has_value());
207 BEAST_EXPECT(obj.object->isFieldPresent(sfNetworkID));
208 BEAST_EXPECT(obj.object->getFieldU32(sfNetworkID) == 4294967295u);
209 }
210
211 // Test min value for uint32
212 {
213 Json::Value j;
214 j[sfNetworkID] = 0;
215 STParsedJSONObject obj("Test", j);
216 BEAST_EXPECT(obj.object.has_value());
217 BEAST_EXPECT(obj.object->getFieldU32(sfNetworkID) == 0);
218 }
219
220 // Test out of range value for uint32 (negative)
221 {
222 Json::Value j;
223 j[sfNetworkID] = -1;
224 STParsedJSONObject obj("Test", j);
225 BEAST_EXPECT(!obj.object.has_value());
226 }
227
228 // Test string value out of range
229 {
230 Json::Value j;
231 j[sfNetworkID] = "4294967296";
232 STParsedJSONObject obj("Test", j);
233 BEAST_EXPECT(!obj.object.has_value());
234 }
235
236 // Test bad_type (arrayValue)
237 {
238 Json::Value j;
239 j[sfNetworkID] = Json::Value(Json::arrayValue);
240 STParsedJSONObject obj("Test", j);
241 BEAST_EXPECT(!obj.object.has_value());
242 }
243
244 // Test bad_type (objectValue)
245 {
246 Json::Value j;
247 j[sfNetworkID] = Json::Value(Json::objectValue);
248 STParsedJSONObject obj("Test", j);
249 BEAST_EXPECT(!obj.object.has_value());
250 }
251 }
252
253 void
255 {
256 testcase("UInt64");
257 {
258 Json::Value j;
259 j[sfIndexNext] = "ffffffffffffffff";
260 STParsedJSONObject obj("Test", j);
261 BEAST_EXPECT(obj.object.has_value());
262 BEAST_EXPECT(obj.object->isFieldPresent(sfIndexNext));
263 BEAST_EXPECT(obj.object->getFieldU64(sfIndexNext) == 18446744073709551615ull);
264 }
265
266 // Test min value for uint64
267 {
268 Json::Value j;
269 j[sfIndexNext] = 0;
270 STParsedJSONObject obj("Test", j);
271 BEAST_EXPECT(obj.object.has_value());
272 BEAST_EXPECT(obj.object->getFieldU64(sfIndexNext) == 0ull);
273 }
274
275 // Test out of range value for uint64 (negative)
276 {
277 Json::Value j;
278 j[sfIndexNext] = -1;
279 STParsedJSONObject obj("Test", j);
280 BEAST_EXPECT(!obj.object.has_value());
281 }
282
283 // NOTE: the JSON parser doesn't support > UInt32, so those values must
284 // be in hex
285 // Test string value out of range
286 // string is interpreted as hex
287 {
288 Json::Value j;
289 j[sfIndexNext] = "10000000000000000"; // uint64 max + 1 (in hex)
290 STParsedJSONObject obj("Test", j);
291 BEAST_EXPECT(!obj.object.has_value());
292 }
293
294 // Test hex string value with 0x prefix (should fail)
295 {
296 Json::Value j;
297 j[sfIndexNext] = "0xabcdefabcdef";
298 STParsedJSONObject obj("Test", j);
299 BEAST_EXPECT(!obj.object.has_value());
300 }
301
302 // Test hex string value with invalid characters
303 {
304 Json::Value j;
305 j[sfIndexNext] = "abcdefga";
306 STParsedJSONObject obj("Test", j);
307 BEAST_EXPECT(!obj.object.has_value());
308 }
309
310 // test arrayValue
311 {
312 Json::Value j;
313 j[sfIndexNext] = Json::Value(Json::arrayValue);
314 STParsedJSONObject obj("Test", j);
315 BEAST_EXPECT(!obj.object.has_value());
316 }
317
318 // test objectValue
319 {
320 Json::Value j;
321 j[sfIndexNext] = Json::Value(Json::objectValue);
322 STParsedJSONObject obj("Test", j);
323 BEAST_EXPECT(!obj.object.has_value());
324 }
325 }
326
327 void
329 {
330 testcase("UInt128");
331 {
332 Json::Value j;
333 j[sfEmailHash] = "0123456789ABCDEF0123456789ABCDEF";
334 STParsedJSONObject obj("Test", j);
335 BEAST_EXPECT(obj.object.has_value());
336 BEAST_EXPECT(obj.object->isFieldPresent(sfEmailHash));
337 BEAST_EXPECT(obj.object->getFieldH128(sfEmailHash).size() == 16);
338 std::array<uint8_t, 16> expected = {
339 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
340 BEAST_EXPECT(obj.object->getFieldH128(sfEmailHash) == uint128{expected});
341 }
342
343 // Valid lowercase hex string for UInt128
344 {
345 Json::Value j;
346 j[sfEmailHash] = "0123456789abcdef0123456789abcdef";
347 STParsedJSONObject obj("Test", j);
348 BEAST_EXPECT(obj.object.has_value());
349 BEAST_EXPECT(obj.object->isFieldPresent(sfEmailHash));
350 BEAST_EXPECT(obj.object->getFieldH128(sfEmailHash).size() == 16);
351 }
352
353 // Empty string for UInt128 (should be valid, all zero)
354 {
355 Json::Value j;
356 j[sfEmailHash] = "";
357 STParsedJSONObject obj("Test", j);
358 BEAST_EXPECT(obj.object.has_value());
359 BEAST_EXPECT(obj.object->isFieldPresent(sfEmailHash));
360 auto const& h128 = obj.object->getFieldH128(sfEmailHash);
361 BEAST_EXPECT(h128.size() == 16);
362 bool allZero = std::all_of(h128.begin(), h128.end(), [](auto b) { return b == 0; });
363 BEAST_EXPECT(allZero);
364 }
365
366 // Odd-length hex string for UInt128 (should fail)
367 {
368 Json::Value j;
369 j[sfEmailHash] = "0123456789ABCDEF0123456789ABCDE";
370 STParsedJSONObject obj("Test", j);
371 BEAST_EXPECT(!obj.object.has_value());
372 }
373
374 // Non-hex string for UInt128 (should fail)
375 {
376 Json::Value j;
377 j[sfEmailHash] = "nothexstring";
378 STParsedJSONObject obj("Test", j);
379 BEAST_EXPECT(!obj.object.has_value());
380 }
381
382 // Hex string too short for UInt128 (should fail)
383 {
384 Json::Value j;
385 j[sfEmailHash] = "01234567";
386 STParsedJSONObject obj("Test", j);
387 BEAST_EXPECT(!obj.object.has_value());
388 }
389
390 // Hex string too long for UInt128 (should fail)
391 {
392 Json::Value j;
393 j[sfEmailHash] = "0123456789ABCDEF0123456789ABCDEF00";
394 STParsedJSONObject obj("Test", j);
395 BEAST_EXPECT(!obj.object.has_value());
396 }
397
398 // Array value for UInt128 (should fail)
399 {
400 Json::Value j;
401 j[sfEmailHash] = Json::Value(Json::arrayValue);
402 STParsedJSONObject obj("Test", j);
403 BEAST_EXPECT(!obj.object.has_value());
404 }
405
406 // Object value for UInt128 (should fail)
407 {
408 Json::Value j;
409 j[sfEmailHash] = Json::Value(Json::objectValue);
410 STParsedJSONObject obj("Test", j);
411 BEAST_EXPECT(!obj.object.has_value());
412 }
413 }
414
415 void
417 {
418 testcase("UInt160");
419 {
420 Json::Value j;
421 j[sfTakerPaysCurrency] = "0123456789ABCDEF0123456789ABCDEF01234567";
422 STParsedJSONObject obj("Test", j);
423 BEAST_EXPECT(obj.object.has_value());
424 BEAST_EXPECT(obj.object->isFieldPresent(sfTakerPaysCurrency));
425 BEAST_EXPECT(obj.object->getFieldH160(sfTakerPaysCurrency).size() == 20);
426 std::array<uint8_t, 20> expected = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23,
427 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67};
428 BEAST_EXPECT(obj.object->getFieldH160(sfTakerPaysCurrency) == uint160{expected});
429 }
430 // Valid lowercase hex string for UInt160
431 {
432 Json::Value j;
433 j[sfTakerPaysCurrency] = "0123456789abcdef0123456789abcdef01234567";
434 STParsedJSONObject obj("Test", j);
435 BEAST_EXPECT(obj.object.has_value());
436 BEAST_EXPECT(obj.object->isFieldPresent(sfTakerPaysCurrency));
437 BEAST_EXPECT(obj.object->getFieldH160(sfTakerPaysCurrency).size() == 20);
438 }
439
440 // Empty string for UInt160 (should be valid, all zero)
441 {
442 Json::Value j;
443 j[sfTakerPaysCurrency] = "";
444 STParsedJSONObject obj("Test", j);
445 BEAST_EXPECT(obj.object.has_value());
446 BEAST_EXPECT(obj.object->isFieldPresent(sfTakerPaysCurrency));
447 auto const& h160 = obj.object->getFieldH160(sfTakerPaysCurrency);
448 BEAST_EXPECT(h160.size() == 20);
449 bool allZero = std::all_of(h160.begin(), h160.end(), [](auto b) { return b == 0; });
450 BEAST_EXPECT(allZero);
451 }
452
453 // Non-hex string for UInt160 (should fail)
454 {
455 Json::Value j;
456 j[sfTakerPaysCurrency] = "nothexstring";
457 STParsedJSONObject obj("Test", j);
458 BEAST_EXPECT(!obj.object.has_value());
459 }
460
461 // Hex string too short for UInt160 (should fail)
462 {
463 Json::Value j;
464 j[sfTakerPaysCurrency] = "01234567";
465 STParsedJSONObject obj("Test", j);
466 BEAST_EXPECT(!obj.object.has_value());
467 }
468
469 // Hex string too long for UInt160 (should fail)
470 {
471 Json::Value j;
472 j[sfTakerPaysCurrency] = "0123456789ABCDEF0123456789ABCDEF0123456789";
473 STParsedJSONObject obj("Test", j);
474 BEAST_EXPECT(!obj.object.has_value());
475 }
476
477 // Array value for UInt160 (should fail)
478 {
479 Json::Value j;
480 j[sfTakerPaysCurrency] = Json::Value(Json::arrayValue);
481 STParsedJSONObject obj("Test", j);
482 BEAST_EXPECT(!obj.object.has_value());
483 }
484
485 // Object value for UInt160 (should fail)
486 {
487 Json::Value j;
488 j[sfTakerPaysCurrency] = Json::Value(Json::objectValue);
489 STParsedJSONObject obj("Test", j);
490 BEAST_EXPECT(!obj.object.has_value());
491 }
492 }
493
494 void
496 {
497 testcase("UInt192");
498 {
499 Json::Value j;
500 j[sfMPTokenIssuanceID] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";
501 STParsedJSONObject obj("Test", j);
502 BEAST_EXPECT(obj.object.has_value());
503 BEAST_EXPECT(obj.object->isFieldPresent(sfMPTokenIssuanceID));
504 BEAST_EXPECT(obj.object->getFieldH192(sfMPTokenIssuanceID).size() == 24);
505 std::array<uint8_t, 24> expected = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
506 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
507 BEAST_EXPECT(obj.object->getFieldH192(sfMPTokenIssuanceID) == uint192{expected});
508 }
509
510 // Valid lowercase hex string for UInt192
511 {
512 Json::Value j;
513 j[sfMPTokenIssuanceID] = "ffffffffffffffffffffffffffffffffffffffffffffffff";
514 STParsedJSONObject obj("Test", j);
515 BEAST_EXPECT(obj.object.has_value());
516 BEAST_EXPECT(obj.object->isFieldPresent(sfMPTokenIssuanceID));
517 BEAST_EXPECT(obj.object->getFieldH192(sfMPTokenIssuanceID).size() == 24);
518 }
519
520 // Empty string for UInt192 (should be valid, all zero)
521 {
522 Json::Value j;
523 j[sfMPTokenIssuanceID] = "";
524 STParsedJSONObject obj("Test", j);
525 BEAST_EXPECT(obj.object.has_value());
526 BEAST_EXPECT(obj.object->isFieldPresent(sfMPTokenIssuanceID));
527 auto const& h192 = obj.object->getFieldH192(sfMPTokenIssuanceID);
528 BEAST_EXPECT(h192.size() == 24);
529 bool allZero = std::all_of(h192.begin(), h192.end(), [](auto b) { return b == 0; });
530 BEAST_EXPECT(allZero);
531 }
532
533 // Odd-length hex string for UInt192 (should fail)
534 {
535 Json::Value j;
536 j[sfMPTokenIssuanceID] = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDE";
537 STParsedJSONObject obj("Test", j);
538 BEAST_EXPECT(!obj.object.has_value());
539 }
540
541 // Non-hex string for UInt192 (should fail)
542 {
543 Json::Value j;
544 j[sfMPTokenIssuanceID] = "nothexstring";
545 STParsedJSONObject obj("Test", j);
546 BEAST_EXPECT(!obj.object.has_value());
547 }
548
549 // Hex string too short for UInt192 (should fail)
550 {
551 Json::Value j;
552 j[sfMPTokenIssuanceID] = "01234567";
553 STParsedJSONObject obj("Test", j);
554 BEAST_EXPECT(!obj.object.has_value());
555 }
556
557 // Hex string too long for UInt192 (should fail)
558 {
559 Json::Value j;
560 j[sfMPTokenIssuanceID] = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF00";
561 STParsedJSONObject obj("Test", j);
562 BEAST_EXPECT(!obj.object.has_value());
563 }
564
565 // Array value for UInt192 (should fail)
566 {
567 Json::Value j;
568 j[sfMPTokenIssuanceID] = Json::Value(Json::arrayValue);
569 STParsedJSONObject obj("Test", j);
570 BEAST_EXPECT(!obj.object.has_value());
571 }
572
573 // Object value for UInt192 (should fail)
574 {
575 Json::Value j;
576 j[sfMPTokenIssuanceID] = Json::Value(Json::objectValue);
577 STParsedJSONObject obj("Test", j);
578 BEAST_EXPECT(!obj.object.has_value());
579 }
580 }
581
582 void
584 {
585 testcase("UInt256");
586 // Test with valid hex string for UInt256
587 {
588 Json::Value j;
589 j[sfLedgerHash] =
590 "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD"
591 "EF";
592 STParsedJSONObject obj("Test", j);
593 BEAST_EXPECT(obj.object.has_value());
594 BEAST_EXPECT(obj.object->isFieldPresent(sfLedgerHash));
595 BEAST_EXPECT(obj.object->getFieldH256(sfLedgerHash).size() == 32);
596 std::array<uint8_t, 32> expected = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45,
597 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB,
598 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
599 BEAST_EXPECT(obj.object->getFieldH256(sfLedgerHash) == uint256{expected});
600 }
601 // Valid lowercase hex string for UInt256
602 {
603 Json::Value j;
604 j[sfLedgerHash] =
605 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
606 "ef";
607 STParsedJSONObject obj("Test", j);
608 BEAST_EXPECT(obj.object.has_value());
609 BEAST_EXPECT(obj.object->isFieldPresent(sfLedgerHash));
610 BEAST_EXPECT(obj.object->getFieldH256(sfLedgerHash).size() == 32);
611 }
612
613 // Empty string for UInt256 (should be valid, all zero)
614 {
615 Json::Value j;
616 j[sfLedgerHash] = "";
617 STParsedJSONObject obj("Test", j);
618 BEAST_EXPECT(obj.object.has_value());
619 BEAST_EXPECT(obj.object->isFieldPresent(sfLedgerHash));
620 auto const& h256 = obj.object->getFieldH256(sfLedgerHash);
621 BEAST_EXPECT(h256.size() == 32);
622 bool allZero = std::all_of(h256.begin(), h256.end(), [](auto b) { return b == 0; });
623 BEAST_EXPECT(allZero);
624 }
625
626 // Odd-length hex string for UInt256 (should fail)
627 {
628 Json::Value j;
629 j[sfLedgerHash] =
630 "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD"
631 "E";
632 STParsedJSONObject obj("Test", j);
633 BEAST_EXPECT(!obj.object.has_value());
634 }
635
636 // Non-hex string for UInt256 (should fail)
637 {
638 Json::Value j;
639 j[sfLedgerHash] = "nothexstring";
640 STParsedJSONObject obj("Test", j);
641 BEAST_EXPECT(!obj.object.has_value());
642 }
643
644 // Hex string too short for UInt256 (should fail)
645 {
646 Json::Value j;
647 j[sfLedgerHash] = "01234567";
648 STParsedJSONObject obj("Test", j);
649 BEAST_EXPECT(!obj.object.has_value());
650 }
651
652 // Hex string too long for UInt256 (should fail)
653 {
654 Json::Value j;
655 j[sfLedgerHash] =
656 "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD"
657 "EF00";
658 STParsedJSONObject obj("Test", j);
659 BEAST_EXPECT(!obj.object.has_value());
660 }
661
662 // Array value for UInt256 (should fail)
663 {
664 Json::Value j;
665 j[sfLedgerHash] = Json::Value(Json::arrayValue);
666 STParsedJSONObject obj("Test", j);
667 BEAST_EXPECT(!obj.object.has_value());
668 }
669
670 // Object value for UInt256 (should fail)
671 {
672 Json::Value j;
673 j[sfLedgerHash] = Json::Value(Json::objectValue);
674 STParsedJSONObject obj("Test", j);
675 BEAST_EXPECT(!obj.object.has_value());
676 }
677 }
678
679 void
681 {
682 testcase("Int32");
683 {
684 Json::Value j;
685 int const minInt32 = -2147483648;
686 j[sfLoanScale] = minInt32;
687 STParsedJSONObject obj("Test", j);
688 BEAST_EXPECT(obj.object.has_value());
689 if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale)))
690 BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == minInt32);
691 }
692
693 // max value
694 {
695 Json::Value j;
696 int const maxInt32 = 2147483647;
697 j[sfLoanScale] = maxInt32;
698 STParsedJSONObject obj("Test", j);
699 BEAST_EXPECT(obj.object.has_value());
700 if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale)))
701 BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == maxInt32);
702 }
703
704 // max uint value
705 {
706 Json::Value j;
707 unsigned int const maxUInt32 = 2147483647u;
708 j[sfLoanScale] = maxUInt32;
709 STParsedJSONObject obj("Test", j);
710 BEAST_EXPECT(obj.object.has_value());
711 if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale)))
712 BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == static_cast<int32_t>(maxUInt32));
713 }
714
715 // Test with string value
716 {
717 Json::Value j;
718 j[sfLoanScale] = "2147483647";
719 STParsedJSONObject obj("Test", j);
720 BEAST_EXPECT(obj.object.has_value());
721 if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale)))
722 BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == 2147483647u);
723 }
724
725 // Test with string negative value
726 {
727 Json::Value j;
728 int value = -2147483648;
729 j[sfLoanScale] = std::to_string(value);
730 STParsedJSONObject obj("Test", j);
731 BEAST_EXPECT(obj.object.has_value());
732 if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale)))
733 BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == value);
734 }
735
736 // Test out of range value for int32 (negative)
737 {
738 Json::Value j;
739 j[sfLoanScale] = "-2147483649";
740 STParsedJSONObject obj("Test", j);
741 BEAST_EXPECT(!obj.object.has_value());
742 }
743
744 // Test out of range value for int32 (positive)
745 {
746 Json::Value j;
747 j[sfLoanScale] = 2147483648u;
748 STParsedJSONObject obj("Test", j);
749 BEAST_EXPECT(!obj.object.has_value());
750 }
751
752 // Test string value out of range
753 {
754 Json::Value j;
755 j[sfLoanScale] = "2147483648";
756 STParsedJSONObject obj("Test", j);
757 BEAST_EXPECT(!obj.object.has_value());
758 }
759
760 // Test bad_type (arrayValue)
761 {
762 Json::Value j;
763 j[sfLoanScale] = Json::Value(Json::arrayValue);
764 STParsedJSONObject obj("Test", j);
765 BEAST_EXPECT(!obj.object.has_value());
766 }
767
768 // Test bad_type (objectValue)
769 {
770 Json::Value j;
771 j[sfLoanScale] = Json::Value(Json::objectValue);
772 STParsedJSONObject obj("Test", j);
773 BEAST_EXPECT(!obj.object.has_value());
774 }
775 }
776
777 void
779 {
780 testcase("Blob");
781 // Test with valid hex string for blob
782 {
783 Json::Value j;
784 j[sfPublicKey] = "DEADBEEF";
785 STParsedJSONObject obj("Test", j);
786 BEAST_EXPECT(obj.object.has_value());
787 BEAST_EXPECT(obj.object->isFieldPresent(sfPublicKey));
788 auto const& blob = obj.object->getFieldVL(sfPublicKey);
789 BEAST_EXPECT(blob.size() == 4);
790 BEAST_EXPECT(blob[0] == 0xDE);
791 BEAST_EXPECT(blob[1] == 0xAD);
792 BEAST_EXPECT(blob[2] == 0xBE);
793 BEAST_EXPECT(blob[3] == 0xEF);
794 }
795
796 // Test empty string for blob (should be valid, size 0)
797 {
798 Json::Value j;
799 j[sfPublicKey] = "";
800 STParsedJSONObject obj("Test", j);
801 BEAST_EXPECT(obj.object.has_value());
802 BEAST_EXPECT(obj.object->isFieldPresent(sfPublicKey));
803 auto const& blob = obj.object->getFieldVL(sfPublicKey);
804 BEAST_EXPECT(blob.size() == 0);
805 }
806
807 // Test lowercase hex string for blob
808 {
809 Json::Value j;
810 j[sfPublicKey] = "deadbeef";
811 STParsedJSONObject obj("Test", j);
812 BEAST_EXPECT(obj.object.has_value());
813 BEAST_EXPECT(obj.object->isFieldPresent(sfPublicKey));
814 auto const& blob = obj.object->getFieldVL(sfPublicKey);
815 BEAST_EXPECT(blob.size() == 4);
816 BEAST_EXPECT(blob[0] == 0xDE);
817 BEAST_EXPECT(blob[1] == 0xAD);
818 BEAST_EXPECT(blob[2] == 0xBE);
819 BEAST_EXPECT(blob[3] == 0xEF);
820 }
821
822 // Test non-hex string for blob (should fail)
823 {
824 Json::Value j;
825 j[sfPublicKey] = "XYZ123";
826 STParsedJSONObject obj("Test", j);
827 BEAST_EXPECT(!obj.object.has_value());
828 }
829
830 // Test array value for blob (should fail)
831 {
832 Json::Value j;
833 j[sfPublicKey] = Json::Value(Json::arrayValue);
834 STParsedJSONObject obj("Test", j);
835 BEAST_EXPECT(!obj.object.has_value());
836 }
837
838 // Test object value for blob (should fail)
839 {
840 Json::Value j;
841 j[sfPublicKey] = Json::Value(Json::objectValue);
842 STParsedJSONObject obj("Test", j);
843 BEAST_EXPECT(!obj.object.has_value());
844 }
845 }
846
847 void
849 {
850 testcase("Vector256");
851 // Test with valid array of hex strings for Vector256
852 {
853 Json::Value j;
855 arr.append(
856 "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD"
857 "EF");
858 arr.append(
859 "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA98765432"
860 "10");
861 j[sfHashes] = arr;
862 STParsedJSONObject obj("Test", j);
863 BEAST_EXPECT(obj.object.has_value());
864 BEAST_EXPECT(obj.object->isFieldPresent(sfHashes));
865 auto const& vec = obj.object->getFieldV256(sfHashes);
866 BEAST_EXPECT(vec.size() == 2);
867 BEAST_EXPECT(to_string(vec[0]) == arr[0u].asString());
868 BEAST_EXPECT(to_string(vec[1]) == arr[1u].asString());
869 }
870 // Test empty array for Vector256 (should be valid, size 0)
871 {
872 Json::Value j;
874 j[sfHashes] = arr;
875 STParsedJSONObject obj("Test", j);
876 BEAST_EXPECT(obj.object.has_value());
877 BEAST_EXPECT(obj.object->isFieldPresent(sfHashes));
878 auto const& vec = obj.object->getFieldV256(sfHashes);
879 BEAST_EXPECT(vec.size() == 0);
880 }
881
882 // Test array with invalid hex string (should fail)
883 {
884 Json::Value j;
886 arr.append("nothexstring");
887 j[sfHashes] = arr;
888 STParsedJSONObject obj("Test", j);
889 BEAST_EXPECT(!obj.object.has_value());
890 }
891
892 // Test array with string of wrong length (should fail)
893 {
894 Json::Value j;
896 arr.append("0123456789ABCDEF"); // too short for uint256
897 j[sfHashes] = arr;
898 STParsedJSONObject obj("Test", j);
899 BEAST_EXPECT(!obj.object.has_value());
900 }
901
902 // Test array with non-string element (should fail)
903 {
904 Json::Value j;
906 arr.append(12345);
907 j[sfHashes] = arr;
908 STParsedJSONObject obj("Test", j);
909 BEAST_EXPECT(!obj.object.has_value());
910 }
911
912 // Test non-array value for Vector256 (should fail)
913 {
914 Json::Value j;
915 j[sfHashes] = "notanarray";
916 STParsedJSONObject obj("Test", j);
917 BEAST_EXPECT(!obj.object.has_value());
918 }
919
920 // Test array with object element (should fail)
921 {
922 Json::Value j;
925 objElem["foo"] = "bar";
926 arr.append(objElem);
927 j[sfHashes] = arr;
928 STParsedJSONObject obj("Test", j);
929 BEAST_EXPECT(!obj.object.has_value());
930 }
931 }
932
933 void
935 {
936 testcase("Account");
937 // Test with valid base58 string for AccountID
938 {
939 Json::Value j;
940 j[sfAccount] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
941 STParsedJSONObject obj("Test", j);
942 BEAST_EXPECT(obj.object.has_value());
943 BEAST_EXPECT(obj.object->isFieldPresent(sfAccount));
944 auto const& acct = obj.object->getAccountID(sfAccount);
945 BEAST_EXPECT(acct.size() == 20);
946 BEAST_EXPECT(toBase58(acct) == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
947 }
948
949 // Valid hex string for AccountID
950 {
951 Json::Value j;
952 j[sfAccount] = "000102030405060708090A0B0C0D0E0F10111213";
953 STParsedJSONObject obj("Test", j);
954 BEAST_EXPECT(obj.object.has_value());
955 BEAST_EXPECT(obj.object->isFieldPresent(sfAccount));
956 auto const& acct = obj.object->getAccountID(sfAccount);
957 BEAST_EXPECT(acct.size() == 20);
958 }
959
960 // Invalid base58 string for AccountID
961 {
962 Json::Value j;
963 j[sfAccount] = "notAValidBase58Account";
964 STParsedJSONObject obj("Test", j);
965 BEAST_EXPECT(!obj.object.has_value());
966 }
967
968 // Invalid hex string for AccountID (too short)
969 {
970 Json::Value j;
971 j[sfAccount] = "001122334455";
972 STParsedJSONObject obj("Test", j);
973 BEAST_EXPECT(!obj.object.has_value());
974 }
975
976 // Invalid hex string for AccountID (too long)
977 {
978 Json::Value j;
979 j[sfAccount] = "000102030405060708090A0B0C0D0E0F101112131415";
980 STParsedJSONObject obj("Test", j);
981 BEAST_EXPECT(!obj.object.has_value());
982 }
983
984 // Invalid hex string for AccountID (bad chars)
985 {
986 Json::Value j;
987 j[sfAccount] = "000102030405060708090A0B0C0D0E0F1011121G";
988 STParsedJSONObject obj("Test", j);
989 BEAST_EXPECT(!obj.object.has_value());
990 }
991
992 // Empty string for AccountID (should fail)
993 {
994 Json::Value j;
995 j[sfAccount] = "";
996 STParsedJSONObject obj("Test", j);
997 BEAST_EXPECT(!obj.object.has_value());
998 }
999
1000 // Array value for AccountID (should fail)
1001 {
1002 Json::Value j;
1003 j[sfAccount] = Json::Value(Json::arrayValue);
1004 STParsedJSONObject obj("Test", j);
1005 BEAST_EXPECT(!obj.object.has_value());
1006 }
1007
1008 // Object value for AccountID (should fail)
1009 {
1010 Json::Value j;
1011 j[sfAccount] = Json::Value(Json::objectValue);
1012 STParsedJSONObject obj("Test", j);
1013 BEAST_EXPECT(!obj.object.has_value());
1014 }
1015 }
1016
1017 void
1019 {
1020 testcase("Currency");
1021 // Test with valid ISO code for currency
1022 {
1023 Json::Value j;
1024 j[sfBaseAsset] = "USD";
1025 STParsedJSONObject obj("Test", j);
1026 BEAST_EXPECT(obj.object.has_value());
1027 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1028 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1029 BEAST_EXPECT(curr.currency().size() == 20);
1030 }
1031
1032 // Valid ISO code
1033 {
1034 Json::Value j;
1035 j[sfBaseAsset] = "EUR";
1036 STParsedJSONObject obj("Test", j);
1037 BEAST_EXPECT(obj.object.has_value());
1038 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1039 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1040 BEAST_EXPECT(curr.currency().size() == 20);
1041 }
1042
1043 // Valid hex string for currency
1044 {
1045 Json::Value j;
1046 j[sfBaseAsset] = "0123456789ABCDEF01230123456789ABCDEF0123";
1047 STParsedJSONObject obj("Test", j);
1048 if (BEAST_EXPECT(obj.object.has_value()))
1049 {
1050 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1051 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1052 BEAST_EXPECT(curr.currency().size() == 20);
1053 }
1054 }
1055
1056 // Invalid ISO code (too long)
1057 {
1058 Json::Value j;
1059 j[sfBaseAsset] = "USDD";
1060 STParsedJSONObject obj("Test", j);
1061 BEAST_EXPECT(!obj.object.has_value());
1062 }
1063
1064 // lowercase ISO code
1065 {
1066 Json::Value j;
1067 j[sfBaseAsset] = "usd";
1068 STParsedJSONObject obj("Test", j);
1069 BEAST_EXPECT(obj.object.has_value());
1070 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1071 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1072 BEAST_EXPECT(curr.currency().size() == 20);
1073 }
1074
1075 // Invalid hex string (too short)
1076 {
1077 Json::Value j;
1078 j[sfBaseAsset] = "0123456789AB";
1079 STParsedJSONObject obj("Test", j);
1080 BEAST_EXPECT(!obj.object.has_value());
1081 }
1082
1083 // Invalid hex string (too long)
1084 {
1085 Json::Value j;
1086 j[sfBaseAsset] = "0123456789ABCDEF0123456789";
1087 STParsedJSONObject obj("Test", j);
1088 BEAST_EXPECT(!obj.object.has_value());
1089 }
1090
1091 // Empty string for currency (should fail)
1092 {
1093 Json::Value j;
1094 j[sfBaseAsset] = "";
1095 STParsedJSONObject obj("Test", j);
1096 BEAST_EXPECT(obj.object.has_value());
1097 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1098 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1099 BEAST_EXPECT(curr.currency().size() == 20);
1100 }
1101
1102 // Array value for currency (should fail)
1103 {
1104 Json::Value j;
1105 j[sfBaseAsset] = Json::Value(Json::arrayValue);
1106 STParsedJSONObject obj("Test", j);
1107 BEAST_EXPECT(!obj.object.has_value());
1108 }
1109
1110 // Object value for currency (should fail)
1111 {
1112 Json::Value j;
1113 j[sfBaseAsset] = Json::Value(Json::objectValue);
1114 STParsedJSONObject obj("Test", j);
1115 BEAST_EXPECT(!obj.object.has_value());
1116 }
1117 }
1118
1119 void
1121 {
1122 testcase("Amount");
1123 // Test with string value for Amount
1124 {
1125 Json::Value j;
1126 j[sfAmount] = "100000000000000000";
1127 STParsedJSONObject obj("Test", j);
1128 BEAST_EXPECT(obj.object.has_value());
1129 BEAST_EXPECT(obj.object->isFieldPresent(sfAmount));
1130 BEAST_EXPECT(obj.object->getFieldAmount(sfAmount) == STAmount(100000000000000000ull));
1131 }
1132
1133 // Test with int value for Amount
1134 {
1135 Json::Value j;
1136 j[sfAmount] = 4294967295u;
1137 STParsedJSONObject obj("Test", j);
1138 BEAST_EXPECT(obj.object.has_value());
1139 BEAST_EXPECT(obj.object->isFieldPresent(sfAmount));
1140 BEAST_EXPECT(obj.object->getFieldAmount(sfAmount) == STAmount(4294967295u));
1141 }
1142
1143 // Test with decimal string for Amount (should fail)
1144 {
1145 Json::Value j;
1146 j[sfAmount] = "123.45";
1147 STParsedJSONObject obj("Test", j);
1148 BEAST_EXPECT(!obj.object.has_value());
1149 }
1150
1151 // Test with empty string for Amount (should fail)
1152 {
1153 Json::Value j;
1154 j[sfAmount] = "";
1155 STParsedJSONObject obj("Test", j);
1156 BEAST_EXPECT(!obj.object.has_value());
1157 }
1158
1159 // Test with non-numeric string for Amount (should fail)
1160 {
1161 Json::Value j;
1162 j[sfAmount] = "notanumber";
1163 STParsedJSONObject obj("Test", j);
1164 BEAST_EXPECT(!obj.object.has_value());
1165 }
1166
1167 // Test with object value for Amount (should fail)
1168 {
1169 Json::Value j;
1170 j[sfAmount] = Json::Value(Json::objectValue);
1171 STParsedJSONObject obj("Test", j);
1172 BEAST_EXPECT(!obj.object.has_value());
1173 }
1174 }
1175
1176 void
1178 {
1179 testcase("PathSet");
1180 // Valid test: single path with single element
1181 {
1182 Json::Value j;
1185 elem["account"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1186 elem["currency"] = "USD";
1187 elem["issuer"] = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe";
1188 path.append(elem);
1190 pathset.append(path);
1191 j[sfPaths] = pathset;
1192 STParsedJSONObject obj("Test", j);
1193 if (BEAST_EXPECT(obj.object.has_value()))
1194 {
1195 BEAST_EXPECT(obj.object->isFieldPresent(sfPaths));
1196 auto const& ps = obj.object->getFieldPathSet(sfPaths);
1197 BEAST_EXPECT(!ps.empty());
1198 BEAST_EXPECT(ps.size() == 1);
1199 BEAST_EXPECT(ps[0].size() == 1);
1200 BEAST_EXPECT(ps[0][0].getAccountID() == parseBase58<AccountID>("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"));
1201 BEAST_EXPECT(to_string(ps[0][0].getCurrency()) == "USD");
1202 BEAST_EXPECT(ps[0][0].getIssuerID() == parseBase58<AccountID>("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"));
1203 }
1204 }
1205
1206 // Valid test: non-standard currency code
1207 {
1208 Json::Value j;
1211 elem["account"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1212 elem["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123";
1213 elem["issuer"] = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe";
1214 path.append(elem);
1216 pathset.append(path);
1217 j[sfPaths] = pathset;
1218 STParsedJSONObject obj("Test", j);
1219 BEAST_EXPECT(obj.object.has_value());
1220 BEAST_EXPECT(obj.object->isFieldPresent(sfPaths));
1221 auto const& ps = obj.object->getFieldPathSet(sfPaths);
1222 BEAST_EXPECT(!ps.empty());
1223 }
1224
1225 // Test with non-array value for PathSet (should fail)
1226 {
1227 Json::Value j;
1228 j[sfPaths] = "notanarray";
1229 STParsedJSONObject obj("Test", j);
1230 BEAST_EXPECT(!obj.object.has_value());
1231 }
1232
1233 // Test with array containing non-array element (should fail)
1234 {
1235 Json::Value j;
1237 pathset.append("notanarray");
1238 j[sfPaths] = pathset;
1239 STParsedJSONObject obj("Test", j);
1240 BEAST_EXPECT(!obj.object.has_value());
1241 }
1242
1243 // Test with array containing array with non-object element (should
1244 // fail)
1245 {
1246 Json::Value j;
1248 path.append("notanobject");
1250 pathset.append(path);
1251 j[sfPaths] = pathset;
1252 STParsedJSONObject obj("Test", j);
1253 BEAST_EXPECT(!obj.object.has_value());
1254 }
1255
1256 // Test with array containing array with object missing required keys
1257 // (should fail)
1258 {
1259 Json::Value j;
1262 elem["foo"] = "bar"; // not a valid path element key
1263 path.append(elem);
1265 pathset.append(path);
1266 j[sfPaths] = pathset;
1267 STParsedJSONObject obj("Test", j);
1268 BEAST_EXPECT(!obj.object.has_value());
1269 }
1270
1271 // Test with array containing array with object with invalid account
1272 // value (should fail)
1273 {
1274 Json::Value j;
1277 elem["account"] = "notAValidBase58Account";
1278 path.append(elem);
1280 pathset.append(path);
1281 j[sfPaths] = pathset;
1282 STParsedJSONObject obj("Test", j);
1283 BEAST_EXPECT(!obj.object.has_value());
1284 }
1285
1286 // Test with account not string (should fail)
1287 {
1288 Json::Value j;
1291 elem["account"] = 12345;
1292 path.append(elem);
1294 pathset.append(path);
1295 j[sfPaths] = pathset;
1296 STParsedJSONObject obj("Test", j);
1297 BEAST_EXPECT(!obj.object.has_value());
1298 }
1299
1300 // Test with currency not string (should fail)
1301 {
1302 Json::Value j;
1305 elem["currency"] = 12345;
1306 path.append(elem);
1308 pathset.append(path);
1309 j[sfPaths] = pathset;
1310 STParsedJSONObject obj("Test", j);
1311 BEAST_EXPECT(!obj.object.has_value());
1312 }
1313
1314 // Test with non-standard currency not hex (should fail)
1315 {
1316 Json::Value j;
1319 elem["currency"] = "notAValidCurrency";
1320 path.append(elem);
1322 pathset.append(path);
1323 j[sfPaths] = pathset;
1324 STParsedJSONObject obj("Test", j);
1325 BEAST_EXPECT(!obj.object.has_value());
1326 }
1327
1328 // Test with issuer not string (should fail)
1329 {
1330 Json::Value j;
1333 elem["issuer"] = 12345;
1334 path.append(elem);
1336 pathset.append(path);
1337 j[sfPaths] = pathset;
1338 STParsedJSONObject obj("Test", j);
1339 BEAST_EXPECT(!obj.object.has_value());
1340 }
1341
1342 // Test with issuer not base58 (should fail)
1343 {
1344 Json::Value j;
1347 elem["issuer"] = "notAValidBase58Account";
1348 path.append(elem);
1350 pathset.append(path);
1351 j[sfPaths] = pathset;
1352 STParsedJSONObject obj("Test", j);
1353 BEAST_EXPECT(!obj.object.has_value());
1354 }
1355 }
1356
1357 void
1359 {
1360 testcase("Issue");
1361 // Valid Issue: currency and issuer as base58
1362 {
1363 Json::Value j;
1364 Json::Value issueJson(Json::objectValue);
1365 issueJson["currency"] = "USD";
1366 issueJson["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1367 j[sfAsset] = issueJson;
1368 STParsedJSONObject obj("Test", j);
1369 if (BEAST_EXPECT(obj.object.has_value()))
1370 {
1371 BEAST_EXPECT(obj.object->isFieldPresent(sfAsset));
1372 auto const& issueField = (*obj.object)[sfAsset];
1373 auto const issue = issueField.value().get<Issue>();
1374 BEAST_EXPECT(issue.currency.size() == 20);
1375 BEAST_EXPECT(to_string(issue.currency) == "USD");
1376 BEAST_EXPECT(issue.account.size() == 20);
1377 BEAST_EXPECT(issue.account == parseBase58<AccountID>("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"));
1378 }
1379 }
1380
1381 // Valid Issue: currency as hex
1382 {
1383 Json::Value j;
1384 Json::Value issueJson(Json::objectValue);
1385 issueJson["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123";
1386 issueJson["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1387 j[sfAsset] = issueJson;
1388 STParsedJSONObject obj("Test", j);
1389 if (BEAST_EXPECT(obj.object.has_value()))
1390 {
1391 BEAST_EXPECT(obj.object->isFieldPresent(sfAsset));
1392 auto const& issueField = (*obj.object)[sfAsset];
1393 auto const issue = issueField.value().get<Issue>();
1394 BEAST_EXPECT(issue.currency.size() == 20);
1395 BEAST_EXPECT(issue.account.size() == 20);
1396 }
1397 }
1398
1399 // Valid Issue: MPTID
1400 {
1401 Json::Value j;
1402 Json::Value issueJson(Json::objectValue);
1403 issueJson["mpt_issuance_id"] = "0000000000000000000000004D5054494431323334234234";
1404 j[sfAsset] = issueJson;
1405 STParsedJSONObject obj("Test", j);
1406 if (BEAST_EXPECT(obj.object.has_value()))
1407 {
1408 BEAST_EXPECT(obj.object->isFieldPresent(sfAsset));
1409 auto const& issueField = (*obj.object)[sfAsset];
1410 auto const issue = issueField.value().get<MPTIssue>();
1411 BEAST_EXPECT(issue.getMptID().size() == 24);
1412 }
1413 }
1414
1415 // Invalid Issue: missing currency
1416 {
1417 Json::Value j;
1419 issue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1420 j[sfAsset] = issue;
1421 STParsedJSONObject obj("Test", j);
1422 BEAST_EXPECT(!obj.object.has_value());
1423 }
1424
1425 // Invalid Issue: missing issuer
1426 {
1427 Json::Value j;
1429 issue["currency"] = "USD";
1430 j[sfAsset] = issue;
1431 STParsedJSONObject obj("Test", j);
1432 BEAST_EXPECT(!obj.object.has_value());
1433 }
1434
1435 // Invalid Issue: currency too long
1436 {
1437 Json::Value j;
1439 issue["currency"] = "USDD";
1440 issue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1441 j[sfAsset] = issue;
1442 STParsedJSONObject obj("Test", j);
1443 BEAST_EXPECT(!obj.object.has_value());
1444 }
1445
1446 // Invalid Issue: issuer not base58 or hex
1447 {
1448 Json::Value j;
1450 issue["currency"] = "USD";
1451 issue["issuer"] = "notAValidIssuer";
1452 j[sfAsset] = issue;
1453 STParsedJSONObject obj("Test", j);
1454 BEAST_EXPECT(!obj.object.has_value());
1455 }
1456
1457 // Invalid Issue: currency not string
1458 {
1459 Json::Value j;
1461 issue["currency"] = Json::Value(Json::arrayValue);
1462 issue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1463 j[sfAsset] = issue;
1464 STParsedJSONObject obj("Test", j);
1465 BEAST_EXPECT(!obj.object.has_value());
1466 }
1467
1468 // Invalid Issue: issuer not string
1469 {
1470 Json::Value j;
1472 issue["currency"] = "USD";
1473 issue["issuer"] = Json::Value(Json::objectValue);
1474 j[sfAsset] = issue;
1475 STParsedJSONObject obj("Test", j);
1476 BEAST_EXPECT(!obj.object.has_value());
1477 }
1478
1479 // Invalid Issue: not an object
1480 {
1481 Json::Value j;
1482 j[sfAsset] = "notanobject";
1483 STParsedJSONObject obj("Test", j);
1484 BEAST_EXPECT(!obj.object.has_value());
1485 }
1486 }
1487
1488 void
1490 {
1491 testcase("XChainBridge");
1492 // Valid XChainBridge
1493 {
1494 Json::Value j;
1496 Json::Value issuingChainIssue(Json::objectValue);
1497 issuingChainIssue["currency"] = "USD";
1498 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1499 Json::Value lockingChainIssue(Json::objectValue);
1500 lockingChainIssue["currency"] = "EUR";
1501 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1502 bridge["LockingChainIssue"] = lockingChainIssue;
1503 bridge["IssuingChainIssue"] = issuingChainIssue;
1504 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1505 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1506 j[sfXChainBridge] = bridge;
1507 STParsedJSONObject obj("Test", j);
1508 if (BEAST_EXPECT(obj.object.has_value()))
1509 {
1510 BEAST_EXPECT(obj.object->isFieldPresent(sfXChainBridge));
1511 auto const& bridgeField = (*obj.object)[sfXChainBridge];
1512 BEAST_EXPECT(bridgeField->lockingChainIssue().currency.size() == 20);
1513 BEAST_EXPECT(bridgeField->issuingChainIssue().currency.size() == 20);
1514 }
1515 }
1516
1517 // Valid XChainBridge: issues as hex currency
1518 {
1519 Json::Value j;
1521 Json::Value issuingChainIssue(Json::objectValue);
1522 issuingChainIssue["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123";
1523 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1524 Json::Value lockingChainIssue(Json::objectValue);
1525 lockingChainIssue["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123";
1526 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1527 bridge["LockingChainIssue"] = lockingChainIssue;
1528 bridge["IssuingChainIssue"] = issuingChainIssue;
1529 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1530 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1531 j[sfXChainBridge] = bridge;
1532 STParsedJSONObject obj("Test", j);
1533 if (BEAST_EXPECT(obj.object.has_value()))
1534 {
1535 BEAST_EXPECT(obj.object->isFieldPresent(sfXChainBridge));
1536 auto const& bridgeField = (*obj.object)[sfXChainBridge];
1537 BEAST_EXPECT(bridgeField->lockingChainIssue().currency.size() == 20);
1538 BEAST_EXPECT(bridgeField->issuingChainIssue().currency.size() == 20);
1539 }
1540 }
1541
1542 // Invalid XChainBridge: missing LockingChainIssue
1543 {
1544 Json::Value j;
1546 Json::Value issuingChainIssue(Json::objectValue);
1547 issuingChainIssue["currency"] = "USD";
1548 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1549 bridge["IssuingChainIssue"] = issuingChainIssue;
1550 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1551 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1552 j[sfXChainBridge] = bridge;
1553 STParsedJSONObject obj("Test", j);
1554 BEAST_EXPECT(!obj.object.has_value());
1555 }
1556
1557 // Invalid XChainBridge: missing IssuingChainIssue
1558 {
1559 Json::Value j;
1561 Json::Value lockingChainIssue(Json::objectValue);
1562 lockingChainIssue["currency"] = "EUR";
1563 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1564 bridge["LockingChainIssue"] = lockingChainIssue;
1565 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1566 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1567 j[sfXChainBridge] = bridge;
1568 STParsedJSONObject obj("Test", j);
1569 BEAST_EXPECT(!obj.object.has_value());
1570 }
1571
1572 // Invalid XChainBridge: missing LockingChainDoor
1573 {
1574 Json::Value j;
1576 Json::Value issuingChainIssue(Json::objectValue);
1577 issuingChainIssue["currency"] = "USD";
1578 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1579 bridge["IssuingChainIssue"] = issuingChainIssue;
1580 Json::Value lockingChainIssue(Json::objectValue);
1581 lockingChainIssue["currency"] = "EUR";
1582 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1583 bridge["LockingChainIssue"] = lockingChainIssue;
1584 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1585 j[sfXChainBridge] = bridge;
1586 STParsedJSONObject obj("Test", j);
1587 BEAST_EXPECT(!obj.object.has_value());
1588 }
1589
1590 // Invalid XChainBridge: missing IssuingChainDoor
1591 {
1592 Json::Value j;
1594 Json::Value issuingChainIssue(Json::objectValue);
1595 issuingChainIssue["currency"] = "USD";
1596 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1597 bridge["IssuingChainIssue"] = issuingChainIssue;
1598 Json::Value lockingChainIssue(Json::objectValue);
1599 lockingChainIssue["currency"] = "EUR";
1600 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1601 bridge["LockingChainIssue"] = lockingChainIssue;
1602 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1603 j[sfXChainBridge] = bridge;
1604 STParsedJSONObject obj("Test", j);
1605 BEAST_EXPECT(!obj.object.has_value());
1606 }
1607
1608 // Invalid XChainBridge: IssuingChainIssue not an object
1609 {
1610 Json::Value j;
1612 bridge["LockingChainIssue"] = "notanobject";
1613 bridge["IssuingChainIssue"] = "notanobject";
1614 j[sfXChainBridge] = bridge;
1615 STParsedJSONObject obj("Test", j);
1616 BEAST_EXPECT(!obj.object.has_value());
1617 }
1618
1619 // Invalid XChainBridge: IssuingChainIssue missing currency
1620 {
1621 Json::Value j;
1624 asset["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1625 Json::Value lockingChainIssue(Json::objectValue);
1626 lockingChainIssue["currency"] = "EUR";
1627 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1628 bridge["LockingChainIssue"] = lockingChainIssue;
1629 bridge["IssuingChainIssue"] = asset;
1630 j[sfXChainBridge] = bridge;
1631 STParsedJSONObject obj("Test", j);
1632 BEAST_EXPECT(!obj.object.has_value());
1633 }
1634
1635 // Invalid XChainBridge: asset missing issuer
1636 {
1637 Json::Value j;
1640 asset["currency"] = "USD";
1641 Json::Value lockingChainIssue(Json::objectValue);
1642 lockingChainIssue["currency"] = "EUR";
1643 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1644 bridge["LockingChainIssue"] = lockingChainIssue;
1645 bridge["IssuingChainIssue"] = asset;
1646 j[sfXChainBridge] = bridge;
1647 STParsedJSONObject obj("Test", j);
1648 BEAST_EXPECT(!obj.object.has_value());
1649 }
1650
1651 // Invalid XChainBridge: asset issuer not base58
1652 {
1653 Json::Value j;
1656 asset["currency"] = "USD";
1657 asset["issuer"] = "notAValidBase58Account";
1658 Json::Value lockingChainIssue(Json::objectValue);
1659 lockingChainIssue["currency"] = "EUR";
1660 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1661 bridge["LockingChainIssue"] = lockingChainIssue;
1662 bridge["IssuingChainIssue"] = asset;
1663 j[sfXChainBridge] = bridge;
1664 STParsedJSONObject obj("Test", j);
1665 BEAST_EXPECT(!obj.object.has_value());
1666 }
1667
1668 // Invalid XChainBridge: not an object
1669 {
1670 Json::Value j;
1671 j[sfXChainBridge] = "notanobject";
1672 STParsedJSONObject obj("Test", j);
1673 BEAST_EXPECT(!obj.object.has_value());
1674 }
1675 }
1676
1677 void
1679 {
1680 testcase("Number");
1681 // Valid integer value for STNumber
1682 {
1683 Json::Value j;
1684 j[sfNumber] = 12345;
1685 STParsedJSONObject obj("Test", j);
1686 BEAST_EXPECT(obj.object.has_value());
1687 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1688 BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(12345, 0));
1689 }
1690
1691 // Valid uint value for STNumber
1692 {
1693 Json::Value j;
1694 j[sfNumber] = 12345u;
1695 STParsedJSONObject obj("Test", j);
1696 BEAST_EXPECT(obj.object.has_value());
1697 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1698 BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(12345, 0));
1699 }
1700
1701 // Valid string integer value for STNumber
1702 {
1703 Json::Value j;
1704 j[sfNumber] = "67890";
1705 STParsedJSONObject obj("Test", j);
1706 BEAST_EXPECT(obj.object.has_value());
1707 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1708 BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(67890, 0));
1709 }
1710
1711 // Valid negative integer value for STNumber
1712 {
1713 Json::Value j;
1714 j[sfNumber] = -42;
1715 STParsedJSONObject obj("Test", j);
1716 BEAST_EXPECT(obj.object.has_value());
1717 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1718 BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(-42, 0));
1719 }
1720
1721 // Valid string negative integer value for STNumber
1722 {
1723 Json::Value j;
1724 j[sfNumber] = "-123";
1725 STParsedJSONObject obj("Test", j);
1726 BEAST_EXPECT(obj.object.has_value());
1727 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1728 BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(-123, 0));
1729 }
1730
1731 // Valid floating point value for STNumber
1732 {
1733 Json::Value j;
1734 j[sfNumber] = "3.14159";
1735 STParsedJSONObject obj("Test", j);
1736 if (BEAST_EXPECT(obj.object.has_value()))
1737 {
1738 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1739 BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(314159, -5));
1740 }
1741 }
1742
1743 // Invalid string value for STNumber (not a number)
1744 {
1745 Json::Value j;
1746 j[sfNumber] = "notanumber";
1747 STParsedJSONObject obj("Test", j);
1748 BEAST_EXPECT(!obj.object.has_value());
1749 }
1750
1751 // Invalid array value for STNumber
1752 {
1753 Json::Value j;
1754 j[sfNumber] = Json::Value(Json::arrayValue);
1755 STParsedJSONObject obj("Test", j);
1756 BEAST_EXPECT(!obj.object.has_value());
1757 }
1758
1759 // Invalid object value for STNumber
1760 {
1761 Json::Value j;
1762 j[sfNumber] = Json::Value(Json::objectValue);
1763 STParsedJSONObject obj("Test", j);
1764 BEAST_EXPECT(!obj.object.has_value());
1765 }
1766
1767 // Empty string for STNumber (should fail)
1768 {
1769 Json::Value j;
1770 j[sfNumber] = "";
1771 STParsedJSONObject obj("Test", j);
1772 BEAST_EXPECT(!obj.object.has_value());
1773 }
1774 }
1775
1776 void
1778 {
1779 testcase("Object");
1780 // Test with valid object for Object
1781 {
1782 Json::Value j;
1784 objVal[sfTransactionResult] = 1;
1785 j[sfTransactionMetaData] = objVal;
1786 STParsedJSONObject obj("Test", j);
1787 BEAST_EXPECT(obj.object.has_value());
1788 BEAST_EXPECT(obj.object->isFieldPresent(sfTransactionMetaData));
1789 auto const& result = obj.object->peekFieldObject(sfTransactionMetaData);
1790 BEAST_EXPECT(result.getFieldU8(sfTransactionResult) == 1);
1791 }
1792
1793 // Test with non-object value for Object (should fail)
1794 {
1795 Json::Value j;
1796 j[sfTransactionMetaData] = "notanobject";
1797 STParsedJSONObject obj("Test", j);
1798 BEAST_EXPECT(!obj.object.has_value());
1799 }
1800
1801 // Test with array value for Object (should fail)
1802 {
1803 Json::Value j;
1805 arr.append(1);
1806 j[sfTransactionMetaData] = arr;
1807 STParsedJSONObject obj("Test", j);
1808 BEAST_EXPECT(!obj.object.has_value());
1809 }
1810
1811 // Test with null value for Object (should fail)
1812 {
1813 Json::Value j;
1814 j[sfTransactionMetaData] = Json::Value(Json::nullValue);
1815 STParsedJSONObject obj("Test", j);
1816 BEAST_EXPECT(!obj.object.has_value());
1817 }
1818
1819 // Test with max depth (should succeed)
1820 // max depth is 64
1821 {
1822 Json::Value j;
1824 Json::Value* current = &obj;
1825 for (int i = 0; i < 63; ++i)
1826 {
1828 (*current)[sfTransactionMetaData] = next;
1829 current = &((*current)[sfTransactionMetaData]);
1830 }
1831 (*current)[sfTransactionResult.getJsonName()] = 1;
1832 j[sfTransactionMetaData] = obj;
1833 STParsedJSONObject parsed("Test", j);
1834 BEAST_EXPECT(parsed.object.has_value());
1835 BEAST_EXPECT(parsed.object->isFieldPresent(sfTransactionMetaData));
1836 }
1837
1838 // Test with depth exceeding maxDepth (should fail)
1839 {
1840 Json::Value j;
1842 Json::Value* current = &obj;
1843 for (int i = 0; i < 64; ++i)
1844 {
1846 (*current)[sfTransactionMetaData] = next;
1847 current = &((*current)[sfTransactionMetaData]);
1848 }
1849 (*current)[sfTransactionResult.getJsonName()] = 1;
1850 j[sfTransactionMetaData] = obj;
1851 STParsedJSONObject parsed("Test", j);
1852 BEAST_EXPECT(!parsed.object.has_value());
1853 }
1854 }
1855
1856 void
1858 {
1859 testcase("Array");
1860 // Test with valid array for Array
1861 {
1862 Json::Value j;
1865 elem[sfTransactionResult] = 2;
1867 elem2[sfTransactionMetaData] = elem;
1868 arr.append(elem2);
1869 j[sfSignerEntries] = arr;
1870 STParsedJSONObject obj("Test", j);
1871 BEAST_EXPECT(obj.object.has_value());
1872 BEAST_EXPECT(obj.object->isFieldPresent(sfSignerEntries));
1873 auto const& result = obj.object->getFieldArray(sfSignerEntries);
1874 if (BEAST_EXPECT(result.size() == 1))
1875 {
1876 BEAST_EXPECT(result[0].getFName() == sfTransactionMetaData);
1877 BEAST_EXPECT(result[0].getJson(0) == elem);
1878 }
1879 }
1880
1881 // Test with array containing non-object element (should fail)
1882 {
1883 Json::Value j;
1885 arr.append("notanobject");
1886 j[sfSignerEntries] = arr;
1887 STParsedJSONObject obj("Test", j);
1888 BEAST_EXPECT(!obj.object.has_value());
1889 }
1890
1891 // Test with array containing object with invalid field (should fail)
1892 {
1893 Json::Value j;
1896 elem["invalidField"] = 1;
1897 arr.append(elem);
1898 j[sfSignerEntries] = arr;
1899 STParsedJSONObject obj("Test", j);
1900 BEAST_EXPECT(!obj.object.has_value());
1901 }
1902
1903 // Test with array containing object with multiple keys (should fail)
1904 {
1905 Json::Value j;
1908 elem[sfTransactionResult] = 2;
1909 elem[sfNetworkID] = 3;
1910 arr.append(elem);
1911 j[sfSignerEntries] = arr;
1912 STParsedJSONObject obj("Test", j);
1913 BEAST_EXPECT(!obj.object.has_value());
1914 }
1915
1916 // Test with non-array value for Array (should fail)
1917 {
1918 Json::Value j;
1919 j[sfSignerEntries] = "notanarray";
1920 STParsedJSONObject obj("Test", j);
1921 BEAST_EXPECT(!obj.object.has_value());
1922 }
1923
1924 // Test with array containing object with valid field but invalid value
1925 // (should fail)
1926 {
1927 Json::Value j;
1930 elem[sfTransactionResult] = "notanint";
1931 arr.append(elem);
1932 j[sfSignerEntries] = arr;
1933 STParsedJSONObject obj("Test", j);
1934 BEAST_EXPECT(!obj.object.has_value());
1935 }
1936
1937 // Test with empty array for Array (should be valid)
1938 {
1939 Json::Value j;
1941 j[sfSignerEntries] = arr;
1942 STParsedJSONObject obj("Test", j);
1943 BEAST_EXPECT(obj.object.has_value());
1944 BEAST_EXPECT(obj.object->isFieldPresent(sfSignerEntries));
1945 }
1946
1947 // Test with object provided but not object SField
1948 {
1949 Json::Value j;
1952 obj[0u][sfTransactionResult] = 1;
1953 j[sfSignerEntries] = obj;
1954 STParsedJSONObject parsed("Test", j);
1955 BEAST_EXPECT(!parsed.object.has_value());
1956 }
1957
1958 // Test invalid children
1959 {
1960 try
1961 {
1962 /*
1963
1964 STArray/STObject constructs don't really map perfectly to json
1965 arrays/objects.
1966
1967 STObject is an associative container, mapping fields to value,
1968 but an STObject may also have a Field as its name, stored
1969 outside the associative structure. The name is important, so to
1970 maintain fidelity, it will take TWO json objects to represent
1971 them.
1972
1973 */
1974 std::string faulty(
1975 "{\"Template\":[{"
1976 "\"ModifiedNode\":{\"Sequence\":1}, "
1977 "\"DeletedNode\":{\"Sequence\":1}"
1978 "}]}");
1979
1981 Json::Value faultyJson;
1982 bool parsedOK(parseJSONString(faulty, faultyJson));
1983 unexpected(!parsedOK, "failed to parse");
1984 STParsedJSONObject parsed("test", faultyJson);
1985 BEAST_EXPECT(!parsed.object);
1986 }
1987 catch (std::runtime_error& e)
1988 {
1989 std::string what(e.what());
1990 unexpected(what.find("First level children of `Template`") != 0);
1991 }
1992 }
1993 }
1994
1995 void
1997 {
1998 testcase("General Invalid Cases");
1999
2000 {
2001 Json::Value j;
2002 j[sfLedgerEntry] = 1; // not a valid SField for STParsedJSON
2003 }
2004
2005 {
2006 std::string const goodJson(R"({"CloseResolution":19,"Method":250,)"
2007 R"("TransactionResult":"tecFROZEN"})");
2008
2009 Json::Value jv;
2010 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
2011 {
2012 STParsedJSONObject parsed("test", jv);
2013 if (BEAST_EXPECT(parsed.object))
2014 {
2015 std::string const& serialized(to_string(parsed.object->getJson(JsonOptions::none)));
2016 BEAST_EXPECT(serialized == goodJson);
2017 }
2018 }
2019 }
2020
2021 {
2022 std::string const goodJson(R"({"CloseResolution":19,"Method":"250",)"
2023 R"("TransactionResult":"tecFROZEN"})");
2024 std::string const expectedJson(R"({"CloseResolution":19,"Method":250,)"
2025 R"("TransactionResult":"tecFROZEN"})");
2026
2027 Json::Value jv;
2028 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
2029 {
2030 // Integer values are always parsed as int,
2031 // unless they're too big. We want a small uint.
2032 jv["CloseResolution"] = Json::UInt(19);
2033 STParsedJSONObject parsed("test", jv);
2034 if (BEAST_EXPECT(parsed.object))
2035 {
2036 std::string const& serialized(to_string(parsed.object->getJson(JsonOptions::none)));
2037 BEAST_EXPECT(serialized == expectedJson);
2038 }
2039 }
2040 }
2041
2042 {
2043 std::string const goodJson(R"({"CloseResolution":"19","Method":"250",)"
2044 R"("TransactionResult":"tecFROZEN"})");
2045 std::string const expectedJson(R"({"CloseResolution":19,"Method":250,)"
2046 R"("TransactionResult":"tecFROZEN"})");
2047
2048 Json::Value jv;
2049 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
2050 {
2051 // Integer values are always parsed as int,
2052 // unless they're too big. We want a small uint.
2053 jv["CloseResolution"] = Json::UInt(19);
2054 STParsedJSONObject parsed("test", jv);
2055 if (BEAST_EXPECT(parsed.object))
2056 {
2057 std::string const& serialized(to_string(parsed.object->getJson(JsonOptions::none)));
2058 BEAST_EXPECT(serialized == expectedJson);
2059 }
2060 }
2061 }
2062
2063 {
2064 std::string const json(R"({"CloseResolution":19,"Method":250,)"
2065 R"("TransactionResult":"terQUEUED"})");
2066
2067 Json::Value jv;
2068 if (BEAST_EXPECT(parseJSONString(json, jv)))
2069 {
2070 STParsedJSONObject parsed("test", jv);
2071 BEAST_EXPECT(!parsed.object);
2072 BEAST_EXPECT(parsed.error);
2073 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2074 BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.TransactionResult' is out of range.");
2075 }
2076 }
2077
2078 {
2079 std::string const json(R"({"CloseResolution":19,"Method":"pony",)"
2080 R"("TransactionResult":"tesSUCCESS"})");
2081
2082 Json::Value jv;
2083 if (BEAST_EXPECT(parseJSONString(json, jv)))
2084 {
2085 STParsedJSONObject parsed("test", jv);
2086 BEAST_EXPECT(!parsed.object);
2087 BEAST_EXPECT(parsed.error);
2088 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2089 BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.Method' has bad type.");
2090 }
2091 }
2092
2093 {
2094 std::string const json(R"({"CloseResolution":19,"Method":3294967296,)"
2095 R"("TransactionResult":"tesSUCCESS"})");
2096
2097 Json::Value jv;
2098 if (BEAST_EXPECT(parseJSONString(json, jv)))
2099 {
2100 STParsedJSONObject parsed("test", jv);
2101 BEAST_EXPECT(!parsed.object);
2102 BEAST_EXPECT(parsed.error);
2103 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2104 BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.Method' is out of range.");
2105 }
2106 }
2107
2108 {
2109 std::string const json(R"({"CloseResolution":-10,"Method":42,)"
2110 R"("TransactionResult":"tesSUCCESS"})");
2111
2112 Json::Value jv;
2113 if (BEAST_EXPECT(parseJSONString(json, jv)))
2114 {
2115 STParsedJSONObject parsed("test", jv);
2116 BEAST_EXPECT(!parsed.object);
2117 BEAST_EXPECT(parsed.error);
2118 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2119 BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.CloseResolution' is out of range.");
2120 }
2121 }
2122
2123 {
2124 std::string const json(R"({"CloseResolution":19,"Method":3.141592653,)"
2125 R"("TransactionResult":"tesSUCCESS"})");
2126
2127 Json::Value jv;
2128 if (BEAST_EXPECT(parseJSONString(json, jv)))
2129 {
2130 STParsedJSONObject parsed("test", jv);
2131 BEAST_EXPECT(!parsed.object);
2132 BEAST_EXPECT(parsed.error);
2133 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2134 BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.Method' has bad type.");
2135 }
2136 }
2137
2138 {
2139 std::string const goodJson(R"({"CloseResolution":19,"Method":250,)"
2140 R"("TransferFee":"65535"})");
2141 std::string const expectedJson(R"({"CloseResolution":19,"Method":250,)"
2142 R"("TransferFee":65535})");
2143
2144 Json::Value jv;
2145 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
2146 {
2147 STParsedJSONObject parsed("test", jv);
2148 if (BEAST_EXPECT(parsed.object))
2149 {
2150 std::string const& serialized(to_string(parsed.object->getJson(JsonOptions::none)));
2151 BEAST_EXPECT(serialized == expectedJson);
2152 }
2153 }
2154 }
2155
2156 {
2157 std::string const json(R"({"CloseResolution":19,"Method":250,)"
2158 R"("TransferFee":"65536"})");
2159
2160 Json::Value jv;
2161 if (BEAST_EXPECT(parseJSONString(json, jv)))
2162 {
2163 STParsedJSONObject parsed("test", jv);
2164 BEAST_EXPECT(!parsed.object);
2165 BEAST_EXPECT(parsed.error);
2166 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2167 BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.TransferFee' has invalid data.");
2168 }
2169 }
2170
2171 {
2172 std::string const json(R"({"CloseResolution":19,"Method":250,)"
2173 R"("TransferFee":"Payment"})");
2174
2175 Json::Value jv;
2176 if (BEAST_EXPECT(parseJSONString(json, jv)))
2177 {
2178 STParsedJSONObject parsed("test", jv);
2179 BEAST_EXPECT(!parsed.object);
2180 BEAST_EXPECT(parsed.error);
2181 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2182 BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.TransferFee' has invalid data.");
2183 }
2184 }
2185
2186 {
2187 std::string const json(R"({"CloseResolution":19,"Method":250,)"
2188 R"("TransferFee":true})");
2189
2190 Json::Value jv;
2191 if (BEAST_EXPECT(parseJSONString(json, jv)))
2192 {
2193 STParsedJSONObject parsed("test", jv);
2194 BEAST_EXPECT(!parsed.object);
2195 BEAST_EXPECT(parsed.error);
2196 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2197 BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.TransferFee' has bad type.");
2198 }
2199 }
2200 }
2201
2202 void
2203 run() override
2204 {
2205 // Instantiate a jtx::Env so debugLog writes are exercised.
2206 test::jtx::Env env(*this);
2207 testUInt8();
2208 testUInt16();
2209 testUInt32();
2210 testUInt64();
2211 testUInt128();
2212 testUInt160();
2213 testUInt192();
2214 testUInt256();
2215 testInt32();
2216 testBlob();
2217 testVector256();
2218 testAccount();
2219 testCurrency();
2220 testAmount();
2221 testPathSet();
2222 testIssue();
2224 testNumber();
2225 testObject();
2226 testArray();
2227 testEdgeCases();
2228 }
2229};
2230
2231BEAST_DEFINE_TESTSUITE(STParsedJSON, protocol, xrpl);
2232
2233} // namespace xrpl
T all_of(T... args)
Unserialize a JSON document into a Value.
Definition json_reader.h:17
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Represents a JSON value.
Definition json_value.h:130
Value & append(Value const &value)
Append value to array at the end.
bool isObject() const
A testsuite class.
Definition suite.h:51
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:482
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:147
A currency issued by an account.
Definition Issue.h:13
Number is a floating point type that can represent a wide range of values.
Definition Number.h:207
Holds the serialized result of parsing an input JSON object.
std::optional< STObject > object
The STObject if the parse was successful.
Json::Value error
On failure, an appropriate set of error values.
void run() override
Runs the suite.
bool parseJSONString(std::string const &json, Json::Value &to)
Integers of any length that is a multiple of 32-bits.
Definition base_uint.h:66
A transaction testing environment.
Definition Env.h:119
T find(T... args)
@ nullValue
'null' value
Definition json_value.h:19
@ arrayValue
array value (ordered list)
Definition json_value.h:25
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:26
unsigned int UInt
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:597
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
@ current
This was a new validation and was added.
T to_string(T... args)
T what(T... args)