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("Int32");
743 {
744 Json::Value j;
745 int const minInt32 = -2147483648;
746 j[sfDummyInt32] = minInt32;
747 STParsedJSONObject obj("Test", j);
748 BEAST_EXPECT(obj.object.has_value());
749 if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32)))
750 BEAST_EXPECT(obj.object->getFieldI32(sfDummyInt32) == minInt32);
751 }
752
753 // max value
754 {
755 Json::Value j;
756 int const maxInt32 = 2147483647;
757 j[sfDummyInt32] = maxInt32;
758 STParsedJSONObject obj("Test", j);
759 BEAST_EXPECT(obj.object.has_value());
760 if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32)))
761 BEAST_EXPECT(obj.object->getFieldI32(sfDummyInt32) == maxInt32);
762 }
763
764 // max uint value
765 {
766 Json::Value j;
767 unsigned int const maxUInt32 = 2147483647u;
768 j[sfDummyInt32] = maxUInt32;
769 STParsedJSONObject obj("Test", j);
770 BEAST_EXPECT(obj.object.has_value());
771 if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32)))
772 BEAST_EXPECT(
773 obj.object->getFieldI32(sfDummyInt32) ==
774 static_cast<int32_t>(maxUInt32));
775 }
776
777 // Test with string value
778 {
779 Json::Value j;
780 j[sfDummyInt32] = "2147483647";
781 STParsedJSONObject obj("Test", j);
782 BEAST_EXPECT(obj.object.has_value());
783 if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32)))
784 BEAST_EXPECT(
785 obj.object->getFieldI32(sfDummyInt32) == 2147483647u);
786 }
787
788 // Test with string negative value
789 {
790 Json::Value j;
791 int value = -2147483648;
792 j[sfDummyInt32] = std::to_string(value);
793 STParsedJSONObject obj("Test", j);
794 BEAST_EXPECT(obj.object.has_value());
795 if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32)))
796 BEAST_EXPECT(obj.object->getFieldI32(sfDummyInt32) == value);
797 }
798
799 // Test out of range value for int32 (negative)
800 {
801 Json::Value j;
802 j[sfDummyInt32] = "-2147483649";
803 STParsedJSONObject obj("Test", j);
804 BEAST_EXPECT(!obj.object.has_value());
805 }
806
807 // Test out of range value for int32 (positive)
808 {
809 Json::Value j;
810 j[sfDummyInt32] = 2147483648u;
811 STParsedJSONObject obj("Test", j);
812 BEAST_EXPECT(!obj.object.has_value());
813 }
814
815 // Test string value out of range
816 {
817 Json::Value j;
818 j[sfDummyInt32] = "2147483648";
819 STParsedJSONObject obj("Test", j);
820 BEAST_EXPECT(!obj.object.has_value());
821 }
822
823 // Test bad_type (arrayValue)
824 {
825 Json::Value j;
826 j[sfDummyInt32] = Json::Value(Json::arrayValue);
827 STParsedJSONObject obj("Test", j);
828 BEAST_EXPECT(!obj.object.has_value());
829 }
830
831 // Test bad_type (objectValue)
832 {
833 Json::Value j;
834 j[sfDummyInt32] = Json::Value(Json::objectValue);
835 STParsedJSONObject obj("Test", j);
836 BEAST_EXPECT(!obj.object.has_value());
837 }
838 }
839
840 void
842 {
843 testcase("Blob");
844 // Test with valid hex string for blob
845 {
846 Json::Value j;
847 j[sfPublicKey] = "DEADBEEF";
848 STParsedJSONObject obj("Test", j);
849 BEAST_EXPECT(obj.object.has_value());
850 BEAST_EXPECT(obj.object->isFieldPresent(sfPublicKey));
851 auto const& blob = obj.object->getFieldVL(sfPublicKey);
852 BEAST_EXPECT(blob.size() == 4);
853 BEAST_EXPECT(blob[0] == 0xDE);
854 BEAST_EXPECT(blob[1] == 0xAD);
855 BEAST_EXPECT(blob[2] == 0xBE);
856 BEAST_EXPECT(blob[3] == 0xEF);
857 }
858
859 // Test empty string for blob (should be valid, size 0)
860 {
861 Json::Value j;
862 j[sfPublicKey] = "";
863 STParsedJSONObject obj("Test", j);
864 BEAST_EXPECT(obj.object.has_value());
865 BEAST_EXPECT(obj.object->isFieldPresent(sfPublicKey));
866 auto const& blob = obj.object->getFieldVL(sfPublicKey);
867 BEAST_EXPECT(blob.size() == 0);
868 }
869
870 // Test lowercase hex string for blob
871 {
872 Json::Value j;
873 j[sfPublicKey] = "deadbeef";
874 STParsedJSONObject obj("Test", j);
875 BEAST_EXPECT(obj.object.has_value());
876 BEAST_EXPECT(obj.object->isFieldPresent(sfPublicKey));
877 auto const& blob = obj.object->getFieldVL(sfPublicKey);
878 BEAST_EXPECT(blob.size() == 4);
879 BEAST_EXPECT(blob[0] == 0xDE);
880 BEAST_EXPECT(blob[1] == 0xAD);
881 BEAST_EXPECT(blob[2] == 0xBE);
882 BEAST_EXPECT(blob[3] == 0xEF);
883 }
884
885 // Test non-hex string for blob (should fail)
886 {
887 Json::Value j;
888 j[sfPublicKey] = "XYZ123";
889 STParsedJSONObject obj("Test", j);
890 BEAST_EXPECT(!obj.object.has_value());
891 }
892
893 // Test array value for blob (should fail)
894 {
895 Json::Value j;
896 j[sfPublicKey] = Json::Value(Json::arrayValue);
897 STParsedJSONObject obj("Test", j);
898 BEAST_EXPECT(!obj.object.has_value());
899 }
900
901 // Test object value for blob (should fail)
902 {
903 Json::Value j;
904 j[sfPublicKey] = Json::Value(Json::objectValue);
905 STParsedJSONObject obj("Test", j);
906 BEAST_EXPECT(!obj.object.has_value());
907 }
908 }
909
910 void
912 {
913 testcase("Vector256");
914 // Test with valid array of hex strings for Vector256
915 {
916 Json::Value j;
918 arr.append(
919 "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD"
920 "EF");
921 arr.append(
922 "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA98765432"
923 "10");
924 j[sfHashes] = arr;
925 STParsedJSONObject obj("Test", j);
926 BEAST_EXPECT(obj.object.has_value());
927 BEAST_EXPECT(obj.object->isFieldPresent(sfHashes));
928 auto const& vec = obj.object->getFieldV256(sfHashes);
929 BEAST_EXPECT(vec.size() == 2);
930 BEAST_EXPECT(to_string(vec[0]) == arr[0u].asString());
931 BEAST_EXPECT(to_string(vec[1]) == arr[1u].asString());
932 }
933 // Test empty array for Vector256 (should be valid, size 0)
934 {
935 Json::Value j;
937 j[sfHashes] = arr;
938 STParsedJSONObject obj("Test", j);
939 BEAST_EXPECT(obj.object.has_value());
940 BEAST_EXPECT(obj.object->isFieldPresent(sfHashes));
941 auto const& vec = obj.object->getFieldV256(sfHashes);
942 BEAST_EXPECT(vec.size() == 0);
943 }
944
945 // Test array with invalid hex string (should fail)
946 {
947 Json::Value j;
949 arr.append("nothexstring");
950 j[sfHashes] = arr;
951 STParsedJSONObject obj("Test", j);
952 BEAST_EXPECT(!obj.object.has_value());
953 }
954
955 // Test array with string of wrong length (should fail)
956 {
957 Json::Value j;
959 arr.append("0123456789ABCDEF"); // too short for uint256
960 j[sfHashes] = arr;
961 STParsedJSONObject obj("Test", j);
962 BEAST_EXPECT(!obj.object.has_value());
963 }
964
965 // Test array with non-string element (should fail)
966 {
967 Json::Value j;
969 arr.append(12345);
970 j[sfHashes] = arr;
971 STParsedJSONObject obj("Test", j);
972 BEAST_EXPECT(!obj.object.has_value());
973 }
974
975 // Test non-array value for Vector256 (should fail)
976 {
977 Json::Value j;
978 j[sfHashes] = "notanarray";
979 STParsedJSONObject obj("Test", j);
980 BEAST_EXPECT(!obj.object.has_value());
981 }
982
983 // Test array with object element (should fail)
984 {
985 Json::Value j;
988 objElem["foo"] = "bar";
989 arr.append(objElem);
990 j[sfHashes] = arr;
991 STParsedJSONObject obj("Test", j);
992 BEAST_EXPECT(!obj.object.has_value());
993 }
994 }
995
996 void
998 {
999 testcase("Account");
1000 // Test with valid base58 string for AccountID
1001 {
1002 Json::Value j;
1003 j[sfAccount] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1004 STParsedJSONObject obj("Test", j);
1005 BEAST_EXPECT(obj.object.has_value());
1006 BEAST_EXPECT(obj.object->isFieldPresent(sfAccount));
1007 auto const& acct = obj.object->getAccountID(sfAccount);
1008 BEAST_EXPECT(acct.size() == 20);
1009 BEAST_EXPECT(
1010 toBase58(acct) == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
1011 }
1012
1013 // Valid hex string for AccountID
1014 {
1015 Json::Value j;
1016 j[sfAccount] = "000102030405060708090A0B0C0D0E0F10111213";
1017 STParsedJSONObject obj("Test", j);
1018 BEAST_EXPECT(obj.object.has_value());
1019 BEAST_EXPECT(obj.object->isFieldPresent(sfAccount));
1020 auto const& acct = obj.object->getAccountID(sfAccount);
1021 BEAST_EXPECT(acct.size() == 20);
1022 }
1023
1024 // Invalid base58 string for AccountID
1025 {
1026 Json::Value j;
1027 j[sfAccount] = "notAValidBase58Account";
1028 STParsedJSONObject obj("Test", j);
1029 BEAST_EXPECT(!obj.object.has_value());
1030 }
1031
1032 // Invalid hex string for AccountID (too short)
1033 {
1034 Json::Value j;
1035 j[sfAccount] = "001122334455";
1036 STParsedJSONObject obj("Test", j);
1037 BEAST_EXPECT(!obj.object.has_value());
1038 }
1039
1040 // Invalid hex string for AccountID (too long)
1041 {
1042 Json::Value j;
1043 j[sfAccount] = "000102030405060708090A0B0C0D0E0F101112131415";
1044 STParsedJSONObject obj("Test", j);
1045 BEAST_EXPECT(!obj.object.has_value());
1046 }
1047
1048 // Invalid hex string for AccountID (bad chars)
1049 {
1050 Json::Value j;
1051 j[sfAccount] = "000102030405060708090A0B0C0D0E0F1011121G";
1052 STParsedJSONObject obj("Test", j);
1053 BEAST_EXPECT(!obj.object.has_value());
1054 }
1055
1056 // Empty string for AccountID (should fail)
1057 {
1058 Json::Value j;
1059 j[sfAccount] = "";
1060 STParsedJSONObject obj("Test", j);
1061 BEAST_EXPECT(!obj.object.has_value());
1062 }
1063
1064 // Array value for AccountID (should fail)
1065 {
1066 Json::Value j;
1067 j[sfAccount] = Json::Value(Json::arrayValue);
1068 STParsedJSONObject obj("Test", j);
1069 BEAST_EXPECT(!obj.object.has_value());
1070 }
1071
1072 // Object value for AccountID (should fail)
1073 {
1074 Json::Value j;
1075 j[sfAccount] = Json::Value(Json::objectValue);
1076 STParsedJSONObject obj("Test", j);
1077 BEAST_EXPECT(!obj.object.has_value());
1078 }
1079 }
1080
1081 void
1083 {
1084 testcase("Currency");
1085 // Test with valid ISO code for currency
1086 {
1087 Json::Value j;
1088 j[sfBaseAsset] = "USD";
1089 STParsedJSONObject obj("Test", j);
1090 BEAST_EXPECT(obj.object.has_value());
1091 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1092 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1093 BEAST_EXPECT(curr.currency().size() == 20);
1094 }
1095
1096 // Valid ISO code
1097 {
1098 Json::Value j;
1099 j[sfBaseAsset] = "EUR";
1100 STParsedJSONObject obj("Test", j);
1101 BEAST_EXPECT(obj.object.has_value());
1102 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1103 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1104 BEAST_EXPECT(curr.currency().size() == 20);
1105 }
1106
1107 // Valid hex string for currency
1108 {
1109 Json::Value j;
1110 j[sfBaseAsset] = "0123456789ABCDEF01230123456789ABCDEF0123";
1111 STParsedJSONObject obj("Test", j);
1112 if (BEAST_EXPECT(obj.object.has_value()))
1113 {
1114 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1115 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1116 BEAST_EXPECT(curr.currency().size() == 20);
1117 }
1118 }
1119
1120 // Invalid ISO code (too long)
1121 {
1122 Json::Value j;
1123 j[sfBaseAsset] = "USDD";
1124 STParsedJSONObject obj("Test", j);
1125 BEAST_EXPECT(!obj.object.has_value());
1126 }
1127
1128 // lowercase ISO code
1129 {
1130 Json::Value j;
1131 j[sfBaseAsset] = "usd";
1132 STParsedJSONObject obj("Test", j);
1133 BEAST_EXPECT(obj.object.has_value());
1134 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1135 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1136 BEAST_EXPECT(curr.currency().size() == 20);
1137 }
1138
1139 // Invalid hex string (too short)
1140 {
1141 Json::Value j;
1142 j[sfBaseAsset] = "0123456789AB";
1143 STParsedJSONObject obj("Test", j);
1144 BEAST_EXPECT(!obj.object.has_value());
1145 }
1146
1147 // Invalid hex string (too long)
1148 {
1149 Json::Value j;
1150 j[sfBaseAsset] = "0123456789ABCDEF0123456789";
1151 STParsedJSONObject obj("Test", j);
1152 BEAST_EXPECT(!obj.object.has_value());
1153 }
1154
1155 // Empty string for currency (should fail)
1156 {
1157 Json::Value j;
1158 j[sfBaseAsset] = "";
1159 STParsedJSONObject obj("Test", j);
1160 BEAST_EXPECT(obj.object.has_value());
1161 BEAST_EXPECT(obj.object->isFieldPresent(sfBaseAsset));
1162 auto const& curr = obj.object->getFieldCurrency(sfBaseAsset);
1163 BEAST_EXPECT(curr.currency().size() == 20);
1164 }
1165
1166 // Array value for currency (should fail)
1167 {
1168 Json::Value j;
1169 j[sfBaseAsset] = Json::Value(Json::arrayValue);
1170 STParsedJSONObject obj("Test", j);
1171 BEAST_EXPECT(!obj.object.has_value());
1172 }
1173
1174 // Object value for currency (should fail)
1175 {
1176 Json::Value j;
1177 j[sfBaseAsset] = Json::Value(Json::objectValue);
1178 STParsedJSONObject obj("Test", j);
1179 BEAST_EXPECT(!obj.object.has_value());
1180 }
1181 }
1182
1183 void
1185 {
1186 testcase("Amount");
1187 // Test with string value for Amount
1188 {
1189 Json::Value j;
1190 j[sfAmount] = "100000000000000000";
1191 STParsedJSONObject obj("Test", j);
1192 BEAST_EXPECT(obj.object.has_value());
1193 BEAST_EXPECT(obj.object->isFieldPresent(sfAmount));
1194 BEAST_EXPECT(
1195 obj.object->getFieldAmount(sfAmount) ==
1196 STAmount(100000000000000000ull));
1197 }
1198
1199 // Test with int value for Amount
1200 {
1201 Json::Value j;
1202 j[sfAmount] = 4294967295u;
1203 STParsedJSONObject obj("Test", j);
1204 BEAST_EXPECT(obj.object.has_value());
1205 BEAST_EXPECT(obj.object->isFieldPresent(sfAmount));
1206 BEAST_EXPECT(
1207 obj.object->getFieldAmount(sfAmount) == STAmount(4294967295u));
1208 }
1209
1210 // Test with decimal string for Amount (should fail)
1211 {
1212 Json::Value j;
1213 j[sfAmount] = "123.45";
1214 STParsedJSONObject obj("Test", j);
1215 BEAST_EXPECT(!obj.object.has_value());
1216 }
1217
1218 // Test with empty string for Amount (should fail)
1219 {
1220 Json::Value j;
1221 j[sfAmount] = "";
1222 STParsedJSONObject obj("Test", j);
1223 BEAST_EXPECT(!obj.object.has_value());
1224 }
1225
1226 // Test with non-numeric string for Amount (should fail)
1227 {
1228 Json::Value j;
1229 j[sfAmount] = "notanumber";
1230 STParsedJSONObject obj("Test", j);
1231 BEAST_EXPECT(!obj.object.has_value());
1232 }
1233
1234 // Test with object value for Amount (should fail)
1235 {
1236 Json::Value j;
1237 j[sfAmount] = Json::Value(Json::objectValue);
1238 STParsedJSONObject obj("Test", j);
1239 BEAST_EXPECT(!obj.object.has_value());
1240 }
1241 }
1242
1243 void
1245 {
1246 testcase("PathSet");
1247 // Valid test: single path with single element
1248 {
1249 Json::Value j;
1252 elem["account"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1253 elem["currency"] = "USD";
1254 elem["issuer"] = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe";
1255 path.append(elem);
1257 pathset.append(path);
1258 j[sfPaths] = pathset;
1259 STParsedJSONObject obj("Test", j);
1260 if (BEAST_EXPECT(obj.object.has_value()))
1261 {
1262 BEAST_EXPECT(obj.object->isFieldPresent(sfPaths));
1263 auto const& ps = obj.object->getFieldPathSet(sfPaths);
1264 BEAST_EXPECT(!ps.empty());
1265 BEAST_EXPECT(ps.size() == 1);
1266 BEAST_EXPECT(ps[0].size() == 1);
1267 BEAST_EXPECT(
1268 ps[0][0].getAccountID() ==
1269 parseBase58<AccountID>(
1270 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"));
1271 BEAST_EXPECT(to_string(ps[0][0].getCurrency()) == "USD");
1272 BEAST_EXPECT(
1273 ps[0][0].getIssuerID() ==
1274 parseBase58<AccountID>(
1275 "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"));
1276 }
1277 }
1278
1279 // Valid test: non-standard currency code
1280 {
1281 Json::Value j;
1284 elem["account"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1285 elem["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123";
1286 elem["issuer"] = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe";
1287 path.append(elem);
1289 pathset.append(path);
1290 j[sfPaths] = pathset;
1291 STParsedJSONObject obj("Test", j);
1292 BEAST_EXPECT(obj.object.has_value());
1293 BEAST_EXPECT(obj.object->isFieldPresent(sfPaths));
1294 auto const& ps = obj.object->getFieldPathSet(sfPaths);
1295 BEAST_EXPECT(!ps.empty());
1296 }
1297
1298 // Test with non-array value for PathSet (should fail)
1299 {
1300 Json::Value j;
1301 j[sfPaths] = "notanarray";
1302 STParsedJSONObject obj("Test", j);
1303 BEAST_EXPECT(!obj.object.has_value());
1304 }
1305
1306 // Test with array containing non-array element (should fail)
1307 {
1308 Json::Value j;
1310 pathset.append("notanarray");
1311 j[sfPaths] = pathset;
1312 STParsedJSONObject obj("Test", j);
1313 BEAST_EXPECT(!obj.object.has_value());
1314 }
1315
1316 // Test with array containing array with non-object element (should
1317 // fail)
1318 {
1319 Json::Value j;
1321 path.append("notanobject");
1323 pathset.append(path);
1324 j[sfPaths] = pathset;
1325 STParsedJSONObject obj("Test", j);
1326 BEAST_EXPECT(!obj.object.has_value());
1327 }
1328
1329 // Test with array containing array with object missing required keys
1330 // (should fail)
1331 {
1332 Json::Value j;
1335 elem["foo"] = "bar"; // not a valid path element key
1336 path.append(elem);
1338 pathset.append(path);
1339 j[sfPaths] = pathset;
1340 STParsedJSONObject obj("Test", j);
1341 BEAST_EXPECT(!obj.object.has_value());
1342 }
1343
1344 // Test with array containing array with object with invalid account
1345 // value (should fail)
1346 {
1347 Json::Value j;
1350 elem["account"] = "notAValidBase58Account";
1351 path.append(elem);
1353 pathset.append(path);
1354 j[sfPaths] = pathset;
1355 STParsedJSONObject obj("Test", j);
1356 BEAST_EXPECT(!obj.object.has_value());
1357 }
1358
1359 // Test with account not string (should fail)
1360 {
1361 Json::Value j;
1364 elem["account"] = 12345;
1365 path.append(elem);
1367 pathset.append(path);
1368 j[sfPaths] = pathset;
1369 STParsedJSONObject obj("Test", j);
1370 BEAST_EXPECT(!obj.object.has_value());
1371 }
1372
1373 // Test with currency not string (should fail)
1374 {
1375 Json::Value j;
1378 elem["currency"] = 12345;
1379 path.append(elem);
1381 pathset.append(path);
1382 j[sfPaths] = pathset;
1383 STParsedJSONObject obj("Test", j);
1384 BEAST_EXPECT(!obj.object.has_value());
1385 }
1386
1387 // Test with non-standard currency not hex (should fail)
1388 {
1389 Json::Value j;
1392 elem["currency"] = "notAValidCurrency";
1393 path.append(elem);
1395 pathset.append(path);
1396 j[sfPaths] = pathset;
1397 STParsedJSONObject obj("Test", j);
1398 BEAST_EXPECT(!obj.object.has_value());
1399 }
1400
1401 // Test with issuer not string (should fail)
1402 {
1403 Json::Value j;
1406 elem["issuer"] = 12345;
1407 path.append(elem);
1409 pathset.append(path);
1410 j[sfPaths] = pathset;
1411 STParsedJSONObject obj("Test", j);
1412 BEAST_EXPECT(!obj.object.has_value());
1413 }
1414
1415 // Test with issuer not base58 (should fail)
1416 {
1417 Json::Value j;
1420 elem["issuer"] = "notAValidBase58Account";
1421 path.append(elem);
1423 pathset.append(path);
1424 j[sfPaths] = pathset;
1425 STParsedJSONObject obj("Test", j);
1426 BEAST_EXPECT(!obj.object.has_value());
1427 }
1428 }
1429
1430 void
1432 {
1433 testcase("Issue");
1434 // Valid Issue: currency and issuer as base58
1435 {
1436 Json::Value j;
1437 Json::Value issueJson(Json::objectValue);
1438 issueJson["currency"] = "USD";
1439 issueJson["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1440 j[sfAsset] = issueJson;
1441 STParsedJSONObject obj("Test", j);
1442 if (BEAST_EXPECT(obj.object.has_value()))
1443 {
1444 BEAST_EXPECT(obj.object->isFieldPresent(sfAsset));
1445 auto const& issueField = (*obj.object)[sfAsset];
1446 auto const issue = issueField.value().get<Issue>();
1447 BEAST_EXPECT(issue.currency.size() == 20);
1448 BEAST_EXPECT(to_string(issue.currency) == "USD");
1449 BEAST_EXPECT(issue.account.size() == 20);
1450 BEAST_EXPECT(
1451 issue.account ==
1452 parseBase58<AccountID>(
1453 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"));
1454 }
1455 }
1456
1457 // Valid Issue: currency as hex
1458 {
1459 Json::Value j;
1460 Json::Value issueJson(Json::objectValue);
1461 issueJson["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123";
1462 issueJson["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1463 j[sfAsset] = issueJson;
1464 STParsedJSONObject obj("Test", j);
1465 if (BEAST_EXPECT(obj.object.has_value()))
1466 {
1467 BEAST_EXPECT(obj.object->isFieldPresent(sfAsset));
1468 auto const& issueField = (*obj.object)[sfAsset];
1469 auto const issue = issueField.value().get<Issue>();
1470 BEAST_EXPECT(issue.currency.size() == 20);
1471 BEAST_EXPECT(issue.account.size() == 20);
1472 }
1473 }
1474
1475 // Valid Issue: MPTID
1476 {
1477 Json::Value j;
1478 Json::Value issueJson(Json::objectValue);
1479 issueJson["mpt_issuance_id"] =
1480 "0000000000000000000000004D5054494431323334234234";
1481 j[sfAsset] = issueJson;
1482 STParsedJSONObject obj("Test", j);
1483 if (BEAST_EXPECT(obj.object.has_value()))
1484 {
1485 BEAST_EXPECT(obj.object->isFieldPresent(sfAsset));
1486 auto const& issueField = (*obj.object)[sfAsset];
1487 auto const issue = issueField.value().get<MPTIssue>();
1488 BEAST_EXPECT(issue.getMptID().size() == 24);
1489 }
1490 }
1491
1492 // Invalid Issue: missing currency
1493 {
1494 Json::Value j;
1496 issue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1497 j[sfAsset] = issue;
1498 STParsedJSONObject obj("Test", j);
1499 BEAST_EXPECT(!obj.object.has_value());
1500 }
1501
1502 // Invalid Issue: missing issuer
1503 {
1504 Json::Value j;
1506 issue["currency"] = "USD";
1507 j[sfAsset] = issue;
1508 STParsedJSONObject obj("Test", j);
1509 BEAST_EXPECT(!obj.object.has_value());
1510 }
1511
1512 // Invalid Issue: currency too long
1513 {
1514 Json::Value j;
1516 issue["currency"] = "USDD";
1517 issue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1518 j[sfAsset] = issue;
1519 STParsedJSONObject obj("Test", j);
1520 BEAST_EXPECT(!obj.object.has_value());
1521 }
1522
1523 // Invalid Issue: issuer not base58 or hex
1524 {
1525 Json::Value j;
1527 issue["currency"] = "USD";
1528 issue["issuer"] = "notAValidIssuer";
1529 j[sfAsset] = issue;
1530 STParsedJSONObject obj("Test", j);
1531 BEAST_EXPECT(!obj.object.has_value());
1532 }
1533
1534 // Invalid Issue: currency not string
1535 {
1536 Json::Value j;
1538 issue["currency"] = Json::Value(Json::arrayValue);
1539 issue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1540 j[sfAsset] = issue;
1541 STParsedJSONObject obj("Test", j);
1542 BEAST_EXPECT(!obj.object.has_value());
1543 }
1544
1545 // Invalid Issue: issuer not string
1546 {
1547 Json::Value j;
1549 issue["currency"] = "USD";
1550 issue["issuer"] = Json::Value(Json::objectValue);
1551 j[sfAsset] = issue;
1552 STParsedJSONObject obj("Test", j);
1553 BEAST_EXPECT(!obj.object.has_value());
1554 }
1555
1556 // Invalid Issue: not an object
1557 {
1558 Json::Value j;
1559 j[sfAsset] = "notanobject";
1560 STParsedJSONObject obj("Test", j);
1561 BEAST_EXPECT(!obj.object.has_value());
1562 }
1563 }
1564
1565 void
1567 {
1568 testcase("XChainBridge");
1569 // Valid XChainBridge
1570 {
1571 Json::Value j;
1573 Json::Value issuingChainIssue(Json::objectValue);
1574 issuingChainIssue["currency"] = "USD";
1575 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1576 Json::Value lockingChainIssue(Json::objectValue);
1577 lockingChainIssue["currency"] = "EUR";
1578 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1579 bridge["LockingChainIssue"] = lockingChainIssue;
1580 bridge["IssuingChainIssue"] = issuingChainIssue;
1581 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1582 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1583 j[sfXChainBridge] = bridge;
1584 STParsedJSONObject obj("Test", j);
1585 if (BEAST_EXPECT(obj.object.has_value()))
1586 {
1587 BEAST_EXPECT(obj.object->isFieldPresent(sfXChainBridge));
1588 auto const& bridgeField = (*obj.object)[sfXChainBridge];
1589 BEAST_EXPECT(
1590 bridgeField->lockingChainIssue().currency.size() == 20);
1591 BEAST_EXPECT(
1592 bridgeField->issuingChainIssue().currency.size() == 20);
1593 }
1594 }
1595
1596 // Valid XChainBridge: issues as hex currency
1597 {
1598 Json::Value j;
1600 Json::Value issuingChainIssue(Json::objectValue);
1601 issuingChainIssue["currency"] =
1602 "0123456789ABCDEF01230123456789ABCDEF0123";
1603 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1604 Json::Value lockingChainIssue(Json::objectValue);
1605 lockingChainIssue["currency"] =
1606 "0123456789ABCDEF01230123456789ABCDEF0123";
1607 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1608 bridge["LockingChainIssue"] = lockingChainIssue;
1609 bridge["IssuingChainIssue"] = issuingChainIssue;
1610 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1611 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1612 j[sfXChainBridge] = bridge;
1613 STParsedJSONObject obj("Test", j);
1614 if (BEAST_EXPECT(obj.object.has_value()))
1615 {
1616 BEAST_EXPECT(obj.object->isFieldPresent(sfXChainBridge));
1617 auto const& bridgeField = (*obj.object)[sfXChainBridge];
1618 BEAST_EXPECT(
1619 bridgeField->lockingChainIssue().currency.size() == 20);
1620 BEAST_EXPECT(
1621 bridgeField->issuingChainIssue().currency.size() == 20);
1622 }
1623 }
1624
1625 // Invalid XChainBridge: missing LockingChainIssue
1626 {
1627 Json::Value j;
1629 Json::Value issuingChainIssue(Json::objectValue);
1630 issuingChainIssue["currency"] = "USD";
1631 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1632 bridge["IssuingChainIssue"] = issuingChainIssue;
1633 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1634 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1635 j[sfXChainBridge] = bridge;
1636 STParsedJSONObject obj("Test", j);
1637 BEAST_EXPECT(!obj.object.has_value());
1638 }
1639
1640 // Invalid XChainBridge: missing IssuingChainIssue
1641 {
1642 Json::Value j;
1644 Json::Value lockingChainIssue(Json::objectValue);
1645 lockingChainIssue["currency"] = "EUR";
1646 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1647 bridge["LockingChainIssue"] = lockingChainIssue;
1648 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1649 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1650 j[sfXChainBridge] = bridge;
1651 STParsedJSONObject obj("Test", j);
1652 BEAST_EXPECT(!obj.object.has_value());
1653 }
1654
1655 // Invalid XChainBridge: missing LockingChainDoor
1656 {
1657 Json::Value j;
1659 Json::Value issuingChainIssue(Json::objectValue);
1660 issuingChainIssue["currency"] = "USD";
1661 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1662 bridge["IssuingChainIssue"] = issuingChainIssue;
1663 Json::Value lockingChainIssue(Json::objectValue);
1664 lockingChainIssue["currency"] = "EUR";
1665 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1666 bridge["LockingChainIssue"] = lockingChainIssue;
1667 bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1668 j[sfXChainBridge] = bridge;
1669 STParsedJSONObject obj("Test", j);
1670 BEAST_EXPECT(!obj.object.has_value());
1671 }
1672
1673 // Invalid XChainBridge: missing IssuingChainDoor
1674 {
1675 Json::Value j;
1677 Json::Value issuingChainIssue(Json::objectValue);
1678 issuingChainIssue["currency"] = "USD";
1679 issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1680 bridge["IssuingChainIssue"] = issuingChainIssue;
1681 Json::Value lockingChainIssue(Json::objectValue);
1682 lockingChainIssue["currency"] = "EUR";
1683 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1684 bridge["LockingChainIssue"] = lockingChainIssue;
1685 bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1686 j[sfXChainBridge] = bridge;
1687 STParsedJSONObject obj("Test", j);
1688 BEAST_EXPECT(!obj.object.has_value());
1689 }
1690
1691 // Invalid XChainBridge: IssuingChainIssue not an object
1692 {
1693 Json::Value j;
1695 bridge["LockingChainIssue"] = "notanobject";
1696 bridge["IssuingChainIssue"] = "notanobject";
1697 j[sfXChainBridge] = bridge;
1698 STParsedJSONObject obj("Test", j);
1699 BEAST_EXPECT(!obj.object.has_value());
1700 }
1701
1702 // Invalid XChainBridge: IssuingChainIssue missing currency
1703 {
1704 Json::Value j;
1707 asset["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1708 Json::Value lockingChainIssue(Json::objectValue);
1709 lockingChainIssue["currency"] = "EUR";
1710 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1711 bridge["LockingChainIssue"] = lockingChainIssue;
1712 bridge["IssuingChainIssue"] = asset;
1713 j[sfXChainBridge] = bridge;
1714 STParsedJSONObject obj("Test", j);
1715 BEAST_EXPECT(!obj.object.has_value());
1716 }
1717
1718 // Invalid XChainBridge: asset missing issuer
1719 {
1720 Json::Value j;
1723 asset["currency"] = "USD";
1724 Json::Value lockingChainIssue(Json::objectValue);
1725 lockingChainIssue["currency"] = "EUR";
1726 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1727 bridge["LockingChainIssue"] = lockingChainIssue;
1728 bridge["IssuingChainIssue"] = asset;
1729 j[sfXChainBridge] = bridge;
1730 STParsedJSONObject obj("Test", j);
1731 BEAST_EXPECT(!obj.object.has_value());
1732 }
1733
1734 // Invalid XChainBridge: asset issuer not base58
1735 {
1736 Json::Value j;
1739 asset["currency"] = "USD";
1740 asset["issuer"] = "notAValidBase58Account";
1741 Json::Value lockingChainIssue(Json::objectValue);
1742 lockingChainIssue["currency"] = "EUR";
1743 lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1744 bridge["LockingChainIssue"] = lockingChainIssue;
1745 bridge["IssuingChainIssue"] = asset;
1746 j[sfXChainBridge] = bridge;
1747 STParsedJSONObject obj("Test", j);
1748 BEAST_EXPECT(!obj.object.has_value());
1749 }
1750
1751 // Invalid XChainBridge: not an object
1752 {
1753 Json::Value j;
1754 j[sfXChainBridge] = "notanobject";
1755 STParsedJSONObject obj("Test", j);
1756 BEAST_EXPECT(!obj.object.has_value());
1757 }
1758 }
1759
1760 void
1762 {
1763 testcase("Number");
1764 // Valid integer value for STNumber
1765 {
1766 Json::Value j;
1767 j[sfNumber] = 12345;
1768 STParsedJSONObject obj("Test", j);
1769 BEAST_EXPECT(obj.object.has_value());
1770 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1771 BEAST_EXPECT(
1772 obj.object->getFieldNumber(sfNumber).value() ==
1773 Number(12345, 0));
1774 }
1775
1776 // Valid uint value for STNumber
1777 {
1778 Json::Value j;
1779 j[sfNumber] = 12345u;
1780 STParsedJSONObject obj("Test", j);
1781 BEAST_EXPECT(obj.object.has_value());
1782 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1783 BEAST_EXPECT(
1784 obj.object->getFieldNumber(sfNumber).value() ==
1785 Number(12345, 0));
1786 }
1787
1788 // Valid string integer value for STNumber
1789 {
1790 Json::Value j;
1791 j[sfNumber] = "67890";
1792 STParsedJSONObject obj("Test", j);
1793 BEAST_EXPECT(obj.object.has_value());
1794 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1795 BEAST_EXPECT(
1796 obj.object->getFieldNumber(sfNumber).value() ==
1797 Number(67890, 0));
1798 }
1799
1800 // Valid negative integer value for STNumber
1801 {
1802 Json::Value j;
1803 j[sfNumber] = -42;
1804 STParsedJSONObject obj("Test", j);
1805 BEAST_EXPECT(obj.object.has_value());
1806 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1807 BEAST_EXPECT(
1808 obj.object->getFieldNumber(sfNumber).value() == Number(-42, 0));
1809 }
1810
1811 // Valid string negative integer value for STNumber
1812 {
1813 Json::Value j;
1814 j[sfNumber] = "-123";
1815 STParsedJSONObject obj("Test", j);
1816 BEAST_EXPECT(obj.object.has_value());
1817 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1818 BEAST_EXPECT(
1819 obj.object->getFieldNumber(sfNumber).value() ==
1820 Number(-123, 0));
1821 }
1822
1823 // Valid floating point value for STNumber
1824 {
1825 Json::Value j;
1826 j[sfNumber] = "3.14159";
1827 STParsedJSONObject obj("Test", j);
1828 if (BEAST_EXPECT(obj.object.has_value()))
1829 {
1830 BEAST_EXPECT(obj.object->isFieldPresent(sfNumber));
1831 BEAST_EXPECT(
1832 obj.object->getFieldNumber(sfNumber).value() ==
1833 Number(314159, -5));
1834 }
1835 }
1836
1837 // Invalid string value for STNumber (not a number)
1838 {
1839 Json::Value j;
1840 j[sfNumber] = "notanumber";
1841 STParsedJSONObject obj("Test", j);
1842 BEAST_EXPECT(!obj.object.has_value());
1843 }
1844
1845 // Invalid array value for STNumber
1846 {
1847 Json::Value j;
1848 j[sfNumber] = Json::Value(Json::arrayValue);
1849 STParsedJSONObject obj("Test", j);
1850 BEAST_EXPECT(!obj.object.has_value());
1851 }
1852
1853 // Invalid object value for STNumber
1854 {
1855 Json::Value j;
1856 j[sfNumber] = Json::Value(Json::objectValue);
1857 STParsedJSONObject obj("Test", j);
1858 BEAST_EXPECT(!obj.object.has_value());
1859 }
1860
1861 // Empty string for STNumber (should fail)
1862 {
1863 Json::Value j;
1864 j[sfNumber] = "";
1865 STParsedJSONObject obj("Test", j);
1866 BEAST_EXPECT(!obj.object.has_value());
1867 }
1868 }
1869
1870 void
1872 {
1873 testcase("Object");
1874 // Test with valid object for Object
1875 {
1876 Json::Value j;
1878 objVal[sfTransactionResult] = 1;
1879 j[sfTransactionMetaData] = objVal;
1880 STParsedJSONObject obj("Test", j);
1881 BEAST_EXPECT(obj.object.has_value());
1882 BEAST_EXPECT(obj.object->isFieldPresent(sfTransactionMetaData));
1883 auto const& result =
1884 obj.object->peekFieldObject(sfTransactionMetaData);
1885 BEAST_EXPECT(result.getFieldU8(sfTransactionResult) == 1);
1886 }
1887
1888 // Test with non-object value for Object (should fail)
1889 {
1890 Json::Value j;
1891 j[sfTransactionMetaData] = "notanobject";
1892 STParsedJSONObject obj("Test", j);
1893 BEAST_EXPECT(!obj.object.has_value());
1894 }
1895
1896 // Test with array value for Object (should fail)
1897 {
1898 Json::Value j;
1900 arr.append(1);
1901 j[sfTransactionMetaData] = arr;
1902 STParsedJSONObject obj("Test", j);
1903 BEAST_EXPECT(!obj.object.has_value());
1904 }
1905
1906 // Test with null value for Object (should fail)
1907 {
1908 Json::Value j;
1909 j[sfTransactionMetaData] = Json::Value(Json::nullValue);
1910 STParsedJSONObject obj("Test", j);
1911 BEAST_EXPECT(!obj.object.has_value());
1912 }
1913
1914 // Test with max depth (should succeed)
1915 // max depth is 64
1916 {
1917 Json::Value j;
1919 Json::Value* current = &obj;
1920 for (int i = 0; i < 63; ++i)
1921 {
1923 (*current)[sfTransactionMetaData] = next;
1924 current = &((*current)[sfTransactionMetaData]);
1925 }
1926 (*current)[sfTransactionResult.getJsonName()] = 1;
1927 j[sfTransactionMetaData] = obj;
1928 STParsedJSONObject parsed("Test", j);
1929 BEAST_EXPECT(parsed.object.has_value());
1930 BEAST_EXPECT(parsed.object->isFieldPresent(sfTransactionMetaData));
1931 }
1932
1933 // Test with depth exceeding maxDepth (should fail)
1934 {
1935 Json::Value j;
1937 Json::Value* current = &obj;
1938 for (int i = 0; i < 64; ++i)
1939 {
1941 (*current)[sfTransactionMetaData] = next;
1942 current = &((*current)[sfTransactionMetaData]);
1943 }
1944 (*current)[sfTransactionResult.getJsonName()] = 1;
1945 j[sfTransactionMetaData] = obj;
1946 STParsedJSONObject parsed("Test", j);
1947 BEAST_EXPECT(!parsed.object.has_value());
1948 }
1949 }
1950
1951 void
1953 {
1954 testcase("Array");
1955 // Test with valid array for Array
1956 {
1957 Json::Value j;
1960 elem[sfTransactionResult] = 2;
1962 elem2[sfTransactionMetaData] = elem;
1963 arr.append(elem2);
1964 j[sfSignerEntries] = arr;
1965 STParsedJSONObject obj("Test", j);
1966 BEAST_EXPECT(obj.object.has_value());
1967 BEAST_EXPECT(obj.object->isFieldPresent(sfSignerEntries));
1968 auto const& result = obj.object->getFieldArray(sfSignerEntries);
1969 if (BEAST_EXPECT(result.size() == 1))
1970 {
1971 BEAST_EXPECT(result[0].getFName() == sfTransactionMetaData);
1972 BEAST_EXPECT(result[0].getJson(0) == elem);
1973 }
1974 }
1975
1976 // Test with array containing non-object element (should fail)
1977 {
1978 Json::Value j;
1980 arr.append("notanobject");
1981 j[sfSignerEntries] = arr;
1982 STParsedJSONObject obj("Test", j);
1983 BEAST_EXPECT(!obj.object.has_value());
1984 }
1985
1986 // Test with array containing object with invalid field (should fail)
1987 {
1988 Json::Value j;
1991 elem["invalidField"] = 1;
1992 arr.append(elem);
1993 j[sfSignerEntries] = arr;
1994 STParsedJSONObject obj("Test", j);
1995 BEAST_EXPECT(!obj.object.has_value());
1996 }
1997
1998 // Test with array containing object with multiple keys (should fail)
1999 {
2000 Json::Value j;
2003 elem[sfTransactionResult] = 2;
2004 elem[sfNetworkID] = 3;
2005 arr.append(elem);
2006 j[sfSignerEntries] = arr;
2007 STParsedJSONObject obj("Test", j);
2008 BEAST_EXPECT(!obj.object.has_value());
2009 }
2010
2011 // Test with non-array value for Array (should fail)
2012 {
2013 Json::Value j;
2014 j[sfSignerEntries] = "notanarray";
2015 STParsedJSONObject obj("Test", j);
2016 BEAST_EXPECT(!obj.object.has_value());
2017 }
2018
2019 // Test with array containing object with valid field but invalid value
2020 // (should fail)
2021 {
2022 Json::Value j;
2025 elem[sfTransactionResult] = "notanint";
2026 arr.append(elem);
2027 j[sfSignerEntries] = arr;
2028 STParsedJSONObject obj("Test", j);
2029 BEAST_EXPECT(!obj.object.has_value());
2030 }
2031
2032 // Test with empty array for Array (should be valid)
2033 {
2034 Json::Value j;
2036 j[sfSignerEntries] = arr;
2037 STParsedJSONObject obj("Test", j);
2038 BEAST_EXPECT(obj.object.has_value());
2039 BEAST_EXPECT(obj.object->isFieldPresent(sfSignerEntries));
2040 }
2041
2042 // Test with object provided but not object SField
2043 {
2044 Json::Value j;
2047 obj[0u][sfTransactionResult] = 1;
2048 j[sfSignerEntries] = obj;
2049 STParsedJSONObject parsed("Test", j);
2050 BEAST_EXPECT(!parsed.object.has_value());
2051 }
2052
2053 // Test invalid children
2054 {
2055 try
2056 {
2057 /*
2058
2059 STArray/STObject constructs don't really map perfectly to json
2060 arrays/objects.
2061
2062 STObject is an associative container, mapping fields to value,
2063 but an STObject may also have a Field as its name, stored
2064 outside the associative structure. The name is important, so to
2065 maintain fidelity, it will take TWO json objects to represent
2066 them.
2067
2068 */
2069 std::string faulty(
2070 "{\"Template\":[{"
2071 "\"ModifiedNode\":{\"Sequence\":1}, "
2072 "\"DeletedNode\":{\"Sequence\":1}"
2073 "}]}");
2074
2076 Json::Value faultyJson;
2077 bool parsedOK(parseJSONString(faulty, faultyJson));
2078 unexpected(!parsedOK, "failed to parse");
2079 STParsedJSONObject parsed("test", faultyJson);
2080 BEAST_EXPECT(!parsed.object);
2081 }
2082 catch (std::runtime_error& e)
2083 {
2084 std::string what(e.what());
2085 unexpected(
2086 what.find("First level children of `Template`") != 0);
2087 }
2088 }
2089 }
2090
2091 void
2093 {
2094 testcase("General Invalid Cases");
2095
2096 {
2097 Json::Value j;
2098 j[sfLedgerEntry] = 1; // not a valid SField for STParsedJSON
2099 }
2100
2101 {
2102 std::string const goodJson(R"({"CloseResolution":19,"Method":250,)"
2103 R"("TransactionResult":"tecFROZEN"})");
2104
2105 Json::Value jv;
2106 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
2107 {
2108 STParsedJSONObject parsed("test", jv);
2109 if (BEAST_EXPECT(parsed.object))
2110 {
2111 std::string const& serialized(
2112 to_string(parsed.object->getJson(JsonOptions::none)));
2113 BEAST_EXPECT(serialized == goodJson);
2114 }
2115 }
2116 }
2117
2118 {
2119 std::string const goodJson(
2120 R"({"CloseResolution":19,"Method":"250",)"
2121 R"("TransactionResult":"tecFROZEN"})");
2122 std::string const expectedJson(
2123 R"({"CloseResolution":19,"Method":250,)"
2124 R"("TransactionResult":"tecFROZEN"})");
2125
2126 Json::Value jv;
2127 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
2128 {
2129 // Integer values are always parsed as int,
2130 // unless they're too big. We want a small uint.
2131 jv["CloseResolution"] = Json::UInt(19);
2132 STParsedJSONObject parsed("test", jv);
2133 if (BEAST_EXPECT(parsed.object))
2134 {
2135 std::string const& serialized(
2136 to_string(parsed.object->getJson(JsonOptions::none)));
2137 BEAST_EXPECT(serialized == expectedJson);
2138 }
2139 }
2140 }
2141
2142 {
2143 std::string const goodJson(
2144 R"({"CloseResolution":"19","Method":"250",)"
2145 R"("TransactionResult":"tecFROZEN"})");
2146 std::string const expectedJson(
2147 R"({"CloseResolution":19,"Method":250,)"
2148 R"("TransactionResult":"tecFROZEN"})");
2149
2150 Json::Value jv;
2151 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
2152 {
2153 // Integer values are always parsed as int,
2154 // unless they're too big. We want a small uint.
2155 jv["CloseResolution"] = Json::UInt(19);
2156 STParsedJSONObject parsed("test", jv);
2157 if (BEAST_EXPECT(parsed.object))
2158 {
2159 std::string const& serialized(
2160 to_string(parsed.object->getJson(JsonOptions::none)));
2161 BEAST_EXPECT(serialized == expectedJson);
2162 }
2163 }
2164 }
2165
2166 {
2167 std::string const json(R"({"CloseResolution":19,"Method":250,)"
2168 R"("TransactionResult":"terQUEUED"})");
2169
2170 Json::Value jv;
2171 if (BEAST_EXPECT(parseJSONString(json, jv)))
2172 {
2173 STParsedJSONObject parsed("test", jv);
2174 BEAST_EXPECT(!parsed.object);
2175 BEAST_EXPECT(parsed.error);
2176 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2177 BEAST_EXPECT(
2178 parsed.error[jss::error_message] ==
2179 "Field 'test.TransactionResult' is out of range.");
2180 }
2181 }
2182
2183 {
2184 std::string const json(R"({"CloseResolution":19,"Method":"pony",)"
2185 R"("TransactionResult":"tesSUCCESS"})");
2186
2187 Json::Value jv;
2188 if (BEAST_EXPECT(parseJSONString(json, jv)))
2189 {
2190 STParsedJSONObject parsed("test", jv);
2191 BEAST_EXPECT(!parsed.object);
2192 BEAST_EXPECT(parsed.error);
2193 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2194 BEAST_EXPECT(
2195 parsed.error[jss::error_message] ==
2196 "Field 'test.Method' has bad type.");
2197 }
2198 }
2199
2200 {
2201 std::string const json(
2202 R"({"CloseResolution":19,"Method":3294967296,)"
2203 R"("TransactionResult":"tesSUCCESS"})");
2204
2205 Json::Value jv;
2206 if (BEAST_EXPECT(parseJSONString(json, jv)))
2207 {
2208 STParsedJSONObject parsed("test", jv);
2209 BEAST_EXPECT(!parsed.object);
2210 BEAST_EXPECT(parsed.error);
2211 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2212 BEAST_EXPECT(
2213 parsed.error[jss::error_message] ==
2214 "Field 'test.Method' is out of range.");
2215 }
2216 }
2217
2218 {
2219 std::string const json(R"({"CloseResolution":-10,"Method":42,)"
2220 R"("TransactionResult":"tesSUCCESS"})");
2221
2222 Json::Value jv;
2223 if (BEAST_EXPECT(parseJSONString(json, jv)))
2224 {
2225 STParsedJSONObject parsed("test", jv);
2226 BEAST_EXPECT(!parsed.object);
2227 BEAST_EXPECT(parsed.error);
2228 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2229 BEAST_EXPECT(
2230 parsed.error[jss::error_message] ==
2231 "Field 'test.CloseResolution' is out of range.");
2232 }
2233 }
2234
2235 {
2236 std::string const json(
2237 R"({"CloseResolution":19,"Method":3.141592653,)"
2238 R"("TransactionResult":"tesSUCCESS"})");
2239
2240 Json::Value jv;
2241 if (BEAST_EXPECT(parseJSONString(json, jv)))
2242 {
2243 STParsedJSONObject parsed("test", jv);
2244 BEAST_EXPECT(!parsed.object);
2245 BEAST_EXPECT(parsed.error);
2246 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2247 BEAST_EXPECT(
2248 parsed.error[jss::error_message] ==
2249 "Field 'test.Method' has bad type.");
2250 }
2251 }
2252
2253 {
2254 std::string const goodJson(R"({"CloseResolution":19,"Method":250,)"
2255 R"("TransferFee":"65535"})");
2256 std::string const expectedJson(
2257 R"({"CloseResolution":19,"Method":250,)"
2258 R"("TransferFee":65535})");
2259
2260 Json::Value jv;
2261 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
2262 {
2263 STParsedJSONObject parsed("test", jv);
2264 if (BEAST_EXPECT(parsed.object))
2265 {
2266 std::string const& serialized(
2267 to_string(parsed.object->getJson(JsonOptions::none)));
2268 BEAST_EXPECT(serialized == expectedJson);
2269 }
2270 }
2271 }
2272
2273 {
2274 std::string const json(R"({"CloseResolution":19,"Method":250,)"
2275 R"("TransferFee":"65536"})");
2276
2277 Json::Value jv;
2278 if (BEAST_EXPECT(parseJSONString(json, jv)))
2279 {
2280 STParsedJSONObject parsed("test", jv);
2281 BEAST_EXPECT(!parsed.object);
2282 BEAST_EXPECT(parsed.error);
2283 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2284 BEAST_EXPECT(
2285 parsed.error[jss::error_message] ==
2286 "Field 'test.TransferFee' has invalid data.");
2287 }
2288 }
2289
2290 {
2291 std::string const json(R"({"CloseResolution":19,"Method":250,)"
2292 R"("TransferFee":"Payment"})");
2293
2294 Json::Value jv;
2295 if (BEAST_EXPECT(parseJSONString(json, jv)))
2296 {
2297 STParsedJSONObject parsed("test", jv);
2298 BEAST_EXPECT(!parsed.object);
2299 BEAST_EXPECT(parsed.error);
2300 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2301 BEAST_EXPECT(
2302 parsed.error[jss::error_message] ==
2303 "Field 'test.TransferFee' has invalid data.");
2304 }
2305 }
2306
2307 {
2308 std::string const json(R"({"CloseResolution":19,"Method":250,)"
2309 R"("TransferFee":true})");
2310
2311 Json::Value jv;
2312 if (BEAST_EXPECT(parseJSONString(json, jv)))
2313 {
2314 STParsedJSONObject parsed("test", jv);
2315 BEAST_EXPECT(!parsed.object);
2316 BEAST_EXPECT(parsed.error);
2317 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
2318 BEAST_EXPECT(
2319 parsed.error[jss::error_message] ==
2320 "Field 'test.TransferFee' has bad type.");
2321 }
2322 }
2323 }
2324
2325 void
2326 run() override
2327 {
2328 // Instantiate a jtx::Env so debugLog writes are exercised.
2329 test::jtx::Env env(*this);
2330 testUInt8();
2331 testUInt16();
2332 testUInt32();
2333 testUInt64();
2334 testUInt128();
2335 testUInt160();
2336 testUInt192();
2337 testUInt256();
2338 testInt32();
2339 testBlob();
2340 testVector256();
2341 testAccount();
2342 testCurrency();
2343 testAmount();
2344 testPathSet();
2345 testIssue();
2347 testNumber();
2348 testObject();
2349 testArray();
2350 testEdgeCases();
2351 }
2352};
2353
2354BEAST_DEFINE_TESTSUITE(STParsedJSON, protocol, ripple);
2355
2356} // 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.
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 to_string(T... args)
T what(T... args)