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