mirror of
https://github.com/XRPLF/rippled.git
synced 2026-09-27 23:38:08 +00:00
refactor: Add initial wrapper classes for all SLEs (#7886)
This commit is contained in:
@@ -31,6 +31,7 @@ set(test_modules
|
||||
consensus
|
||||
crypto
|
||||
json
|
||||
ledger
|
||||
nodestore
|
||||
peerfinder
|
||||
protocol
|
||||
|
||||
25
src/tests/libxrpl/ledger/AMMEntry.cpp
Normal file
25
src/tests/libxrpl/ledger/AMMEntry.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <xrpl/ledger/entries/AMMEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/IOU.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(AMMEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
Asset const xrp{xrpIssue()};
|
||||
Asset const usd{IOU("USD", e.alice).issue()};
|
||||
|
||||
expectKeylet<AMMEntry>(e, keylet::amm(xrp, usd), "amm(asset, asset)", xrp, usd);
|
||||
|
||||
expectKeylet<AMMEntry>(e, keylet::amm(e.someID()), "amm(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
21
src/tests/libxrpl/ledger/AccountRootEntry.cpp
Normal file
21
src/tests/libxrpl/ledger/AccountRootEntry.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/Account.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(AccountRootEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<AccountRootEntry>(e, keylet::account(e.alice.id()), "account(id)", e.alice.id());
|
||||
|
||||
expectKeylet<AccountRootEntry>(
|
||||
e, keylet::account(Account("nobody").id()), "account(id) absent", Account("nobody").id());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
17
src/tests/libxrpl/ledger/AmendmentsEntry.cpp
Normal file
17
src/tests/libxrpl/ledger/AmendmentsEntry.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <xrpl/ledger/entries/AmendmentsEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(AmendmentsEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<AmendmentsEntry>(e, keylet::amendments(), "amendments()");
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
41
src/tests/libxrpl/ledger/BridgeEntry.cpp
Normal file
41
src/tests/libxrpl/ledger/BridgeEntry.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <xrpl/ledger/entries/BridgeEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/IOU.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(BridgeEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
STXChainBridge const bridge{e.alice.id(), xrpIssue(), e.bob.id(), IOU("USD", e.bob).issue()};
|
||||
|
||||
expectKeylet<BridgeEntry>(
|
||||
e,
|
||||
keylet::bridge(bridge, STXChainBridge::ChainType::Locking),
|
||||
"bridge(bridge, Locking)",
|
||||
bridge,
|
||||
STXChainBridge::ChainType::Locking);
|
||||
|
||||
expectKeylet<BridgeEntry>(
|
||||
e,
|
||||
keylet::bridge(bridge, STXChainBridge::ChainType::Issuing),
|
||||
"bridge(bridge, Issuing)",
|
||||
bridge,
|
||||
STXChainBridge::ChainType::Issuing);
|
||||
|
||||
// The two chain types must not collide, or the assertions above would
|
||||
// pass with chainType ignored entirely.
|
||||
EXPECT_NE(
|
||||
keylet::bridge(bridge, STXChainBridge::ChainType::Locking).key,
|
||||
keylet::bridge(bridge, STXChainBridge::ChainType::Issuing).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
23
src/tests/libxrpl/ledger/CheckEntry.cpp
Normal file
23
src/tests/libxrpl/ledger/CheckEntry.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <xrpl/ledger/entries/CheckEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(CheckEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const seq = SeqProxy::rawSequence(7);
|
||||
|
||||
expectKeylet<CheckEntry>(
|
||||
e, keylet::check(e.alice.id(), seq), "check(id, seq)", e.alice.id(), seq);
|
||||
|
||||
expectKeylet<CheckEntry>(e, keylet::check(e.someID()), "check(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
39
src/tests/libxrpl/ledger/CredentialEntry.cpp
Normal file
39
src/tests/libxrpl/ledger/CredentialEntry.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <xrpl/ledger/entries/CredentialEntry.h>
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(CredentialEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
std::string const credTypeStr = "termsandconditions";
|
||||
Slice const credType = makeSlice(credTypeStr);
|
||||
|
||||
expectKeylet<CredentialEntry>(
|
||||
e,
|
||||
keylet::credential(e.alice.id(), e.bob.id(), credType),
|
||||
"credential(subject, issuer, credType)",
|
||||
e.alice.id(),
|
||||
e.bob.id(),
|
||||
credType);
|
||||
|
||||
expectKeylet<CredentialEntry>(
|
||||
e, keylet::credential(e.someID()), "credential(uint256)", e.someID());
|
||||
|
||||
// Subject and issuer are both AccountIDs, so the assertion above only
|
||||
// has teeth if their order matters.
|
||||
EXPECT_NE(
|
||||
keylet::credential(e.alice.id(), e.bob.id(), credType).key,
|
||||
keylet::credential(e.bob.id(), e.alice.id(), credType).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
17
src/tests/libxrpl/ledger/DIDEntry.cpp
Normal file
17
src/tests/libxrpl/ledger/DIDEntry.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <xrpl/ledger/entries/DIDEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(DIDEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<DIDEntry>(e, keylet::did(e.alice.id()), "did(account)", e.alice.id());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
29
src/tests/libxrpl/ledger/DelegateEntry.cpp
Normal file
29
src/tests/libxrpl/ledger/DelegateEntry.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <xrpl/ledger/entries/DelegateEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(DelegateEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<DelegateEntry>(
|
||||
e,
|
||||
keylet::delegate(e.alice.id(), e.bob.id()),
|
||||
"delegate(account, authorizedAccount)",
|
||||
e.alice.id(),
|
||||
e.bob.id());
|
||||
|
||||
// Both arguments are AccountIDs, so the assertion above only has teeth
|
||||
// if their order matters.
|
||||
EXPECT_NE(
|
||||
keylet::delegate(e.alice.id(), e.bob.id()).key,
|
||||
keylet::delegate(e.bob.id(), e.alice.id()).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
54
src/tests/libxrpl/ledger/DepositPreauthEntry.cpp
Normal file
54
src/tests/libxrpl/ledger/DepositPreauthEntry.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <xrpl/ledger/entries/DepositPreauthEntry.h>
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(DepositPreauthEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
std::string const credTypeStr = "termsandconditions";
|
||||
std::set<std::pair<AccountID, Slice>> const authCreds{{e.bob.id(), makeSlice(credTypeStr)}};
|
||||
|
||||
expectKeylet<DepositPreauthEntry>(
|
||||
e,
|
||||
keylet::depositPreauth(e.alice.id(), e.bob.id()),
|
||||
"depositPreauth(owner, preauthorized)",
|
||||
e.alice.id(),
|
||||
e.bob.id());
|
||||
|
||||
expectKeylet<DepositPreauthEntry>(
|
||||
e,
|
||||
keylet::depositPreauth(e.alice.id(), authCreds),
|
||||
"depositPreauth(owner, authCreds)",
|
||||
e.alice.id(),
|
||||
authCreds);
|
||||
|
||||
expectKeylet<DepositPreauthEntry>(
|
||||
e, keylet::depositPreauth(e.someID()), "depositPreauth(uint256)", e.someID());
|
||||
|
||||
// Owner and preauthorized are both AccountIDs, so the assertion above
|
||||
// only has teeth if their order matters.
|
||||
EXPECT_NE(
|
||||
keylet::depositPreauth(e.alice.id(), e.bob.id()).key,
|
||||
keylet::depositPreauth(e.bob.id(), e.alice.id()).key);
|
||||
|
||||
// The credential-set overload must not collide with the single-account
|
||||
// one.
|
||||
EXPECT_NE(
|
||||
keylet::depositPreauth(e.alice.id(), authCreds).key,
|
||||
keylet::depositPreauth(e.alice.id(), e.bob.id()).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
28
src/tests/libxrpl/ledger/DirectoryNodeEntry.cpp
Normal file
28
src/tests/libxrpl/ledger/DirectoryNodeEntry.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <xrpl/ledger/entries/DirectoryNodeEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(DirectoryNodeEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<DirectoryNodeEntry>(
|
||||
e, keylet::ownerDir(e.alice.id()), "ownerDir(id)", e.alice.id());
|
||||
|
||||
expectKeylet<DirectoryNodeEntry>(
|
||||
e, keylet::page(e.someID(), 3u), "page(root, index)", e.someID(), std::uint64_t{3});
|
||||
|
||||
// The two overloads reach different keylet:: functions; a copy-paste
|
||||
// slip between them would be invisible otherwise.
|
||||
EXPECT_NE(keylet::ownerDir(e.alice.id()).key, keylet::page(e.someID(), 3u).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
123
src/tests/libxrpl/ledger/EntryTestHelpers.h
Normal file
123
src/tests/libxrpl/ledger/EntryTestHelpers.h
Normal file
@@ -0,0 +1,123 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ApplyViewImpl.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/LedgerHeader.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/Account.h>
|
||||
#include <helpers/TxTest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
/**
|
||||
* Scaffolding shared by the per-entry-type suites.
|
||||
*
|
||||
* Each of those suites needs the same three things: a ledger with a few funded
|
||||
* accounts, a throwaway ApplyView that is never applied, and some arbitrary
|
||||
* uint256 to stand in for an object ID. Build one of these per test case --
|
||||
* TxTest construction dominates the runtime of these tests by a wide margin,
|
||||
* and none of the assertions mutate the ledger.
|
||||
*/
|
||||
class EntryTestEnv
|
||||
{
|
||||
public:
|
||||
TxTest env;
|
||||
Account const alice{"alice"};
|
||||
Account const bob{"bob"};
|
||||
Account const carol{"carol"};
|
||||
|
||||
EntryTestEnv() : av_(&fundAndClose(), TapNone)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The closed ledger apply() was built over. Nothing here closes another
|
||||
* ledger or submits a transaction afterward, so this and apply() never
|
||||
* diverge.
|
||||
*/
|
||||
[[nodiscard]] ReadView const&
|
||||
read() const
|
||||
{
|
||||
return env.getClosedLedger();
|
||||
}
|
||||
|
||||
[[nodiscard]] ApplyView&
|
||||
apply()
|
||||
{
|
||||
return av_;
|
||||
}
|
||||
|
||||
/**
|
||||
* An arbitrary but stable uint256, for the entry constructors that take
|
||||
* an object ID directly. Nothing in the ledger has this key, which is the
|
||||
* point: those overloads should resolve to a non-existent entry.
|
||||
*/
|
||||
[[nodiscard]] uint256
|
||||
someID() const
|
||||
{
|
||||
return read().header().parentHash;
|
||||
}
|
||||
|
||||
private:
|
||||
// Runs from the av_ member initializer, so it may only touch env and the
|
||||
// accounts -- everything declared above av_.
|
||||
ReadView const&
|
||||
fundAndClose()
|
||||
{
|
||||
env.createAccount(alice, XRP(10'000));
|
||||
env.createAccount(bob, XRP(10'000));
|
||||
env.createAccount(carol, XRP(10'000));
|
||||
env.close();
|
||||
return env.getClosedLedger();
|
||||
}
|
||||
|
||||
ApplyViewImpl av_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assert that both flavors of @p Entry built from @p args resolve the ledger
|
||||
* object that @p expected names.
|
||||
*
|
||||
* The entry classes are near identical, so the defect they invite is a
|
||||
* copy-paste one: a constructor that reaches the wrong keylet:: function, or
|
||||
* that transposes two same-typed arguments. Comparing against an independently
|
||||
* spelled-out keylet at the call site catches exactly that.
|
||||
*
|
||||
* @p what names the overload under test, so a failure says which one broke.
|
||||
*/
|
||||
template <template <typename> class Entry, typename... Args>
|
||||
void
|
||||
expectKeylet(EntryTestEnv& e, Keylet const& expected, std::string const& what, Args const&... args)
|
||||
{
|
||||
bool const present = e.read().read(expected) != nullptr;
|
||||
|
||||
// The writable entry retains its keylet, so it can be inspected whether
|
||||
// or not the entry exists.
|
||||
Entry<ApplyView> const w(args..., e.apply());
|
||||
EXPECT_EQ(w.keylet().key, expected.key) << what << ": writable key";
|
||||
EXPECT_EQ(w.keylet().type, expected.type) << what << ": writable type";
|
||||
EXPECT_EQ(w.exists(), present) << what << ": writable exists";
|
||||
|
||||
// The read-only entry has no keylet of its own -- it derives one from the
|
||||
// SLE, and only when the SLE exists. Its agreement with a direct read
|
||||
// of the expected keylet is what shows it resolved the same key.
|
||||
Entry<ReadView> const r(args..., e.read());
|
||||
EXPECT_EQ(r.exists(), present) << what << ": read-only exists";
|
||||
if (present)
|
||||
{
|
||||
EXPECT_EQ(r.key(), expected.key) << what << ": read-only key";
|
||||
}
|
||||
|
||||
// Not r.type(): for a typed entry that returns kEntryType, so checking it
|
||||
// would just be this same assertion spelled twice.
|
||||
static_assert(Entry<ReadView>::kEntryType == Entry<ApplyView>::kEntryType);
|
||||
EXPECT_EQ(Entry<ReadView>::kEntryType, expected.type) << what << ": kEntryType";
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
21
src/tests/libxrpl/ledger/EscrowEntry.cpp
Normal file
21
src/tests/libxrpl/ledger/EscrowEntry.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <xrpl/ledger/entries/EscrowEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(EscrowEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const seq = SeqProxy::rawSequence(11);
|
||||
|
||||
expectKeylet<EscrowEntry>(
|
||||
e, keylet::escrow(e.alice.id(), seq), "escrow(src, seq)", e.alice.id(), seq);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
17
src/tests/libxrpl/ledger/FeeSettingsEntry.cpp
Normal file
17
src/tests/libxrpl/ledger/FeeSettingsEntry.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(FeeSettingsEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<FeeSettingsEntry>(e, keylet::feeSettings(), "feeSettings()");
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
17
src/tests/libxrpl/ledger/LedgerHashesEntry.cpp
Normal file
17
src/tests/libxrpl/ledger/LedgerHashesEntry.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <xrpl/ledger/entries/LedgerHashesEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(LedgerHashesEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<LedgerHashesEntry>(e, keylet::skip(), "skip()");
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
24
src/tests/libxrpl/ledger/LoanBrokerEntry.cpp
Normal file
24
src/tests/libxrpl/ledger/LoanBrokerEntry.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <xrpl/ledger/entries/LoanBrokerEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(LoanBrokerEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const seq = SeqProxy::rawSequence(5);
|
||||
|
||||
expectKeylet<LoanBrokerEntry>(
|
||||
e, keylet::loanBroker(e.alice.id(), seq), "loanBroker(owner, seq)", e.alice.id(), seq);
|
||||
|
||||
expectKeylet<LoanBrokerEntry>(
|
||||
e, keylet::loanBroker(e.someID()), "loanBroker(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
29
src/tests/libxrpl/ledger/LoanEntry.cpp
Normal file
29
src/tests/libxrpl/ledger/LoanEntry.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(LoanEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const seq = SeqProxy::rawSequence(9);
|
||||
|
||||
expectKeylet<LoanEntry>(
|
||||
e, keylet::loan(e.someID(), seq), "loan(loanBrokerID, loanSeq)", e.someID(), seq);
|
||||
|
||||
expectKeylet<LoanEntry>(e, keylet::loan(e.someID()), "loan(uint256)", e.someID());
|
||||
|
||||
// Both overloads start with the same uint256, so they must not produce
|
||||
// the same key -- otherwise arity is the only thing keeping them apart
|
||||
// and the test proves nothing.
|
||||
EXPECT_NE(keylet::loan(e.someID(), seq).key, keylet::loan(e.someID()).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
34
src/tests/libxrpl/ledger/MPTokenEntry.cpp
Normal file
34
src/tests/libxrpl/ledger/MPTokenEntry.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <xrpl/ledger/entries/MPTokenEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(MPTokenEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
MPTID const issuanceID = makeMptID(1, e.alice.id());
|
||||
|
||||
expectKeylet<MPTokenEntry>(
|
||||
e,
|
||||
keylet::mptoken(issuanceID, e.bob.id()),
|
||||
"mptoken(MPTID, holder)",
|
||||
issuanceID,
|
||||
e.bob.id());
|
||||
|
||||
expectKeylet<MPTokenEntry>(
|
||||
e,
|
||||
keylet::mptoken(e.someID(), e.bob.id()),
|
||||
"mptoken(issuanceKey, holder)",
|
||||
e.someID(),
|
||||
e.bob.id());
|
||||
|
||||
expectKeylet<MPTokenEntry>(e, keylet::mptoken(e.someID()), "mptoken(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
33
src/tests/libxrpl/ledger/MPTokenIssuanceEntry.cpp
Normal file
33
src/tests/libxrpl/ledger/MPTokenIssuanceEntry.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(MPTokenIssuanceEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
MPTID const issuanceID = makeMptID(1, e.alice.id());
|
||||
|
||||
expectKeylet<MPTokenIssuanceEntry>(
|
||||
e,
|
||||
keylet::mptokenIssuance(makeMptID(1, e.alice.id())),
|
||||
"mptokenIssuance(seq, issuer)",
|
||||
std::uint32_t{1},
|
||||
e.alice.id());
|
||||
|
||||
expectKeylet<MPTokenIssuanceEntry>(
|
||||
e, keylet::mptokenIssuance(issuanceID), "mptokenIssuance(MPTID)", issuanceID);
|
||||
|
||||
expectKeylet<MPTokenIssuanceEntry>(
|
||||
e, keylet::mptokenIssuance(e.someID()), "mptokenIssuance(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
24
src/tests/libxrpl/ledger/NFTokenOfferEntry.cpp
Normal file
24
src/tests/libxrpl/ledger/NFTokenOfferEntry.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <xrpl/ledger/entries/NFTokenOfferEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(NFTokenOfferEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const seq = SeqProxy::rawSequence(13);
|
||||
|
||||
expectKeylet<NFTokenOfferEntry>(
|
||||
e, keylet::nftokenOffer(e.alice.id(), seq), "nftokenOffer(owner, seq)", e.alice.id(), seq);
|
||||
|
||||
expectKeylet<NFTokenOfferEntry>(
|
||||
e, keylet::nftokenOffer(e.someID()), "nftokenOffer(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
25
src/tests/libxrpl/ledger/NFTokenPageEntry.cpp
Normal file
25
src/tests/libxrpl/ledger/NFTokenPageEntry.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <xrpl/ledger/entries/NFTokenPageEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(NFTokenPageEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
Keylet const pageMin = keylet::nftokenPageMin(e.alice.id());
|
||||
|
||||
expectKeylet<NFTokenPageEntry>(
|
||||
e,
|
||||
keylet::nftokenPage(pageMin, e.someID()),
|
||||
"nftokenPage(page, token)",
|
||||
pageMin,
|
||||
e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
17
src/tests/libxrpl/ledger/NegativeUNLEntry.cpp
Normal file
17
src/tests/libxrpl/ledger/NegativeUNLEntry.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <xrpl/ledger/entries/NegativeUNLEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(NegativeUNLEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<NegativeUNLEntry>(e, keylet::negativeUNL(), "negativeUNL()");
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
23
src/tests/libxrpl/ledger/OfferEntry.cpp
Normal file
23
src/tests/libxrpl/ledger/OfferEntry.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <xrpl/ledger/entries/OfferEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(OfferEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const seq = SeqProxy::rawSequence(3);
|
||||
|
||||
expectKeylet<OfferEntry>(
|
||||
e, keylet::offer(e.alice.id(), seq), "offer(id, seq)", e.alice.id(), seq);
|
||||
|
||||
expectKeylet<OfferEntry>(e, keylet::offer(e.someID()), "offer(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
24
src/tests/libxrpl/ledger/OracleEntry.cpp
Normal file
24
src/tests/libxrpl/ledger/OracleEntry.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <xrpl/ledger/entries/OracleEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(OracleEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<OracleEntry>(
|
||||
e,
|
||||
keylet::oracle(e.alice.id(), 7u),
|
||||
"oracle(account, documentID)",
|
||||
e.alice.id(),
|
||||
std::uint32_t{7});
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
33
src/tests/libxrpl/ledger/PayChannelEntry.cpp
Normal file
33
src/tests/libxrpl/ledger/PayChannelEntry.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <xrpl/ledger/entries/PayChannelEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(PayChannelEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const seq = SeqProxy::rawSequence(4);
|
||||
|
||||
expectKeylet<PayChannelEntry>(
|
||||
e,
|
||||
keylet::payChannel(e.alice.id(), e.bob.id(), seq),
|
||||
"payChannel(src, dst, seq)",
|
||||
e.alice.id(),
|
||||
e.bob.id(),
|
||||
seq);
|
||||
|
||||
// Source and destination are both AccountIDs, so the assertion above
|
||||
// only has teeth if their order matters.
|
||||
EXPECT_NE(
|
||||
keylet::payChannel(e.alice.id(), e.bob.id(), seq).key,
|
||||
keylet::payChannel(e.bob.id(), e.alice.id(), seq).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
28
src/tests/libxrpl/ledger/PermissionedDomainEntry.cpp
Normal file
28
src/tests/libxrpl/ledger/PermissionedDomainEntry.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(PermissionedDomainEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const seq = SeqProxy::rawSequence(6);
|
||||
|
||||
expectKeylet<PermissionedDomainEntry>(
|
||||
e,
|
||||
keylet::permissionedDomain(e.alice.id(), seq),
|
||||
"permissionedDomain(account, seq)",
|
||||
e.alice.id(),
|
||||
seq);
|
||||
|
||||
expectKeylet<PermissionedDomainEntry>(
|
||||
e, keylet::permissionedDomain(e.someID()), "permissionedDomain(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
43
src/tests/libxrpl/ledger/RippleStateEntry.cpp
Normal file
43
src/tests/libxrpl/ledger/RippleStateEntry.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <xrpl/ledger/entries/RippleStateEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/IOU.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(RippleStateEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
IOU const usd("USD", e.alice);
|
||||
Currency const currency = usd.currency();
|
||||
|
||||
expectKeylet<RippleStateEntry>(
|
||||
e,
|
||||
keylet::trustLine(e.alice.id(), e.bob.id(), currency),
|
||||
"trustLine(id0, id1, currency)",
|
||||
e.alice.id(),
|
||||
e.bob.id(),
|
||||
currency);
|
||||
|
||||
expectKeylet<RippleStateEntry>(
|
||||
e,
|
||||
keylet::trustLine(e.bob.id(), usd.issue()),
|
||||
"trustLine(id, issue)",
|
||||
e.bob.id(),
|
||||
usd.issue());
|
||||
|
||||
// Trust lines are deliberately symmetric in their two accounts -- the
|
||||
// keylet canonicalizes them -- so unlike the other two-account entries
|
||||
// there is no transposition to catch here.
|
||||
EXPECT_EQ(
|
||||
keylet::trustLine(e.alice.id(), e.bob.id(), currency).key,
|
||||
keylet::trustLine(e.bob.id(), e.alice.id(), currency).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
428
src/tests/libxrpl/ledger/SLEBase.cpp
Normal file
428
src/tests/libxrpl/ledger/SLEBase.cpp
Normal file
@@ -0,0 +1,428 @@
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ApplyViewImpl.h>
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/AMMEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||
#include <xrpl/ledger/entries/AmendmentsEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/BridgeEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/CheckEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/CredentialEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/DIDEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/DelegateEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/DepositPreauthEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/DirectoryNodeEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/EscrowEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/FeeSettingsEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/LedgerHashesEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/LoanBrokerEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/LoanEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/MPTokenEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/NFTokenOfferEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/NFTokenPageEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/NegativeUNLEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/OfferEntry.h>
|
||||
#include <xrpl/ledger/entries/OracleEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/PayChannelEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/PermissionedDomainEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/RippleStateEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/SignerListEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/SponsorshipEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/TicketEntry.h>
|
||||
#include <xrpl/ledger/entries/VaultEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/XChainOwnedClaimIDEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/XChainOwnedCreateAccountClaimIDEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/protocol_autogen/transactions/AccountSet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/Account.h>
|
||||
#include <helpers/TxTest.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// The entry classes have no consumers yet, and an un-instantiated class
|
||||
// template is barely type-checked. Instantiate every one explicitly so the
|
||||
// compiler actually checks them. Keep this block even once real call sites
|
||||
// exist: it is what catches a new ledger entry type being added without its
|
||||
// wrapper class, or the wrapper class existing but never actually being used.
|
||||
//
|
||||
// Driving this off ledger_entries.macro keeps it exhaustive by construction:
|
||||
// adding a ledger entry type without adding its entry class stops compiling
|
||||
// here, and the static_assert pins each one to the right LedgerEntryType.
|
||||
//
|
||||
// Keep this loop in one file rather than splitting it across the per-entry
|
||||
// *Entry_test.cpp suites. Those are hand-written, so a new ledger entry type
|
||||
// would simply have no file there and nothing would complain; this is the only
|
||||
// thing making the coverage exhaustive rather than merely extensive.
|
||||
|
||||
template class SLEBase<ReadView>;
|
||||
template class SLEBase<ApplyView>;
|
||||
|
||||
#pragma push_macro("LEDGER_ENTRY")
|
||||
#undef LEDGER_ENTRY
|
||||
|
||||
#define LEDGER_ENTRY(tag, value, name, ...) \
|
||||
template class name##Entry<ReadView>; \
|
||||
template class name##Entry<ApplyView>; \
|
||||
static_assert( \
|
||||
name##Entry<ReadView>::kEntryType == tag && name##Entry<ApplyView>::kEntryType == tag, \
|
||||
#name "Entry must be bound to " #tag);
|
||||
|
||||
#include <xrpl/protocol/detail/ledger_entries.macro>
|
||||
|
||||
#undef LEDGER_ENTRY
|
||||
#pragma pop_macro("LEDGER_ENTRY")
|
||||
|
||||
// --- Entry-type safety, checked at compile time. ---
|
||||
//
|
||||
// The writable -> read-only converting constructor is inherited into every
|
||||
// per-type entry, so without the entry-type constraint it will bind any
|
||||
// writable entry that slices to SLEBase. These assertions pin down which
|
||||
// conversions are legal.
|
||||
|
||||
// An entry class for one entry type must never be constructible from another.
|
||||
static_assert(
|
||||
!std::is_convertible_v<OfferEntryW, AccountRootEntryR>,
|
||||
"cross-entry-type conversion must not compile");
|
||||
static_assert(
|
||||
!std::is_constructible_v<AccountRootEntryR, OfferEntryW>,
|
||||
"cross-entry-type construction must not compile, even explicitly");
|
||||
static_assert(
|
||||
!std::is_convertible_v<OfferEntryR, AccountRootEntryR>,
|
||||
"read-only cross-entry-type conversion must not compile");
|
||||
|
||||
// Nor from a type-erased writable entry, which carries no static type.
|
||||
static_assert(
|
||||
!std::is_convertible_v<WritableSLE, AccountRootEntryR>,
|
||||
"generic -> typed conversion must not compile");
|
||||
|
||||
// The intended conversions must keep working: same type writable -> read-only,
|
||||
// and typed -> generic widening.
|
||||
static_assert(
|
||||
std::is_convertible_v<AccountRootEntryW, AccountRootEntryR>,
|
||||
"same-type writable -> read-only conversion must keep working");
|
||||
static_assert(
|
||||
std::is_convertible_v<AccountRootEntryW, ReadOnlySLE>,
|
||||
"typed -> generic widening must keep working");
|
||||
|
||||
// Detection idioms for the writable interface. These have to go through a
|
||||
// template parameter: a requires-expression over a concrete type is checked
|
||||
// eagerly, so spelling the calls out inline would be a hard error rather than
|
||||
// the `false` the assertions below want.
|
||||
template <typename T>
|
||||
concept HasMutableRawSle = requires(T& t) { t.mutableRawSle(); };
|
||||
|
||||
template <typename T>
|
||||
concept HasApplyView = requires(T& t) { t.applyView(); };
|
||||
|
||||
namespace test {
|
||||
|
||||
/**
|
||||
* Scaffolding shared by the test cases below: a funded alice, an unfunded bob
|
||||
* (for the entries that need to resolve to nothing), and the TxTest ledger
|
||||
* they live in.
|
||||
*/
|
||||
class SLEBaseTests : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
TxTest env_;
|
||||
Account const alice_{"alice"};
|
||||
Account const bob_{"bob"};
|
||||
|
||||
SLEBaseTests()
|
||||
{
|
||||
env_.createAccount(alice_, XRP(10'000));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SLEBaseTests, ReadOnly)
|
||||
{
|
||||
AccountRootEntryR const absent(bob_.id(), env_.getClosedLedger());
|
||||
EXPECT_FALSE(absent.exists());
|
||||
EXPECT_FALSE(static_cast<bool>(absent));
|
||||
// A typed entry knows its entry type even with nothing to read.
|
||||
EXPECT_EQ(absent.type(), ltACCOUNT_ROOT);
|
||||
|
||||
AccountRootEntryR const present(alice_.id(), env_.getClosedLedger());
|
||||
EXPECT_TRUE(present.exists());
|
||||
EXPECT_TRUE(static_cast<bool>(present));
|
||||
EXPECT_EQ(present.key(), keylet::account(alice_.id()).key);
|
||||
EXPECT_EQ(present.type(), ltACCOUNT_ROOT);
|
||||
EXPECT_EQ(present.keylet().type, ltACCOUNT_ROOT);
|
||||
EXPECT_EQ(present->getType(), ltACCOUNT_ROOT);
|
||||
EXPECT_EQ((*present).getType(), ltACCOUNT_ROOT);
|
||||
EXPECT_EQ(&present.readView(), &env_.getClosedLedger());
|
||||
}
|
||||
|
||||
TEST_F(SLEBaseTests, AdoptSLE)
|
||||
{
|
||||
auto const sle = env_.getClosedLedger().read(keylet::account(alice_.id()));
|
||||
ASSERT_NE(sle, nullptr);
|
||||
|
||||
AccountRootEntryR const adopted(sle, env_.getClosedLedger());
|
||||
EXPECT_TRUE(adopted.exists());
|
||||
EXPECT_EQ(adopted.rawSle(), sle);
|
||||
EXPECT_EQ(adopted.key(), keylet::account(alice_.id()).key);
|
||||
EXPECT_EQ(adopted.type(), ltACCOUNT_ROOT);
|
||||
// keylet() reports the SLE's own type, not the entry's static binding, so
|
||||
// it stays truthful in a Release build where the constructor's
|
||||
// entry-type assert is compiled out.
|
||||
EXPECT_EQ(adopted.keylet().type, ltACCOUNT_ROOT);
|
||||
|
||||
// Adopting a null SLE is allowed: the assert only fires on a
|
||||
// type mismatch, and a null pointer has no type to mismatch.
|
||||
AccountRootEntryR const empty(SLE::const_pointer{}, env_.getClosedLedger());
|
||||
EXPECT_FALSE(empty.exists());
|
||||
EXPECT_EQ(empty.type(), ltACCOUNT_ROOT);
|
||||
|
||||
// A generic entry adopting the same SLE has to read the type back.
|
||||
ReadOnlySLE const generic(sle, env_.getClosedLedger());
|
||||
EXPECT_TRUE(generic.exists());
|
||||
EXPECT_EQ(generic.type(), ltACCOUNT_ROOT);
|
||||
EXPECT_EQ(generic.keylet().type, ltACCOUNT_ROOT);
|
||||
|
||||
// There is deliberately no writable equivalent.
|
||||
static_assert(
|
||||
!std::is_constructible_v<AccountRootEntryW, SLE::pointer, ApplyView&>,
|
||||
"writable entries must not be constructible from a bare SLE");
|
||||
}
|
||||
|
||||
TEST_F(SLEBaseTests, WritableAccessors)
|
||||
{
|
||||
ApplyViewImpl av(&env_.getClosedLedger(), TapNone);
|
||||
beast::Journal const j{beast::Journal::getNullSink()};
|
||||
|
||||
AccountRootEntryW account(alice_.id(), av, j);
|
||||
EXPECT_TRUE(account.exists());
|
||||
EXPECT_EQ(account.mutableRawSle(), account.rawSle());
|
||||
EXPECT_EQ(&account.applyView(), &av);
|
||||
EXPECT_EQ(&account.readView(), static_cast<ReadView const*>(&av));
|
||||
EXPECT_EQ(&account.journal().sink(), &j.sink());
|
||||
|
||||
// The mutable dereference operators reach the same entry.
|
||||
EXPECT_EQ(account.operator->(), account.rawSle().get());
|
||||
EXPECT_EQ(&*account, account.rawSle().get());
|
||||
|
||||
// Everything handing out mutable access is non-const, so a const
|
||||
// writable entry is as inert as a read-only one.
|
||||
static_assert(HasMutableRawSle<AccountRootEntryW>);
|
||||
static_assert(HasApplyView<AccountRootEntryW>);
|
||||
static_assert(
|
||||
!HasMutableRawSle<AccountRootEntryW const>,
|
||||
"mutableRawSle() must not be callable on a const writable entry");
|
||||
static_assert(
|
||||
!HasApplyView<AccountRootEntryW const>,
|
||||
"applyView() must not be callable on a const writable entry");
|
||||
|
||||
// Read-only entries do not have the writable interface at all.
|
||||
static_assert(
|
||||
!HasMutableRawSle<AccountRootEntryR>,
|
||||
"mutableRawSle() must not exist on a read-only entry");
|
||||
static_assert(
|
||||
!HasApplyView<AccountRootEntryR>, "applyView() must not exist on a read-only entry");
|
||||
}
|
||||
|
||||
TEST_F(SLEBaseTests, ApplyViewContextCtor)
|
||||
{
|
||||
ApplyViewImpl av(&env_.getClosedLedger(), TapNone);
|
||||
beast::Journal const j{beast::Journal::getNullSink()};
|
||||
|
||||
transactions::AccountSetBuilder builder{alice_.id()};
|
||||
builder.setSequence(env_.getAccountRoot(alice_.id()).getSequence());
|
||||
builder.setFee(XRPAmount(10));
|
||||
auto const tx = builder.build(alice_.pk(), alice_.sk()).getSTTx();
|
||||
ASSERT_NE(tx, nullptr);
|
||||
ApplyViewContext const ctx{.view = av, .tx = *tx};
|
||||
|
||||
// Delegates to the (Keylet, ApplyView&) constructor; ctx.tx is not
|
||||
// retained, so this must be indistinguishable from building from
|
||||
// ctx.view directly.
|
||||
AccountRootEntryW fromCtx(keylet::account(alice_.id()), ctx, j);
|
||||
EXPECT_TRUE(fromCtx.exists());
|
||||
EXPECT_EQ(&fromCtx.applyView(), &av);
|
||||
EXPECT_EQ(fromCtx.key(), keylet::account(alice_.id()).key);
|
||||
|
||||
AccountRootEntryW const fromView(keylet::account(alice_.id()), av, j);
|
||||
EXPECT_EQ(fromCtx.rawSle(), fromView.rawSle());
|
||||
}
|
||||
|
||||
TEST_F(SLEBaseTests, WritableLifecycle)
|
||||
{
|
||||
// A view we never apply, so nothing here reaches the ledger.
|
||||
ApplyViewImpl av(&env_.getClosedLedger(), TapNone);
|
||||
|
||||
// Entry that does not exist yet: newSLE() -> insert().
|
||||
{
|
||||
TicketEntryW ticket(keylet::ticket(alice_.id(), SeqProxy::rawTicket(1)), av);
|
||||
EXPECT_FALSE(ticket.exists());
|
||||
EXPECT_EQ(ticket.key(), keylet::ticket(alice_.id(), SeqProxy::rawTicket(1)).key);
|
||||
EXPECT_EQ(ticket.type(), ltTICKET);
|
||||
EXPECT_EQ(ticket.keylet().type, ltTICKET);
|
||||
|
||||
ticket.newSLE();
|
||||
EXPECT_TRUE(ticket.exists());
|
||||
ticket.insert();
|
||||
ticket.update();
|
||||
|
||||
// Erasing an entry inserted in this same view drops it outright.
|
||||
ticket.erase();
|
||||
EXPECT_FALSE(ticket.exists());
|
||||
}
|
||||
|
||||
// Entry that already exists: update() is what promotes it from a bare
|
||||
// peek to a real change. ApplyViewImpl::size() counts Insert, Modify and
|
||||
// Erase but not Cache, so it shows the difference: building the entry
|
||||
// only peeks, and the write is invisible to the view until update().
|
||||
{
|
||||
ApplyViewImpl fresh(&env_.getClosedLedger(), TapNone);
|
||||
|
||||
AccountRootEntryW account(alice_.id(), fresh);
|
||||
EXPECT_TRUE(account.exists());
|
||||
EXPECT_EQ(fresh.size(), 0);
|
||||
|
||||
account->setFieldU32(sfSequence, account->getFieldU32(sfSequence) + 1);
|
||||
EXPECT_EQ(fresh.size(), 0);
|
||||
|
||||
account.update();
|
||||
EXPECT_EQ(fresh.size(), 1);
|
||||
|
||||
// update() is idempotent: the entry is already a Modify.
|
||||
account.update();
|
||||
EXPECT_EQ(fresh.size(), 1);
|
||||
}
|
||||
|
||||
// Entry that already exists. ApplyStateTable::erase() keeps holding
|
||||
// this exact SLE and builds the DeletedNode's FinalFields from it, so
|
||||
// the entry must drop its pointer or a later write would silently
|
||||
// land in transaction metadata.
|
||||
{
|
||||
AccountRootEntryW account(alice_.id(), av);
|
||||
EXPECT_TRUE(account.exists());
|
||||
|
||||
account.erase();
|
||||
EXPECT_FALSE(account.exists());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SLEBaseTests, Conversion)
|
||||
{
|
||||
ApplyViewImpl av(&env_.getClosedLedger(), TapNone);
|
||||
|
||||
AccountRootEntryW const writable(alice_.id(), av);
|
||||
EXPECT_TRUE(writable.exists());
|
||||
|
||||
AccountRootEntryR const readOnly = writable;
|
||||
EXPECT_TRUE(readOnly.exists());
|
||||
EXPECT_EQ(readOnly.rawSle(), writable.rawSle());
|
||||
|
||||
ReadOnlySLE const generic = writable;
|
||||
EXPECT_TRUE(generic.exists());
|
||||
EXPECT_EQ(generic.rawSle(), writable.rawSle());
|
||||
// A generic entry has to read the type back out of the SLE.
|
||||
EXPECT_EQ(generic.type(), ltACCOUNT_ROOT);
|
||||
}
|
||||
|
||||
TEST_F(SLEBaseTests, ResolveEntryPeeks)
|
||||
{
|
||||
// getOpenLedger() is an OpenView, which derives from ReadView but not
|
||||
// from ApplyView, so resolveEntry's dynamic_cast fails and this takes
|
||||
// the plain ReadView::read() path.
|
||||
OpenView const& ledger = env_.getOpenLedger();
|
||||
AccountRootEntryR const overLedger(alice_.id(), ledger);
|
||||
EXPECT_TRUE(overLedger.exists());
|
||||
|
||||
ApplyViewImpl av(&ledger, TapNone);
|
||||
|
||||
// ReadView const& binds an ApplyViewImpl just as happily, and there the
|
||||
// dynamic_cast succeeds, so this one resolves through ApplyView::peek().
|
||||
AccountRootEntryR const readOnly(alice_.id(), av);
|
||||
EXPECT_TRUE(readOnly.exists());
|
||||
|
||||
AccountRootEntryW writable(alice_.id(), av);
|
||||
EXPECT_TRUE(writable.exists());
|
||||
|
||||
// The invariant resolveEntry() exists to hold: one SLE per key per
|
||||
// view. read() would have handed back the base ledger's entry instead,
|
||||
// which is a different object.
|
||||
EXPECT_EQ(readOnly.rawSle(), writable.rawSle());
|
||||
EXPECT_NE(readOnly.rawSle(), overLedger.rawSle());
|
||||
|
||||
// Which is what keeps a read-only entry from going stale: a write
|
||||
// through any other entry over the same view is visible through it.
|
||||
auto const bumped = writable->getFieldU32(sfSequence) + 1;
|
||||
writable->setFieldU32(sfSequence, bumped);
|
||||
EXPECT_EQ(readOnly->getFieldU32(sfSequence), bumped);
|
||||
}
|
||||
|
||||
TEST_F(SLEBaseTests, ThrowsOnMissingEntry)
|
||||
{
|
||||
// A generic read-only entry has no static type to fall back on, so
|
||||
// type() must read it off the (absent) SLE and throw.
|
||||
ReadOnlySLE const absent(keylet::account(bob_.id()), env_.getClosedLedger());
|
||||
EXPECT_FALSE(absent.exists());
|
||||
EXPECT_THROW(std::ignore = absent.type(), std::logic_error);
|
||||
|
||||
// A per-type read-only entry always knows its type, but keylet() and
|
||||
// key() still have to derive the ledger key from the SLE.
|
||||
AccountRootEntryR const missing(bob_.id(), env_.getClosedLedger());
|
||||
EXPECT_FALSE(missing.exists());
|
||||
EXPECT_THROW(std::ignore = missing.key(), std::logic_error);
|
||||
EXPECT_THROW(std::ignore = missing.keylet(), std::logic_error);
|
||||
|
||||
// Dereferencing an absent entry throws rather than handing back a null
|
||||
// pointer for the caller to walk into.
|
||||
EXPECT_THROW(std::ignore = missing.operator->(), std::logic_error);
|
||||
EXPECT_THROW(std::ignore = (*missing).getType(), std::logic_error);
|
||||
}
|
||||
|
||||
TEST_F(SLEBaseTests, ThrowsOnMissingWritableEntry)
|
||||
{
|
||||
// A view we never apply, so nothing here reaches the ledger.
|
||||
ApplyViewImpl av(&env_.getClosedLedger(), TapNone);
|
||||
|
||||
// bob is unfunded, so this resolves to nothing and every operation that
|
||||
// needs an SLE has to throw instead of dereferencing null. These are the
|
||||
// cases a Release build used to walk straight past, back when they were
|
||||
// XRPL_ASSERTs.
|
||||
AccountRootEntryW missing(bob_.id(), av);
|
||||
EXPECT_FALSE(missing.exists());
|
||||
|
||||
EXPECT_THROW(std::ignore = missing.operator->(), std::logic_error);
|
||||
EXPECT_THROW(std::ignore = (*missing).getType(), std::logic_error);
|
||||
EXPECT_THROW(missing.insert(), std::logic_error);
|
||||
EXPECT_THROW(missing.update(), std::logic_error);
|
||||
EXPECT_THROW(missing.erase(), std::logic_error);
|
||||
|
||||
// keylet() and key() are the exception: a writable entry keeps the keylet
|
||||
// it was built from, so they stay valid before newSLE().
|
||||
EXPECT_EQ(missing.key(), keylet::account(bob_.id()).key);
|
||||
|
||||
// newSLE() is the inverse -- it throws when the entry *does* exist,
|
||||
// rather than silently dropping the SLE already held.
|
||||
missing.newSLE();
|
||||
EXPECT_TRUE(missing.exists());
|
||||
EXPECT_THROW(missing.newSLE(), std::logic_error);
|
||||
|
||||
// And once erased, the entry is empty again and throws as before.
|
||||
missing.insert();
|
||||
missing.erase();
|
||||
EXPECT_FALSE(missing.exists());
|
||||
EXPECT_THROW(missing.update(), std::logic_error);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace xrpl
|
||||
18
src/tests/libxrpl/ledger/SignerListEntry.cpp
Normal file
18
src/tests/libxrpl/ledger/SignerListEntry.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <xrpl/ledger/entries/SignerListEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(SignerListEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<SignerListEntry>(
|
||||
e, keylet::signerList(e.alice.id()), "signerList(account)", e.alice.id());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
29
src/tests/libxrpl/ledger/SponsorshipEntry.cpp
Normal file
29
src/tests/libxrpl/ledger/SponsorshipEntry.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <xrpl/ledger/entries/SponsorshipEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(SponsorshipEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
expectKeylet<SponsorshipEntry>(
|
||||
e,
|
||||
keylet::sponsorship(e.alice.id(), e.bob.id()),
|
||||
"sponsorship(sponsor, sponsee)",
|
||||
e.alice.id(),
|
||||
e.bob.id());
|
||||
|
||||
// Sponsor and sponsee are both AccountIDs, so the assertion above only
|
||||
// has teeth if their order matters.
|
||||
EXPECT_NE(
|
||||
keylet::sponsorship(e.alice.id(), e.bob.id()).key,
|
||||
keylet::sponsorship(e.bob.id(), e.alice.id()).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
27
src/tests/libxrpl/ledger/TicketEntry.cpp
Normal file
27
src/tests/libxrpl/ledger/TicketEntry.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <xrpl/ledger/entries/TicketEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(TicketEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const ticketSeq = SeqProxy::rawTicket(2);
|
||||
|
||||
expectKeylet<TicketEntry>(
|
||||
e,
|
||||
keylet::ticket(e.alice.id(), ticketSeq),
|
||||
"ticket(id, ticketSeq)",
|
||||
e.alice.id(),
|
||||
ticketSeq);
|
||||
|
||||
expectKeylet<TicketEntry>(e, keylet::ticket(e.someID()), "ticket(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
23
src/tests/libxrpl/ledger/VaultEntry.cpp
Normal file
23
src/tests/libxrpl/ledger/VaultEntry.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <xrpl/ledger/entries/VaultEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(VaultEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
SeqProxy const seq = SeqProxy::rawSequence(8);
|
||||
|
||||
expectKeylet<VaultEntry>(
|
||||
e, keylet::vault(e.alice.id(), seq), "vault(owner, seq)", e.alice.id(), seq);
|
||||
|
||||
expectKeylet<VaultEntry>(e, keylet::vault(e.someID()), "vault(uint256)", e.someID());
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
29
src/tests/libxrpl/ledger/XChainOwnedClaimIDEntry.cpp
Normal file
29
src/tests/libxrpl/ledger/XChainOwnedClaimIDEntry.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <xrpl/ledger/entries/XChainOwnedClaimIDEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/IOU.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(XChainOwnedClaimIDEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
STXChainBridge const bridge{e.alice.id(), xrpIssue(), e.bob.id(), IOU("USD", e.bob).issue()};
|
||||
|
||||
expectKeylet<XChainOwnedClaimIDEntry>(
|
||||
e,
|
||||
keylet::xChainClaimID(bridge, 5u),
|
||||
"xChainClaimID(bridge, seq)",
|
||||
bridge,
|
||||
std::uint64_t{5});
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <xrpl/ledger/entries/XChainOwnedCreateAccountClaimIDEntry.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/IOU.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
TEST(XChainOwnedCreateAccountClaimIDEntryTests, Constructors)
|
||||
{
|
||||
EntryTestEnv e;
|
||||
|
||||
STXChainBridge const bridge{e.alice.id(), xrpIssue(), e.bob.id(), IOU("USD", e.bob).issue()};
|
||||
|
||||
expectKeylet<XChainOwnedCreateAccountClaimIDEntry>(
|
||||
e,
|
||||
keylet::xChainCreateAccountClaimID(bridge, 5u),
|
||||
"xChainCreateAccountClaimID(bridge, seq)",
|
||||
bridge,
|
||||
std::uint64_t{5});
|
||||
|
||||
// Must not collide with the plain claim-ID keylet, which takes the same
|
||||
// arguments.
|
||||
EXPECT_NE(
|
||||
keylet::xChainCreateAccountClaimID(bridge, 5u).key, keylet::xChainClaimID(bridge, 5u).key);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
Reference in New Issue
Block a user