rippled
Loading...
Searching...
No Matches
STObject_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 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/json/to_string.h>
25#include <xrpl/protocol/SecretKey.h>
26#include <xrpl/protocol/jss.h>
27#include <xrpl/protocol/st.h>
28
29#include <array>
30#include <memory>
31#include <type_traits>
32
33namespace ripple {
34
36{
37public:
38 bool
40 {
41 Json::Reader reader;
42 return reader.parse(json, to) && to.isObject();
43 }
44
45 void
47 {
48 testcase("parse json array invalid children");
49 try
50 {
51 /*
52
53 STArray/STObject constructs don't really map perfectly to json
54 arrays/objects.
55
56 STObject is an associative container, mapping fields to value, but
57 an STObject may also have a Field as its name, stored outside the
58 associative structure. The name is important, so to maintain
59 fidelity, it will take TWO json objects to represent them.
60
61 */
62 std::string faulty(
63 "{\"Template\":[{"
64 "\"ModifiedNode\":{\"Sequence\":1}, "
65 "\"DeletedNode\":{\"Sequence\":1}"
66 "}]}");
67
69 Json::Value faultyJson;
70 bool parsedOK(parseJSONString(faulty, faultyJson));
71 unexpected(!parsedOK, "failed to parse");
72 STParsedJSONObject parsed("test", faultyJson);
73 BEAST_EXPECT(!parsed.object);
74 }
75 catch (std::runtime_error& e)
76 {
77 std::string what(e.what());
78 unexpected(what.find("First level children of `Template`") != 0);
79 }
80 }
81
82 void
84 {
85 testcase("parse json array");
86 std::string const json(
87 "{\"Template\":[{\"ModifiedNode\":{\"Sequence\":1}}]}");
88
89 Json::Value jsonObject;
90 bool parsedOK(parseJSONString(json, jsonObject));
91 if (parsedOK)
92 {
93 STParsedJSONObject parsed("test", jsonObject);
94 BEAST_EXPECT(parsed.object);
95 std::string const& serialized(
96 to_string(parsed.object->getJson(JsonOptions::none)));
97 BEAST_EXPECT(serialized == json);
98 }
99 else
100 {
101 fail("Couldn't parse json: " + json);
102 }
103 }
104
105 void
107 {
108 testcase("parse json object");
109
110 {
111 std::string const goodJson(R"({"CloseResolution":19,"Method":250,)"
112 R"("TransactionResult":"tecFROZEN"})");
113
114 Json::Value jv;
115 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
116 {
117 STParsedJSONObject parsed("test", jv);
118 if (BEAST_EXPECT(parsed.object))
119 {
120 std::string const& serialized(
121 to_string(parsed.object->getJson(JsonOptions::none)));
122 BEAST_EXPECT(serialized == goodJson);
123 }
124 }
125 }
126
127 {
128 std::string const goodJson(
129 R"({"CloseResolution":19,"Method":"250",)"
130 R"("TransactionResult":"tecFROZEN"})");
131 std::string const expectedJson(
132 R"({"CloseResolution":19,"Method":250,)"
133 R"("TransactionResult":"tecFROZEN"})");
134
135 Json::Value jv;
136 if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
137 {
138 // Integer values are always parsed as int,
139 // unless they're too big. We want a small uint.
140 jv["CloseResolution"] = Json::UInt(19);
141 STParsedJSONObject parsed("test", jv);
142 if (BEAST_EXPECT(parsed.object))
143 {
144 std::string const& serialized(
145 to_string(parsed.object->getJson(JsonOptions::none)));
146 BEAST_EXPECT(serialized == expectedJson);
147 }
148 }
149 }
150
151 {
152 std::string const json(R"({"CloseResolution":19,"Method":250,)"
153 R"("TransactionResult":"terQUEUED"})");
154
155 Json::Value jv;
156 if (BEAST_EXPECT(parseJSONString(json, jv)))
157 {
158 STParsedJSONObject parsed("test", jv);
159 BEAST_EXPECT(!parsed.object);
160 BEAST_EXPECT(parsed.error);
161 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
162 BEAST_EXPECT(
163 parsed.error[jss::error_message] ==
164 "Field 'test.TransactionResult' is out of range.");
165 }
166 }
167
168 {
169 std::string const json(R"({"CloseResolution":19,"Method":"pony",)"
170 R"("TransactionResult":"tesSUCCESS"})");
171
172 Json::Value jv;
173 if (BEAST_EXPECT(parseJSONString(json, jv)))
174 {
175 STParsedJSONObject parsed("test", jv);
176 BEAST_EXPECT(!parsed.object);
177 BEAST_EXPECT(parsed.error);
178 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
179 BEAST_EXPECT(
180 parsed.error[jss::error_message] ==
181 "Field 'test.Method' has bad type.");
182 }
183 }
184
185 {
186 std::string const json(
187 R"({"CloseResolution":19,"Method":3294967296,)"
188 R"("TransactionResult":"tesSUCCESS"})");
189
190 Json::Value jv;
191 if (BEAST_EXPECT(parseJSONString(json, jv)))
192 {
193 STParsedJSONObject parsed("test", jv);
194 BEAST_EXPECT(!parsed.object);
195 BEAST_EXPECT(parsed.error);
196 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
197 BEAST_EXPECT(
198 parsed.error[jss::error_message] ==
199 "Field 'test.Method' is out of range.");
200 }
201 }
202
203 {
204 std::string const json(R"({"CloseResolution":-10,"Method":42,)"
205 R"("TransactionResult":"tesSUCCESS"})");
206
207 Json::Value jv;
208 if (BEAST_EXPECT(parseJSONString(json, jv)))
209 {
210 STParsedJSONObject parsed("test", jv);
211 BEAST_EXPECT(!parsed.object);
212 BEAST_EXPECT(parsed.error);
213 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
214 BEAST_EXPECT(
215 parsed.error[jss::error_message] ==
216 "Field 'test.CloseResolution' is out of range.");
217 }
218 }
219
220 {
221 std::string const json(
222 R"({"CloseResolution":19,"Method":3.141592653,)"
223 R"("TransactionResult":"tesSUCCESS"})");
224
225 Json::Value jv;
226 if (BEAST_EXPECT(parseJSONString(json, jv)))
227 {
228 STParsedJSONObject parsed("test", jv);
229 BEAST_EXPECT(!parsed.object);
230 BEAST_EXPECT(parsed.error);
231 BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
232 BEAST_EXPECT(
233 parsed.error[jss::error_message] ==
234 "Field 'test.Method' has bad type.");
235 }
236 }
237 }
238
239 void
241 {
242 testcase("serialization");
243
244 unexpected(sfGeneric.isUseful(), "sfGeneric must not be useful");
245 {
246 // Try to put sfGeneric in an SOTemplate.
247 except<std::runtime_error>(
248 [&]() { SOTemplate elements{{sfGeneric, soeREQUIRED}}; });
249 }
250
251 unexpected(sfInvalid.isUseful(), "sfInvalid must not be useful");
252 {
253 // Test return of sfInvalid.
254 auto testInvalid = [this](SerializedTypeID tid, int fv) {
255 SField const& shouldBeInvalid{SField::getField(tid, fv)};
256 BEAST_EXPECT(shouldBeInvalid == sfInvalid);
257 };
258 testInvalid(STI_VL, 255);
259 testInvalid(STI_UINT256, 255);
260 testInvalid(STI_UINT32, 255);
261 testInvalid(STI_VECTOR256, 255);
262 testInvalid(STI_OBJECT, 255);
263 }
264 {
265 // Try to put sfInvalid in an SOTemplate.
266 except<std::runtime_error>(
267 [&]() { SOTemplate elements{{sfInvalid, soeREQUIRED}}; });
268 }
269 {
270 // Try to put the same SField into an SOTemplate twice.
271 except<std::runtime_error>([&]() {
272 SOTemplate elements{
273 {sfAccount, soeREQUIRED},
274 {sfAccount, soeREQUIRED},
275 };
276 });
277 }
278
279 // Put a variety of SFields of different types in an SOTemplate.
280 SField const& sfTestVL = sfMasterSignature;
281 SField const& sfTestH256 = sfCheckID;
282 SField const& sfTestU32 = sfSettleDelay;
283 SField const& sfTestV256 = sfAmendments;
284 SField const& sfTestObject = sfMajority;
285
286 SOTemplate const elements{
287 {sfFlags, soeREQUIRED},
288 {sfTestVL, soeREQUIRED},
289 {sfTestH256, soeOPTIONAL},
290 {sfTestU32, soeREQUIRED},
291 {sfTestV256, soeOPTIONAL},
292 };
293
294 STObject object1(elements, sfTestObject);
295 STObject object2(object1);
296
298 object1.getSerializer() != object2.getSerializer(),
299 "STObject error 1");
300
302 object1.isFieldPresent(sfTestH256) ||
303 !object1.isFieldPresent(sfTestVL),
304 "STObject error");
305
306 object1.makeFieldPresent(sfTestH256);
307
308 unexpected(!object1.isFieldPresent(sfTestH256), "STObject Error 2");
309
311 object1.getFieldH256(sfTestH256) != uint256(), "STObject error 3");
312
313 if (object1.getSerializer() == object2.getSerializer())
314 {
315 log << "O1: " << object1.getJson(JsonOptions::none) << '\n'
316 << "O2: " << object2.getJson(JsonOptions::none) << std::endl;
317 fail("STObject error 4");
318 }
319 else
320 {
321 pass();
322 }
323
324 object1.makeFieldAbsent(sfTestH256);
325
326 unexpected(object1.isFieldPresent(sfTestH256), "STObject error 5");
327
328 unexpected(object1.getFlags() != 0, "STObject error 6");
329
331 object1.getSerializer() != object2.getSerializer(),
332 "STObject error 7");
333
334 STObject copy(object1);
335
336 unexpected(object1.isFieldPresent(sfTestH256), "STObject error 8");
337
338 unexpected(copy.isFieldPresent(sfTestH256), "STObject error 9");
339
341 object1.getSerializer() != copy.getSerializer(),
342 "STObject error 10");
343
344 copy.setFieldU32(sfTestU32, 1);
345
347 object1.getSerializer() == copy.getSerializer(),
348 "STObject error 11");
349
350 for (int i = 0; i < 1000; i++)
351 {
352 Blob j(i, 2);
353
354 object1.setFieldVL(sfTestVL, j);
355
356 Serializer s;
357 object1.add(s);
358 SerialIter it(s.slice());
359
360 STObject object3(elements, it, sfTestObject);
361
362 unexpected(object1.getFieldVL(sfTestVL) != j, "STObject error");
363
364 unexpected(object3.getFieldVL(sfTestVL) != j, "STObject error");
365 }
366
367 {
369 uints.reserve(5);
370 for (int i = 0; i < uints.capacity(); ++i)
371 {
372 uints.emplace_back(i);
373 }
374 object1.setFieldV256(sfTestV256, STVector256(uints));
375
376 Serializer s;
377 object1.add(s);
378 SerialIter it(s.slice());
379
380 STObject object3(elements, it, sfTestObject);
381
382 auto const& uints1 = object1.getFieldV256(sfTestV256);
383 auto const& uints3 = object3.getFieldV256(sfTestV256);
384
385 BEAST_EXPECT(uints1 == uints3);
386 }
387 }
388
389 // Exercise field accessors
390 void
392 {
393 testcase("fields");
394
395 auto const& sf1Outer = sfSequence;
396 auto const& sf2Outer = sfExpiration;
397 auto const& sf3Outer = sfQualityIn;
398 auto const& sf4Outer = sfAmount;
399 auto const& sf4 = sfSignature;
400 auto const& sf5 = sfPublicKey;
401
402 // read free object
403
404 {
405 auto const st = [&]() {
407 s.setFieldU32(sf1Outer, 1);
408 s.setFieldU32(sf2Outer, 2);
409 return s;
410 }();
411
412 BEAST_EXPECT(st[sf1Outer] == 1);
413 BEAST_EXPECT(st[sf2Outer] == 2);
414 except<STObject::FieldErr>([&]() { st[sf3Outer]; });
415 BEAST_EXPECT(*st[~sf1Outer] == 1);
416 BEAST_EXPECT(*st[~sf2Outer] == 2);
417 BEAST_EXPECT(st[~sf3Outer] == std::nullopt);
418 BEAST_EXPECT(!!st[~sf1Outer]);
419 BEAST_EXPECT(!!st[~sf2Outer]);
420 BEAST_EXPECT(!st[~sf3Outer]);
421 BEAST_EXPECT(st[sf1Outer] != st[sf2Outer]);
422 BEAST_EXPECT(st[~sf1Outer] != st[~sf2Outer]);
423 }
424
425 // read templated object
426 SOTemplate const sotOuter{
427 {sf1Outer, soeREQUIRED},
428 {sf2Outer, soeOPTIONAL},
429 {sf3Outer, soeDEFAULT},
430 {sf4Outer, soeOPTIONAL},
431 {sf4, soeOPTIONAL},
432 {sf5, soeDEFAULT},
433 };
434
435 {
436 auto const st = [&]() {
437 STObject s(sotOuter, sfGeneric);
438 s.setFieldU32(sf1Outer, 1);
439 s.setFieldU32(sf2Outer, 2);
440 return s;
441 }();
442
443 BEAST_EXPECT(st[sf1Outer] == 1);
444 BEAST_EXPECT(st[sf2Outer] == 2);
445 BEAST_EXPECT(st[sf3Outer] == 0);
446 BEAST_EXPECT(*st[~sf1Outer] == 1);
447 BEAST_EXPECT(*st[~sf2Outer] == 2);
448 BEAST_EXPECT(*st[~sf3Outer] == 0);
449 BEAST_EXPECT(!!st[~sf1Outer]);
450 BEAST_EXPECT(!!st[~sf2Outer]);
451 BEAST_EXPECT(!!st[~sf3Outer]);
452 }
453
454 // write free object
455
456 {
458 unexcept([&]() { st[sf1Outer]; });
459 except([&]() { return st[sf1Outer] == 0; });
460 BEAST_EXPECT(st[~sf1Outer] == std::nullopt);
461 BEAST_EXPECT(st[~sf1Outer] == std::optional<std::uint32_t>{});
462 BEAST_EXPECT(st[~sf1Outer] != std::optional<std::uint32_t>(1));
463 BEAST_EXPECT(!st[~sf1Outer]);
464 st[sf1Outer] = 2;
465 BEAST_EXPECT(st[sf1Outer] == 2);
466 BEAST_EXPECT(st[~sf1Outer] != std::nullopt);
467 BEAST_EXPECT(st[~sf1Outer] == std::optional<std::uint32_t>(2));
468 BEAST_EXPECT(!!st[~sf1Outer]);
469 st[sf1Outer] = 1;
470 BEAST_EXPECT(st[sf1Outer] == 1);
471 BEAST_EXPECT(!!st[sf1Outer]);
472 BEAST_EXPECT(!!st[~sf1Outer]);
473 st[sf1Outer] = 0;
474 BEAST_EXPECT(!st[sf1Outer]);
475 BEAST_EXPECT(!!st[~sf1Outer]);
476 st[~sf1Outer] = std::nullopt;
477 BEAST_EXPECT(!st[~sf1Outer]);
478 BEAST_EXPECT(st[~sf1Outer] == std::nullopt);
479 BEAST_EXPECT(st[~sf1Outer] == std::optional<std::uint32_t>{});
480 st[~sf1Outer] = std::nullopt;
481 BEAST_EXPECT(!st[~sf1Outer]);
482 except([&]() { return st[sf1Outer] == 0; });
483 except([&]() { return *st[~sf1Outer]; });
484 st[sf1Outer] = 1;
485 BEAST_EXPECT(st[sf1Outer] == 1);
486 BEAST_EXPECT(!!st[sf1Outer]);
487 BEAST_EXPECT(!!st[~sf1Outer]);
488 st[sf1Outer] = 3;
489 st[sf2Outer] = st[sf1Outer];
490 BEAST_EXPECT(st[sf1Outer] == 3);
491 BEAST_EXPECT(st[sf2Outer] == 3);
492 BEAST_EXPECT(st[sf2Outer] == st[sf1Outer]);
493 st[sf1Outer] = 4;
494 st[sf2Outer] = st[sf1Outer];
495 BEAST_EXPECT(st[sf1Outer] == 4);
496 BEAST_EXPECT(st[sf2Outer] == 4);
497 BEAST_EXPECT(st[sf2Outer] == st[sf1Outer]);
498 st[sf1Outer] += 1;
499 BEAST_EXPECT(st[sf1Outer] == 5);
500 st[sf4Outer] = STAmount{1};
501 BEAST_EXPECT(st[sf4Outer] == STAmount{1});
502 st[sf4Outer] += STAmount{1};
503 BEAST_EXPECT(st[sf4Outer] == STAmount{2});
504 st[sf1Outer] -= 1;
505 BEAST_EXPECT(st[sf1Outer] == 4);
506 st[sf4Outer] -= STAmount{1};
507 BEAST_EXPECT(st[sf4Outer] == STAmount{1});
508 }
509
510 // Write templated object
511
512 {
513 STObject st(sotOuter, sfGeneric);
514 BEAST_EXPECT(!!st[~sf1Outer]);
515 BEAST_EXPECT(st[~sf1Outer] != std::nullopt);
516 BEAST_EXPECT(st[sf1Outer] == 0);
517 BEAST_EXPECT(*st[~sf1Outer] == 0);
518 BEAST_EXPECT(!st[~sf2Outer]);
519 BEAST_EXPECT(st[~sf2Outer] == std::nullopt);
520 except([&]() { return st[sf2Outer] == 0; });
521 BEAST_EXPECT(!!st[~sf3Outer]);
522 BEAST_EXPECT(st[~sf3Outer] != std::nullopt);
523 BEAST_EXPECT(st[sf3Outer] == 0);
524 except([&]() { st[~sf1Outer] = std::nullopt; });
525 st[sf1Outer] = 1;
526 BEAST_EXPECT(st[sf1Outer] == 1);
527 BEAST_EXPECT(*st[~sf1Outer] == 1);
528 BEAST_EXPECT(!!st[~sf1Outer]);
529 st[sf1Outer] = 0;
530 BEAST_EXPECT(st[sf1Outer] == 0);
531 BEAST_EXPECT(*st[~sf1Outer] == 0);
532 BEAST_EXPECT(!!st[~sf1Outer]);
533 st[sf2Outer] = 2;
534 BEAST_EXPECT(st[sf2Outer] == 2);
535 BEAST_EXPECT(*st[~sf2Outer] == 2);
536 BEAST_EXPECT(!!st[~sf2Outer]);
537 st[~sf2Outer] = std::nullopt;
538 except([&]() { return *st[~sf2Outer]; });
539 BEAST_EXPECT(!st[~sf2Outer]);
540 st[sf3Outer] = 3;
541 BEAST_EXPECT(st[sf3Outer] == 3);
542 BEAST_EXPECT(*st[~sf3Outer] == 3);
543 BEAST_EXPECT(!!st[~sf3Outer]);
544 st[sf3Outer] = 2;
545 BEAST_EXPECT(st[sf3Outer] == 2);
546 BEAST_EXPECT(*st[~sf3Outer] == 2);
547 BEAST_EXPECT(!!st[~sf3Outer]);
548 st[sf3Outer] = 0;
549 BEAST_EXPECT(st[sf3Outer] == 0);
550 BEAST_EXPECT(*st[~sf3Outer] == 0);
551 BEAST_EXPECT(!!st[~sf3Outer]);
552 except([&]() { st[~sf3Outer] = std::nullopt; });
553 BEAST_EXPECT(st[sf3Outer] == 0);
554 BEAST_EXPECT(*st[~sf3Outer] == 0);
555 BEAST_EXPECT(!!st[~sf3Outer]);
556 st[sf1Outer] += 1;
557 BEAST_EXPECT(st[sf1Outer] == 1);
558 st[sf4Outer] = STAmount{1};
559 BEAST_EXPECT(st[sf4Outer] == STAmount{1});
560 st[sf4Outer] += STAmount{1};
561 BEAST_EXPECT(st[sf4Outer] == STAmount{2});
562 st[sf1Outer] -= 1;
563 BEAST_EXPECT(st[sf1Outer] == 0);
564 st[sf4Outer] -= STAmount{1};
565 BEAST_EXPECT(st[sf4Outer] == STAmount{1});
566 }
567
568 // coercion operator to std::optional
569
570 {
572 auto const v = ~st[~sf1Outer];
573 static_assert(
575 std::decay_t<decltype(v)>,
577 "");
578 }
579
580 // UDT scalar fields
581
582 {
584 st[sfAmount] = STAmount{};
585 st[sfAccount] = AccountID{};
586 st[sfDigest] = uint256{};
587 [&](STAmount) {}(st[sfAmount]);
588 [&](AccountID) {}(st[sfAccount]);
589 [&](uint256) {}(st[sfDigest]);
590 }
591
592 // STBlob and slice
593
594 {
595 {
597 Buffer b(1);
598 BEAST_EXPECT(!b.empty());
599 st[sf4] = std::move(b);
600 BEAST_EXPECT(b.empty());
601 BEAST_EXPECT(Slice(st[sf4]).size() == 1);
602 st[~sf4] = std::nullopt;
603 BEAST_EXPECT(!~st[~sf4]);
604 b = Buffer{2};
605 st[sf4] = Slice(b);
606 BEAST_EXPECT(b.size() == 2);
607 BEAST_EXPECT(Slice(st[sf4]).size() == 2);
608 st[sf5] = st[sf4];
609 BEAST_EXPECT(Slice(st[sf4]).size() == 2);
610 BEAST_EXPECT(Slice(st[sf5]).size() == 2);
611 }
612 {
613 STObject st(sotOuter, sfGeneric);
614 BEAST_EXPECT(st[sf5] == Slice{});
615 BEAST_EXPECT(!!st[~sf5]);
616 BEAST_EXPECT(!!~st[~sf5]);
617 Buffer b(1);
618 st[sf5] = std::move(b);
619 BEAST_EXPECT(b.empty());
620 BEAST_EXPECT(Slice(st[sf5]).size() == 1);
621 st[~sf4] = std::nullopt;
622 BEAST_EXPECT(!~st[~sf4]);
623 }
624 }
625
626 // UDT blobs
627
628 {
630 BEAST_EXPECT(!st[~sf5]);
631 auto const kp = generateKeyPair(
632 KeyType::secp256k1, generateSeed("masterpassphrase"));
633 st[sf5] = kp.first;
634 st[~sf5] = std::nullopt;
635 }
636
637 // By reference fields
638
639 {
640 auto const& sf = sfIndexes;
643 v.emplace_back(1);
644 v.emplace_back(2);
645 st[sf] = v;
646 st[sf] = std::move(v);
647 auto const& cst = st;
648 BEAST_EXPECT(cst[sf].size() == 2);
649 BEAST_EXPECT(cst[~sf]->size() == 2);
650 BEAST_EXPECT(cst[sf][0] == 1);
651 BEAST_EXPECT(cst[sf][1] == 2);
652 static_assert(
654 decltype(cst[sfIndexes]),
655 std::vector<uint256> const&>::value,
656 "");
657 }
658
659 // Default by reference field
660
661 {
662 auto const& sf1 = sfIndexes;
663 auto const& sf2 = sfHashes;
664 auto const& sf3 = sfAmendments;
665 SOTemplate const sot{
666 {sf1, soeREQUIRED},
667 {sf2, soeOPTIONAL},
668 {sf3, soeDEFAULT},
669 };
670
671 STObject st(sot, sfGeneric);
672 auto const& cst(st);
673 BEAST_EXPECT(cst[sf1].size() == 0);
674 BEAST_EXPECT(!cst[~sf2]);
675 BEAST_EXPECT(cst[sf3].size() == 0);
677 v.emplace_back(1);
678 st[sf1] = v;
679 BEAST_EXPECT(cst[sf1].size() == 1);
680 BEAST_EXPECT(cst[sf1][0] == uint256{1});
681 st[sf2] = v;
682 BEAST_EXPECT(cst[sf2].size() == 1);
683 BEAST_EXPECT(cst[sf2][0] == uint256{1});
684 st[~sf2] = std::nullopt;
685 BEAST_EXPECT(!st[~sf2]);
686 st[sf3] = v;
687 BEAST_EXPECT(cst[sf3].size() == 1);
688 BEAST_EXPECT(cst[sf3][0] == uint256{1});
689 st[sf3] = std::vector<uint256>{};
690 BEAST_EXPECT(cst[sf3].size() == 0);
691 }
692 } // namespace ripple
693
694 void
696 {
697 testcase("Malformed serialized forms");
698
699 try
700 {
701 std::array<std::uint8_t, 7> const payload{
702 {0xe9, 0x12, 0xab, 0xcd, 0x12, 0xfe, 0xdc}};
703 SerialIter sit{makeSlice(payload)};
704 auto obj = std::make_shared<STArray>(sit, sfMetadata);
705 BEAST_EXPECT(!obj);
706 }
707 catch (std::exception const& e)
708 {
709 BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0);
710 }
711
712 try
713 {
714 std::array<std::uint8_t, 3> const payload{{0xe2, 0xe1, 0xe2}};
715 SerialIter sit{makeSlice(payload)};
716 auto obj = std::make_shared<STObject>(sit, sfMetadata);
717 BEAST_EXPECT(!obj);
718 }
719 catch (std::exception const& e)
720 {
721 BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0);
722 }
723 }
724
725 void
726 run() override
727 {
728 // Instantiate a jtx::Env so debugLog writes are exercised.
729 test::jtx::Env env(*this);
730
731 testFields();
737 }
738};
739
740BEAST_DEFINE_TESTSUITE(STObject, protocol, ripple);
741
742} // namespace ripple
T capacity(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.
Definition: json_reader.cpp:78
Represents a JSON value.
Definition: json_value.h:149
bool isObject() const
A testsuite class.
Definition: suite.h:55
log_os< char > log
Logging output stream.
Definition: suite.h:152
void pass()
Record a successful test condition.
Definition: suite.h:511
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition: suite.h:499
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
bool unexcept(F &&f, String const &reason)
Definition: suite.h:482
bool except(F &&f, String const &reason)
Definition: suite.h:448
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition: suite.h:533
Like std::vector<char> but better.
Definition: Buffer.h:36
std::size_t size() const noexcept
Returns the number of bytes in the buffer.
Definition: Buffer.h:127
bool empty() const noexcept
Definition: Buffer.h:133
Identifies fields.
Definition: SField.h:143
static SField const & getField(int fieldCode)
Definition: SField.cpp:118
bool isUseful() const
Definition: SField.h:235
Defines the fields and their attributes within a STObject.
Definition: SOTemplate.h:113
void testParseJSONArrayWithInvalidChildrenObjects()
void run() override
Runs the suite.
bool parseJSONString(std::string const &json, Json::Value &to)
Blob getFieldVL(SField const &field) const
Definition: STObject.cpp:657
void makeFieldAbsent(SField const &field)
Definition: STObject.cpp:570
Serializer getSerializer() const
Definition: STObject.h:963
STBase * makeFieldPresent(SField const &field)
Definition: STObject.cpp:548
void add(Serializer &s) const override
Definition: STObject.cpp:141
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:484
void setFieldV256(SField const &field, STVector256 const &v)
Definition: STObject.cpp:765
Json::Value getJson(JsonOptions=JsonOptions::none) const override
Definition: STObject.cpp:825
void setFieldU32(SField const &field, std::uint32_t)
Definition: STObject.cpp:741
void setFieldVL(SField const &field, Blob const &)
Definition: STObject.cpp:777
std::uint32_t getFlags() const
Definition: STObject.cpp:537
uint256 getFieldH256(SField const &field) const
Definition: STObject.cpp:645
STVector256 const & getFieldV256(SField const &field) const
Definition: STObject.cpp:679
Holds the serialized result of parsing an input JSON object.
Definition: STParsedJSON.h:33
std::optional< STObject > object
The STObject if the parse was successful.
Definition: STParsedJSON.h:51
Json::Value error
On failure, an appropriate set of error values.
Definition: STParsedJSON.h:54
Slice slice() const noexcept
Definition: Serializer.h:66
An immutable linear range of bytes.
Definition: Slice.h:46
A transaction testing environment.
Definition: Env.h:121
T emplace_back(T... args)
T endl(T... args)
T find(T... args)
unsigned int UInt
Definition: json_forwards.h:27
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:25
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition: AccountID.h:48
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Definition: SecretKey.cpp:369
base_uint< 256 > uint256
Definition: base_uint.h:558
SerializedTypeID
Definition: SField.h:107
SField const sfInvalid
SField const sfGeneric
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:244
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
@ soeOPTIONAL
Definition: SOTemplate.h:36
@ soeREQUIRED
Definition: SOTemplate.h:35
@ soeDEFAULT
Definition: SOTemplate.h:37
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition: Seed.cpp:76
T reserve(T... args)
T what(T... args)