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