mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-11 06:35:51 +00:00
Compare commits
2 Commits
a1q123456/
...
a1q123456/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac55c8725c | ||
|
|
793768a7ba |
@@ -1,74 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/XRPLF/rippled/
|
|
||||||
Copyright (c) 2023 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <xrpl/beast/unit_test.h>
|
|
||||||
#include <xrpl/beast/unit_test/suite.h>
|
|
||||||
#include <xrpl/protocol/ApiVersion.h>
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <limits>
|
|
||||||
#include <optional>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
namespace test {
|
|
||||||
struct ApiVersion_test : beast::unit_test::suite
|
|
||||||
{
|
|
||||||
void
|
|
||||||
run() override
|
|
||||||
{
|
|
||||||
{
|
|
||||||
testcase("API versions invariants");
|
|
||||||
|
|
||||||
static_assert(
|
|
||||||
RPC::apiMinimumSupportedVersion <=
|
|
||||||
RPC::apiMaximumSupportedVersion);
|
|
||||||
static_assert(
|
|
||||||
RPC::apiMinimumSupportedVersion <= RPC::apiMaximumValidVersion);
|
|
||||||
static_assert(
|
|
||||||
RPC::apiMaximumSupportedVersion <= RPC::apiMaximumValidVersion);
|
|
||||||
static_assert(RPC::apiBetaVersion <= RPC::apiMaximumValidVersion);
|
|
||||||
|
|
||||||
BEAST_EXPECT(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Update when we change versions
|
|
||||||
testcase("API versions");
|
|
||||||
|
|
||||||
static_assert(RPC::apiMinimumSupportedVersion >= 1);
|
|
||||||
static_assert(RPC::apiMinimumSupportedVersion < 2);
|
|
||||||
static_assert(RPC::apiMaximumSupportedVersion >= 2);
|
|
||||||
static_assert(RPC::apiMaximumSupportedVersion < 3);
|
|
||||||
static_assert(RPC::apiMaximumValidVersion >= 3);
|
|
||||||
static_assert(RPC::apiMaximumValidVersion < 4);
|
|
||||||
static_assert(RPC::apiBetaVersion >= 3);
|
|
||||||
static_assert(RPC::apiBetaVersion < 4);
|
|
||||||
|
|
||||||
BEAST_EXPECT(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(ApiVersion, protocol, ripple);
|
|
||||||
|
|
||||||
} // namespace test
|
|
||||||
} // namespace ripple
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2020 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <xrpl/beast/unit_test.h>
|
|
||||||
#include <xrpl/protocol/BuildInfo.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
class BuildInfo_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void
|
|
||||||
testEncodeSoftwareVersion()
|
|
||||||
{
|
|
||||||
testcase("EncodeSoftwareVersion");
|
|
||||||
|
|
||||||
auto encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b7");
|
|
||||||
|
|
||||||
// the first two bytes identify the particular implementation, 0x183B
|
|
||||||
BEAST_EXPECT(
|
|
||||||
(encodedVersion & 0xFFFF'0000'0000'0000LLU) ==
|
|
||||||
0x183B'0000'0000'0000LLU);
|
|
||||||
|
|
||||||
// the next three bytes: major version, minor version, patch version,
|
|
||||||
// 0x010203
|
|
||||||
BEAST_EXPECT(
|
|
||||||
(encodedVersion & 0x0000'FFFF'FF00'0000LLU) ==
|
|
||||||
0x0000'0102'0300'0000LLU);
|
|
||||||
|
|
||||||
// the next two bits:
|
|
||||||
{
|
|
||||||
// 01 if a beta
|
|
||||||
BEAST_EXPECT(
|
|
||||||
(encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b01);
|
|
||||||
// 10 if an RC
|
|
||||||
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.4-rc7");
|
|
||||||
BEAST_EXPECT(
|
|
||||||
(encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b10);
|
|
||||||
// 11 if neither an RC nor a beta
|
|
||||||
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.5");
|
|
||||||
BEAST_EXPECT(
|
|
||||||
(encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b11);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the next six bits: rc/beta number (1-63)
|
|
||||||
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.6-b63");
|
|
||||||
BEAST_EXPECT((encodedVersion & 0x0000'0000'003F'0000LLU) >> 16 == 63);
|
|
||||||
|
|
||||||
// the last two bytes are zeros
|
|
||||||
BEAST_EXPECT((encodedVersion & 0x0000'0000'0000'FFFFLLU) == 0);
|
|
||||||
|
|
||||||
// Test some version strings with wrong formats:
|
|
||||||
// no rc/beta number
|
|
||||||
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b");
|
|
||||||
BEAST_EXPECT((encodedVersion & 0x0000'0000'00FF'0000LLU) == 0);
|
|
||||||
// rc/beta number out of range
|
|
||||||
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b64");
|
|
||||||
BEAST_EXPECT((encodedVersion & 0x0000'0000'00FF'0000LLU) == 0);
|
|
||||||
|
|
||||||
// Check that the rc/beta number of a release is 0:
|
|
||||||
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.6");
|
|
||||||
BEAST_EXPECT((encodedVersion & 0x0000'0000'003F'0000LLU) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testIsRippledVersion()
|
|
||||||
{
|
|
||||||
testcase("IsRippledVersion");
|
|
||||||
auto vFF = 0xFFFF'FFFF'FFFF'FFFFLLU;
|
|
||||||
BEAST_EXPECT(!BuildInfo::isRippledVersion(vFF));
|
|
||||||
auto vRippled = 0x183B'0000'0000'0000LLU;
|
|
||||||
BEAST_EXPECT(BuildInfo::isRippledVersion(vRippled));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testIsNewerVersion()
|
|
||||||
{
|
|
||||||
testcase("IsNewerVersion");
|
|
||||||
auto vFF = 0xFFFF'FFFF'FFFF'FFFFLLU;
|
|
||||||
BEAST_EXPECT(!BuildInfo::isNewerVersion(vFF));
|
|
||||||
|
|
||||||
auto v159 = BuildInfo::encodeSoftwareVersion("1.5.9");
|
|
||||||
BEAST_EXPECT(!BuildInfo::isNewerVersion(v159));
|
|
||||||
|
|
||||||
auto vCurrent = BuildInfo::getEncodedVersion();
|
|
||||||
BEAST_EXPECT(!BuildInfo::isNewerVersion(vCurrent));
|
|
||||||
|
|
||||||
auto vMax = BuildInfo::encodeSoftwareVersion("255.255.255");
|
|
||||||
BEAST_EXPECT(BuildInfo::isNewerVersion(vMax));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
run() override
|
|
||||||
{
|
|
||||||
testEncodeSoftwareVersion();
|
|
||||||
testIsRippledVersion();
|
|
||||||
testIsNewerVersion();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(BuildInfo, protocol, ripple);
|
|
||||||
} // namespace ripple
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012-2017 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <test/jtx.h>
|
|
||||||
|
|
||||||
#include <xrpl/protocol/Feature.h>
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
class Hooks_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This unit test was requested here:
|
|
||||||
* https://github.com/ripple/rippled/pull/4089#issuecomment-1050274539
|
|
||||||
* These are tests that exercise facilities that are reserved for when Hooks
|
|
||||||
* is merged in the future.
|
|
||||||
**/
|
|
||||||
|
|
||||||
void
|
|
||||||
testHookFields()
|
|
||||||
{
|
|
||||||
testcase("Test Hooks fields");
|
|
||||||
|
|
||||||
using namespace test::jtx;
|
|
||||||
|
|
||||||
std::vector<std::reference_wrapper<SField const>> fields_to_test = {
|
|
||||||
sfHookResult,
|
|
||||||
sfHookStateChangeCount,
|
|
||||||
sfHookEmitCount,
|
|
||||||
sfHookExecutionIndex,
|
|
||||||
sfHookApiVersion,
|
|
||||||
sfHookStateCount,
|
|
||||||
sfEmitGeneration,
|
|
||||||
sfHookOn,
|
|
||||||
sfHookInstructionCount,
|
|
||||||
sfEmitBurden,
|
|
||||||
sfHookReturnCode,
|
|
||||||
sfReferenceCount,
|
|
||||||
sfEmitParentTxnID,
|
|
||||||
sfEmitNonce,
|
|
||||||
sfEmitHookHash,
|
|
||||||
sfHookStateKey,
|
|
||||||
sfHookHash,
|
|
||||||
sfHookNamespace,
|
|
||||||
sfHookSetTxnID,
|
|
||||||
sfHookStateData,
|
|
||||||
sfHookReturnString,
|
|
||||||
sfHookParameterName,
|
|
||||||
sfHookParameterValue,
|
|
||||||
sfEmitCallback,
|
|
||||||
sfHookAccount,
|
|
||||||
sfEmittedTxn,
|
|
||||||
sfHook,
|
|
||||||
sfHookDefinition,
|
|
||||||
sfHookParameter,
|
|
||||||
sfHookGrant,
|
|
||||||
sfEmitDetails,
|
|
||||||
sfHookExecutions,
|
|
||||||
sfHookExecution,
|
|
||||||
sfHookParameters,
|
|
||||||
sfHooks,
|
|
||||||
sfHookGrants};
|
|
||||||
|
|
||||||
for (auto const& rf : fields_to_test)
|
|
||||||
{
|
|
||||||
SField const& f = rf.get();
|
|
||||||
|
|
||||||
STObject dummy{sfGeneric};
|
|
||||||
|
|
||||||
BEAST_EXPECT(!dummy.isFieldPresent(f));
|
|
||||||
|
|
||||||
switch (f.fieldType)
|
|
||||||
{
|
|
||||||
case STI_UINT8: {
|
|
||||||
dummy.setFieldU8(f, 0);
|
|
||||||
BEAST_EXPECT(dummy.getFieldU8(f) == 0);
|
|
||||||
|
|
||||||
dummy.setFieldU8(f, 255);
|
|
||||||
BEAST_EXPECT(dummy.getFieldU8(f) == 255);
|
|
||||||
|
|
||||||
BEAST_EXPECT(dummy.isFieldPresent(f));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STI_UINT16: {
|
|
||||||
dummy.setFieldU16(f, 0);
|
|
||||||
BEAST_EXPECT(dummy.getFieldU16(f) == 0);
|
|
||||||
|
|
||||||
dummy.setFieldU16(f, 0xFFFFU);
|
|
||||||
BEAST_EXPECT(dummy.getFieldU16(f) == 0xFFFFU);
|
|
||||||
|
|
||||||
BEAST_EXPECT(dummy.isFieldPresent(f));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STI_UINT32: {
|
|
||||||
dummy.setFieldU32(f, 0);
|
|
||||||
BEAST_EXPECT(dummy.getFieldU32(f) == 0);
|
|
||||||
|
|
||||||
dummy.setFieldU32(f, 0xFFFFFFFFU);
|
|
||||||
BEAST_EXPECT(dummy.getFieldU32(f) == 0xFFFFFFFFU);
|
|
||||||
|
|
||||||
BEAST_EXPECT(dummy.isFieldPresent(f));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STI_UINT64: {
|
|
||||||
dummy.setFieldU64(f, 0);
|
|
||||||
BEAST_EXPECT(dummy.getFieldU64(f) == 0);
|
|
||||||
|
|
||||||
dummy.setFieldU64(f, 0xFFFFFFFFFFFFFFFFU);
|
|
||||||
BEAST_EXPECT(dummy.getFieldU64(f) == 0xFFFFFFFFFFFFFFFFU);
|
|
||||||
|
|
||||||
BEAST_EXPECT(dummy.isFieldPresent(f));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STI_UINT256: {
|
|
||||||
uint256 u = uint256::fromVoid(
|
|
||||||
"DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBE"
|
|
||||||
"EFDEADBEEF");
|
|
||||||
dummy.setFieldH256(f, u);
|
|
||||||
BEAST_EXPECT(dummy.getFieldH256(f) == u);
|
|
||||||
BEAST_EXPECT(dummy.isFieldPresent(f));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STI_VL: {
|
|
||||||
std::vector<uint8_t> v{1, 2, 3};
|
|
||||||
dummy.setFieldVL(f, v);
|
|
||||||
BEAST_EXPECT(dummy.getFieldVL(f) == v);
|
|
||||||
BEAST_EXPECT(dummy.isFieldPresent(f));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STI_ACCOUNT: {
|
|
||||||
AccountID id = *parseBase58<AccountID>(
|
|
||||||
"rwfSjJNK2YQuN64bSWn7T2eY9FJAyAPYJT");
|
|
||||||
dummy.setAccountID(f, id);
|
|
||||||
BEAST_EXPECT(dummy.getAccountID(f) == id);
|
|
||||||
BEAST_EXPECT(dummy.isFieldPresent(f));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STI_OBJECT: {
|
|
||||||
dummy.emplace_back(STObject{f});
|
|
||||||
BEAST_EXPECT(dummy.getField(f).getFName() == f);
|
|
||||||
BEAST_EXPECT(dummy.isFieldPresent(f));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STI_ARRAY: {
|
|
||||||
STArray dummy2{f, 2};
|
|
||||||
dummy2.push_back(STObject{sfGeneric});
|
|
||||||
dummy2.push_back(STObject{sfGeneric});
|
|
||||||
dummy.setFieldArray(f, dummy2);
|
|
||||||
BEAST_EXPECT(dummy.getFieldArray(f) == dummy2);
|
|
||||||
BEAST_EXPECT(dummy.isFieldPresent(f));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
BEAST_EXPECT(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void
|
|
||||||
run() override
|
|
||||||
{
|
|
||||||
using namespace test::jtx;
|
|
||||||
testHookFields();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(Hooks, protocol, ripple);
|
|
||||||
|
|
||||||
} // namespace ripple
|
|
||||||
@@ -1,983 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <xrpl/basics/UnorderedContainers.h>
|
|
||||||
#include <xrpl/beast/unit_test.h>
|
|
||||||
#include <xrpl/protocol/Book.h>
|
|
||||||
#include <xrpl/protocol/Issue.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <optional>
|
|
||||||
#include <set>
|
|
||||||
#include <typeinfo>
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
#if BEAST_MSVC
|
|
||||||
#define STL_SET_HAS_EMPLACE 1
|
|
||||||
#else
|
|
||||||
#define STL_SET_HAS_EMPLACE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RIPPLE_ASSETS_ENABLE_STD_HASH
|
|
||||||
#if BEAST_MAC || BEAST_IOS
|
|
||||||
#define RIPPLE_ASSETS_ENABLE_STD_HASH 0
|
|
||||||
#else
|
|
||||||
#define RIPPLE_ASSETS_ENABLE_STD_HASH 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
class Issue_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Domain = uint256;
|
|
||||||
|
|
||||||
// Comparison, hash tests for uint60 (via base_uint)
|
|
||||||
template <typename Unsigned>
|
|
||||||
void
|
|
||||||
testUnsigned()
|
|
||||||
{
|
|
||||||
Unsigned const u1(1);
|
|
||||||
Unsigned const u2(2);
|
|
||||||
Unsigned const u3(3);
|
|
||||||
|
|
||||||
BEAST_EXPECT(u1 != u2);
|
|
||||||
BEAST_EXPECT(u1 < u2);
|
|
||||||
BEAST_EXPECT(u1 <= u2);
|
|
||||||
BEAST_EXPECT(u2 <= u2);
|
|
||||||
BEAST_EXPECT(u2 == u2);
|
|
||||||
BEAST_EXPECT(u2 >= u2);
|
|
||||||
BEAST_EXPECT(u3 >= u2);
|
|
||||||
BEAST_EXPECT(u3 > u2);
|
|
||||||
|
|
||||||
std::hash<Unsigned> hash;
|
|
||||||
|
|
||||||
BEAST_EXPECT(hash(u1) == hash(u1));
|
|
||||||
BEAST_EXPECT(hash(u2) == hash(u2));
|
|
||||||
BEAST_EXPECT(hash(u3) == hash(u3));
|
|
||||||
BEAST_EXPECT(hash(u1) != hash(u2));
|
|
||||||
BEAST_EXPECT(hash(u1) != hash(u3));
|
|
||||||
BEAST_EXPECT(hash(u2) != hash(u3));
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Comparison, hash tests for Issue
|
|
||||||
template <class Issue>
|
|
||||||
void
|
|
||||||
testIssue()
|
|
||||||
{
|
|
||||||
Currency const c1(1);
|
|
||||||
AccountID const i1(1);
|
|
||||||
Currency const c2(2);
|
|
||||||
AccountID const i2(2);
|
|
||||||
Currency const c3(3);
|
|
||||||
AccountID const i3(3);
|
|
||||||
|
|
||||||
BEAST_EXPECT(Issue(c1, i1) != Issue(c2, i1));
|
|
||||||
BEAST_EXPECT(Issue(c1, i1) < Issue(c2, i1));
|
|
||||||
BEAST_EXPECT(Issue(c1, i1) <= Issue(c2, i1));
|
|
||||||
BEAST_EXPECT(Issue(c2, i1) <= Issue(c2, i1));
|
|
||||||
BEAST_EXPECT(Issue(c2, i1) == Issue(c2, i1));
|
|
||||||
BEAST_EXPECT(Issue(c2, i1) >= Issue(c2, i1));
|
|
||||||
BEAST_EXPECT(Issue(c3, i1) >= Issue(c2, i1));
|
|
||||||
BEAST_EXPECT(Issue(c3, i1) > Issue(c2, i1));
|
|
||||||
BEAST_EXPECT(Issue(c1, i1) != Issue(c1, i2));
|
|
||||||
BEAST_EXPECT(Issue(c1, i1) < Issue(c1, i2));
|
|
||||||
BEAST_EXPECT(Issue(c1, i1) <= Issue(c1, i2));
|
|
||||||
BEAST_EXPECT(Issue(c1, i2) <= Issue(c1, i2));
|
|
||||||
BEAST_EXPECT(Issue(c1, i2) == Issue(c1, i2));
|
|
||||||
BEAST_EXPECT(Issue(c1, i2) >= Issue(c1, i2));
|
|
||||||
BEAST_EXPECT(Issue(c1, i3) >= Issue(c1, i2));
|
|
||||||
BEAST_EXPECT(Issue(c1, i3) > Issue(c1, i2));
|
|
||||||
|
|
||||||
std::hash<Issue> hash;
|
|
||||||
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i1)) == hash(Issue(c1, i1)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i2)) == hash(Issue(c1, i2)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i3)) == hash(Issue(c1, i3)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c2, i1)) == hash(Issue(c2, i1)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c2, i2)) == hash(Issue(c2, i2)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c2, i3)) == hash(Issue(c2, i3)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c3, i1)) == hash(Issue(c3, i1)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c3, i2)) == hash(Issue(c3, i2)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c3, i3)) == hash(Issue(c3, i3)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i1)) != hash(Issue(c1, i2)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i1)) != hash(Issue(c1, i3)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i1)) != hash(Issue(c2, i1)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i1)) != hash(Issue(c2, i2)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i1)) != hash(Issue(c2, i3)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i1)) != hash(Issue(c3, i1)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i1)) != hash(Issue(c3, i2)));
|
|
||||||
BEAST_EXPECT(hash(Issue(c1, i1)) != hash(Issue(c3, i3)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Set>
|
|
||||||
void
|
|
||||||
testIssueSet()
|
|
||||||
{
|
|
||||||
Currency const c1(1);
|
|
||||||
AccountID const i1(1);
|
|
||||||
Currency const c2(2);
|
|
||||||
AccountID const i2(2);
|
|
||||||
Issue const a1(c1, i1);
|
|
||||||
Issue const a2(c2, i2);
|
|
||||||
|
|
||||||
{
|
|
||||||
Set c;
|
|
||||||
|
|
||||||
c.insert(a1);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(a2);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c1, i2)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c1, i1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c2, i2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Set c;
|
|
||||||
|
|
||||||
c.insert(a1);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(a2);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c1, i2)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c1, i1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c2, i2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
#if STL_SET_HAS_EMPLACE
|
|
||||||
c.emplace(c1, i1);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.emplace(c2, i2);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Map>
|
|
||||||
void
|
|
||||||
testIssueMap()
|
|
||||||
{
|
|
||||||
Currency const c1(1);
|
|
||||||
AccountID const i1(1);
|
|
||||||
Currency const c2(2);
|
|
||||||
AccountID const i2(2);
|
|
||||||
Issue const a1(c1, i1);
|
|
||||||
Issue const a2(c2, i2);
|
|
||||||
|
|
||||||
{
|
|
||||||
Map c;
|
|
||||||
|
|
||||||
c.insert(std::make_pair(a1, 1));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(std::make_pair(a2, 2));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c1, i2)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c1, i1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c2, i2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Map c;
|
|
||||||
|
|
||||||
c.insert(std::make_pair(a1, 1));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(std::make_pair(a2, 2));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c1, i2)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c1, i1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Issue(c2, i2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Set>
|
|
||||||
void
|
|
||||||
testIssueDomainSet()
|
|
||||||
{
|
|
||||||
Currency const c1(1);
|
|
||||||
AccountID const i1(1);
|
|
||||||
Currency const c2(2);
|
|
||||||
AccountID const i2(2);
|
|
||||||
Issue const a1(c1, i1);
|
|
||||||
Issue const a2(c2, i2);
|
|
||||||
uint256 const domain1{1};
|
|
||||||
uint256 const domain2{2};
|
|
||||||
|
|
||||||
Set c;
|
|
||||||
|
|
||||||
c.insert(std::make_pair(a1, domain1));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(std::make_pair(a2, domain1));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
c.insert(std::make_pair(a2, domain2));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 3))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(std::make_pair(Issue(c1, i2), domain1)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(std::make_pair(a1, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(std::make_pair(a2, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(std::make_pair(a2, domain2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Map>
|
|
||||||
void
|
|
||||||
testIssueDomainMap()
|
|
||||||
{
|
|
||||||
Currency const c1(1);
|
|
||||||
AccountID const i1(1);
|
|
||||||
Currency const c2(2);
|
|
||||||
AccountID const i2(2);
|
|
||||||
Issue const a1(c1, i1);
|
|
||||||
Issue const a2(c2, i2);
|
|
||||||
uint256 const domain1{1};
|
|
||||||
uint256 const domain2{2};
|
|
||||||
|
|
||||||
Map c;
|
|
||||||
|
|
||||||
c.insert(std::make_pair(std::make_pair(a1, domain1), 1));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(std::make_pair(std::make_pair(a2, domain1), 2));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
c.insert(std::make_pair(std::make_pair(a2, domain2), 2));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 3))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(std::make_pair(Issue(c1, i2), domain1)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(std::make_pair(a1, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(std::make_pair(a2, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(std::make_pair(a2, domain2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testIssueDomainSets()
|
|
||||||
{
|
|
||||||
testcase("std::set <std::pair<Issue, Domain>>");
|
|
||||||
testIssueDomainSet<std::set<std::pair<Issue, Domain>>>();
|
|
||||||
|
|
||||||
testcase("std::set <std::pair<Issue, Domain>>");
|
|
||||||
testIssueDomainSet<std::set<std::pair<Issue, Domain>>>();
|
|
||||||
|
|
||||||
testcase("hash_set <std::pair<Issue, Domain>>");
|
|
||||||
testIssueDomainSet<hash_set<std::pair<Issue, Domain>>>();
|
|
||||||
|
|
||||||
testcase("hash_set <std::pair<Issue, Domain>>");
|
|
||||||
testIssueDomainSet<hash_set<std::pair<Issue, Domain>>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testIssueDomainMaps()
|
|
||||||
{
|
|
||||||
testcase("std::map <std::pair<Issue, Domain>, int>");
|
|
||||||
testIssueDomainMap<std::map<std::pair<Issue, Domain>, int>>();
|
|
||||||
|
|
||||||
testcase("std::map <std::pair<Issue, Domain>, int>");
|
|
||||||
testIssueDomainMap<std::map<std::pair<Issue, Domain>, int>>();
|
|
||||||
|
|
||||||
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
|
||||||
testcase("hash_map <std::pair<Issue, Domain>, int>");
|
|
||||||
testIssueDomainMap<hash_map<std::pair<Issue, Domain>, int>>();
|
|
||||||
|
|
||||||
testcase("hash_map <std::pair<Issue, Domain>, int>");
|
|
||||||
testIssueDomainMap<hash_map<std::pair<Issue, Domain>, int>>();
|
|
||||||
|
|
||||||
testcase("hardened_hash_map <std::pair<Issue, Domain>, int>");
|
|
||||||
testIssueDomainMap<hardened_hash_map<std::pair<Issue, Domain>, int>>();
|
|
||||||
|
|
||||||
testcase("hardened_hash_map <std::pair<Issue, Domain>, int>");
|
|
||||||
testIssueDomainMap<hardened_hash_map<std::pair<Issue, Domain>, int>>();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testIssueSets()
|
|
||||||
{
|
|
||||||
testcase("std::set <Issue>");
|
|
||||||
testIssueSet<std::set<Issue>>();
|
|
||||||
|
|
||||||
testcase("std::set <Issue>");
|
|
||||||
testIssueSet<std::set<Issue>>();
|
|
||||||
|
|
||||||
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
|
||||||
testcase("std::unordered_set <Issue>");
|
|
||||||
testIssueSet<std::unordered_set<Issue>>();
|
|
||||||
|
|
||||||
testcase("std::unordered_set <Issue>");
|
|
||||||
testIssueSet<std::unordered_set<Issue>>();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
testcase("hash_set <Issue>");
|
|
||||||
testIssueSet<hash_set<Issue>>();
|
|
||||||
|
|
||||||
testcase("hash_set <Issue>");
|
|
||||||
testIssueSet<hash_set<Issue>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testIssueMaps()
|
|
||||||
{
|
|
||||||
testcase("std::map <Issue, int>");
|
|
||||||
testIssueMap<std::map<Issue, int>>();
|
|
||||||
|
|
||||||
testcase("std::map <Issue, int>");
|
|
||||||
testIssueMap<std::map<Issue, int>>();
|
|
||||||
|
|
||||||
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
|
||||||
testcase("std::unordered_map <Issue, int>");
|
|
||||||
testIssueMap<std::unordered_map<Issue, int>>();
|
|
||||||
|
|
||||||
testcase("std::unordered_map <Issue, int>");
|
|
||||||
testIssueMap<std::unordered_map<Issue, int>>();
|
|
||||||
|
|
||||||
testcase("hash_map <Issue, int>");
|
|
||||||
testIssueMap<hash_map<Issue, int>>();
|
|
||||||
|
|
||||||
testcase("hash_map <Issue, int>");
|
|
||||||
testIssueMap<hash_map<Issue, int>>();
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Comparison, hash tests for Book
|
|
||||||
template <class Book>
|
|
||||||
void
|
|
||||||
testBook()
|
|
||||||
{
|
|
||||||
Currency const c1(1);
|
|
||||||
AccountID const i1(1);
|
|
||||||
Currency const c2(2);
|
|
||||||
AccountID const i2(2);
|
|
||||||
Currency const c3(3);
|
|
||||||
AccountID const i3(3);
|
|
||||||
|
|
||||||
Issue a1(c1, i1);
|
|
||||||
Issue a2(c1, i2);
|
|
||||||
Issue a3(c2, i2);
|
|
||||||
Issue a4(c3, i2);
|
|
||||||
uint256 const domain1{1};
|
|
||||||
uint256 const domain2{2};
|
|
||||||
|
|
||||||
// Books without domains
|
|
||||||
BEAST_EXPECT(Book(a1, a2, std::nullopt) != Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a1, a2, std::nullopt) < Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a1, a2, std::nullopt) <= Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, std::nullopt) <= Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, std::nullopt) >= Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a3, a4, std::nullopt) >= Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a3, a4, std::nullopt) > Book(a2, a3, std::nullopt));
|
|
||||||
|
|
||||||
// test domain books
|
|
||||||
{
|
|
||||||
// Books with different domains
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) != Book(a2, a3, domain2));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) < Book(a2, a3, domain2));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain2) > Book(a2, a3, domain1));
|
|
||||||
|
|
||||||
// One Book has a domain, the other does not
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) != Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, std::nullopt) < Book(a2, a3, domain1));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) > Book(a2, a3, std::nullopt));
|
|
||||||
|
|
||||||
// Both Books have the same domain
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) == Book(a2, a3, domain1));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain2) == Book(a2, a3, domain2));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt));
|
|
||||||
|
|
||||||
// Both Books have no domain
|
|
||||||
BEAST_EXPECT(
|
|
||||||
Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt));
|
|
||||||
|
|
||||||
// Testing comparisons with >= and <=
|
|
||||||
|
|
||||||
// When comparing books with domain1 vs domain2
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) <= Book(a2, a3, domain2));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain2) >= Book(a2, a3, domain1));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) >= Book(a2, a3, domain1));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain2) <= Book(a2, a3, domain2));
|
|
||||||
|
|
||||||
// One Book has domain1 and the other has no domain
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) > Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, std::nullopt) < Book(a2, a3, domain1));
|
|
||||||
|
|
||||||
// One Book has domain2 and the other has no domain
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain2) > Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, std::nullopt) < Book(a2, a3, domain2));
|
|
||||||
|
|
||||||
// Comparing two Books with no domains
|
|
||||||
BEAST_EXPECT(
|
|
||||||
Book(a2, a3, std::nullopt) <= Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
Book(a2, a3, std::nullopt) >= Book(a2, a3, std::nullopt));
|
|
||||||
|
|
||||||
// Test case where domain1 is less than domain2
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) <= Book(a2, a3, domain2));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain2) >= Book(a2, a3, domain1));
|
|
||||||
|
|
||||||
// Test case where domain2 is equal to domain1
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) >= Book(a2, a3, domain1));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) <= Book(a2, a3, domain1));
|
|
||||||
|
|
||||||
// More test cases involving a4 (with domain2)
|
|
||||||
|
|
||||||
// Comparing Book with domain2 (a4) to a Book with domain1
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) < Book(a3, a4, domain2));
|
|
||||||
BEAST_EXPECT(Book(a3, a4, domain2) > Book(a2, a3, domain1));
|
|
||||||
|
|
||||||
// Comparing Book with domain2 (a4) to a Book with no domain
|
|
||||||
BEAST_EXPECT(Book(a3, a4, domain2) > Book(a2, a3, std::nullopt));
|
|
||||||
BEAST_EXPECT(Book(a2, a3, std::nullopt) < Book(a3, a4, domain2));
|
|
||||||
|
|
||||||
// Comparing Book with domain2 (a4) to a Book with the same domain
|
|
||||||
BEAST_EXPECT(Book(a3, a4, domain2) == Book(a3, a4, domain2));
|
|
||||||
|
|
||||||
// Comparing Book with domain2 (a4) to a Book with domain1
|
|
||||||
BEAST_EXPECT(Book(a2, a3, domain1) < Book(a3, a4, domain2));
|
|
||||||
BEAST_EXPECT(Book(a3, a4, domain2) > Book(a2, a3, domain1));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::hash<Book> hash;
|
|
||||||
|
|
||||||
// log << std::hex << hash (Book (a1, a2));
|
|
||||||
// log << std::hex << hash (Book (a1, a2));
|
|
||||||
//
|
|
||||||
// log << std::hex << hash (Book (a1, a3));
|
|
||||||
// log << std::hex << hash (Book (a1, a3));
|
|
||||||
//
|
|
||||||
// log << std::hex << hash (Book (a1, a4));
|
|
||||||
// log << std::hex << hash (Book (a1, a4));
|
|
||||||
//
|
|
||||||
// log << std::hex << hash (Book (a2, a3));
|
|
||||||
// log << std::hex << hash (Book (a2, a3));
|
|
||||||
//
|
|
||||||
// log << std::hex << hash (Book (a2, a4));
|
|
||||||
// log << std::hex << hash (Book (a2, a4));
|
|
||||||
//
|
|
||||||
// log << std::hex << hash (Book (a3, a4));
|
|
||||||
// log << std::hex << hash (Book (a3, a4));
|
|
||||||
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, std::nullopt)) ==
|
|
||||||
hash(Book(a1, a2, std::nullopt)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a3, std::nullopt)) ==
|
|
||||||
hash(Book(a1, a3, std::nullopt)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a4, std::nullopt)) ==
|
|
||||||
hash(Book(a1, a4, std::nullopt)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a3, std::nullopt)) ==
|
|
||||||
hash(Book(a2, a3, std::nullopt)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a4, std::nullopt)) ==
|
|
||||||
hash(Book(a2, a4, std::nullopt)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a3, a4, std::nullopt)) ==
|
|
||||||
hash(Book(a3, a4, std::nullopt)));
|
|
||||||
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, std::nullopt)) !=
|
|
||||||
hash(Book(a1, a3, std::nullopt)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, std::nullopt)) !=
|
|
||||||
hash(Book(a1, a4, std::nullopt)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, std::nullopt)) !=
|
|
||||||
hash(Book(a2, a3, std::nullopt)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, std::nullopt)) !=
|
|
||||||
hash(Book(a2, a4, std::nullopt)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, std::nullopt)) !=
|
|
||||||
hash(Book(a3, a4, std::nullopt)));
|
|
||||||
|
|
||||||
// Books with domain
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, domain1)) == hash(Book(a1, a2, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a3, domain1)) == hash(Book(a1, a3, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a4, domain1)) == hash(Book(a1, a4, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a3, domain1)) == hash(Book(a2, a3, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a4, domain1)) == hash(Book(a2, a4, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a3, a4, domain1)) == hash(Book(a3, a4, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, std::nullopt)) ==
|
|
||||||
hash(Book(a1, a2, std::nullopt)));
|
|
||||||
|
|
||||||
// Comparing Books with domain1 vs no domain
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, std::nullopt)) != hash(Book(a1, a2, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a3, std::nullopt)) != hash(Book(a1, a3, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a4, std::nullopt)) != hash(Book(a1, a4, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a3, std::nullopt)) != hash(Book(a2, a3, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a4, std::nullopt)) != hash(Book(a2, a4, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a3, a4, std::nullopt)) != hash(Book(a3, a4, domain1)));
|
|
||||||
|
|
||||||
// Books with domain1 but different Issues
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, domain1)) != hash(Book(a1, a3, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, domain1)) != hash(Book(a1, a4, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a3, domain1)) != hash(Book(a2, a4, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, domain1)) != hash(Book(a2, a3, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a4, domain1)) != hash(Book(a3, a4, domain1)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a3, a4, domain1)) != hash(Book(a1, a4, domain1)));
|
|
||||||
|
|
||||||
// Books with domain1 and domain2
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a2, domain1)) != hash(Book(a1, a2, domain2)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a3, domain1)) != hash(Book(a1, a3, domain2)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a1, a4, domain1)) != hash(Book(a1, a4, domain2)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a3, domain1)) != hash(Book(a2, a3, domain2)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a2, a4, domain1)) != hash(Book(a2, a4, domain2)));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
hash(Book(a3, a4, domain1)) != hash(Book(a3, a4, domain2)));
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template <class Set>
|
|
||||||
void
|
|
||||||
testBookSet()
|
|
||||||
{
|
|
||||||
Currency const c1(1);
|
|
||||||
AccountID const i1(1);
|
|
||||||
Currency const c2(2);
|
|
||||||
AccountID const i2(2);
|
|
||||||
Issue const a1(c1, i1);
|
|
||||||
Issue const a2(c2, i2);
|
|
||||||
Book const b1(a1, a2, std::nullopt);
|
|
||||||
Book const b2(a2, a1, std::nullopt);
|
|
||||||
|
|
||||||
uint256 const domain1{1};
|
|
||||||
uint256 const domain2{2};
|
|
||||||
|
|
||||||
Book const b1_d1(a1, a2, domain1);
|
|
||||||
Book const b2_d1(a2, a1, domain1);
|
|
||||||
Book const b1_d2(a1, a2, domain2);
|
|
||||||
Book const b2_d2(a2, a1, domain2);
|
|
||||||
|
|
||||||
{
|
|
||||||
Set c;
|
|
||||||
|
|
||||||
c.insert(b1);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(b2);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a1, std::nullopt)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Set c;
|
|
||||||
|
|
||||||
c.insert(b1);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(b2);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a1, std::nullopt)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
#if STL_SET_HAS_EMPLACE
|
|
||||||
c.emplace(a1, a2);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.emplace(a2, a1);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Set c;
|
|
||||||
|
|
||||||
c.insert(b1_d1);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(b2_d1);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
c.insert(b1_d2);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 3))
|
|
||||||
return;
|
|
||||||
c.insert(b2_d2);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 4))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Try removing non-existent elements
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a2, domain1)) == 0))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, domain2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, domain2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Set c;
|
|
||||||
|
|
||||||
c.insert(b1);
|
|
||||||
c.insert(b2);
|
|
||||||
c.insert(b1_d1);
|
|
||||||
c.insert(b2_d1);
|
|
||||||
if (!BEAST_EXPECT(c.size() == 4))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Map>
|
|
||||||
void
|
|
||||||
testBookMap()
|
|
||||||
{
|
|
||||||
Currency const c1(1);
|
|
||||||
AccountID const i1(1);
|
|
||||||
Currency const c2(2);
|
|
||||||
AccountID const i2(2);
|
|
||||||
Issue const a1(c1, i1);
|
|
||||||
Issue const a2(c2, i2);
|
|
||||||
Book const b1(a1, a2, std::nullopt);
|
|
||||||
Book const b2(a2, a1, std::nullopt);
|
|
||||||
|
|
||||||
uint256 const domain1{1};
|
|
||||||
uint256 const domain2{2};
|
|
||||||
|
|
||||||
Book const b1_d1(a1, a2, domain1);
|
|
||||||
Book const b2_d1(a2, a1, domain1);
|
|
||||||
Book const b1_d2(a1, a2, domain2);
|
|
||||||
Book const b2_d2(a2, a1, domain2);
|
|
||||||
|
|
||||||
// typename Map::value_type value_type;
|
|
||||||
// std::pair <Book const, int> value_type;
|
|
||||||
|
|
||||||
{
|
|
||||||
Map c;
|
|
||||||
|
|
||||||
// c.insert (value_type (b1, 1));
|
|
||||||
c.insert(std::make_pair(b1, 1));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
// c.insert (value_type (b2, 2));
|
|
||||||
c.insert(std::make_pair(b2, 1));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a1, std::nullopt)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Map c;
|
|
||||||
|
|
||||||
// c.insert (value_type (b1, 1));
|
|
||||||
c.insert(std::make_pair(b1, 1));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
// c.insert (value_type (b2, 2));
|
|
||||||
c.insert(std::make_pair(b2, 1));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a1, std::nullopt)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Map c;
|
|
||||||
|
|
||||||
c.insert(std::make_pair(b1_d1, 10));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 1))
|
|
||||||
return;
|
|
||||||
c.insert(std::make_pair(b2_d1, 20));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
c.insert(std::make_pair(b1_d2, 30));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 3))
|
|
||||||
return;
|
|
||||||
c.insert(std::make_pair(b2_d2, 40));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 4))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Try removing non-existent elements
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a2, domain1)) == 0))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, domain2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, domain2)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Map c;
|
|
||||||
|
|
||||||
c.insert(std::make_pair(b1, 1));
|
|
||||||
c.insert(std::make_pair(b2, 2));
|
|
||||||
c.insert(std::make_pair(b1_d1, 3));
|
|
||||||
c.insert(std::make_pair(b2_d1, 4));
|
|
||||||
if (!BEAST_EXPECT(c.size() == 4))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Try removing non-existent elements
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a1, domain1)) == 0))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a2, domain2)) == 0))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, std::nullopt)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.size() == 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a1, a2, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.erase(Book(a2, a1, domain1)) == 1))
|
|
||||||
return;
|
|
||||||
if (!BEAST_EXPECT(c.empty()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testBookSets()
|
|
||||||
{
|
|
||||||
testcase("std::set <Book>");
|
|
||||||
testBookSet<std::set<Book>>();
|
|
||||||
|
|
||||||
testcase("std::set <Book>");
|
|
||||||
testBookSet<std::set<Book>>();
|
|
||||||
|
|
||||||
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
|
||||||
testcase("std::unordered_set <Book>");
|
|
||||||
testBookSet<std::unordered_set<Book>>();
|
|
||||||
|
|
||||||
testcase("std::unordered_set <Book>");
|
|
||||||
testBookSet<std::unordered_set<Book>>();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
testcase("hash_set <Book>");
|
|
||||||
testBookSet<hash_set<Book>>();
|
|
||||||
|
|
||||||
testcase("hash_set <Book>");
|
|
||||||
testBookSet<hash_set<Book>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testBookMaps()
|
|
||||||
{
|
|
||||||
testcase("std::map <Book, int>");
|
|
||||||
testBookMap<std::map<Book, int>>();
|
|
||||||
|
|
||||||
testcase("std::map <Book, int>");
|
|
||||||
testBookMap<std::map<Book, int>>();
|
|
||||||
|
|
||||||
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
|
||||||
testcase("std::unordered_map <Book, int>");
|
|
||||||
testBookMap<std::unordered_map<Book, int>>();
|
|
||||||
|
|
||||||
testcase("std::unordered_map <Book, int>");
|
|
||||||
testBookMap<std::unordered_map<Book, int>>();
|
|
||||||
|
|
||||||
testcase("hash_map <Book, int>");
|
|
||||||
testBookMap<hash_map<Book, int>>();
|
|
||||||
|
|
||||||
testcase("hash_map <Book, int>");
|
|
||||||
testBookMap<hash_map<Book, int>>();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void
|
|
||||||
run() override
|
|
||||||
{
|
|
||||||
testcase("Currency");
|
|
||||||
testUnsigned<Currency>();
|
|
||||||
|
|
||||||
testcase("AccountID");
|
|
||||||
testUnsigned<AccountID>();
|
|
||||||
|
|
||||||
// ---
|
|
||||||
|
|
||||||
testcase("Issue");
|
|
||||||
testIssue<Issue>();
|
|
||||||
|
|
||||||
testcase("Issue");
|
|
||||||
testIssue<Issue>();
|
|
||||||
|
|
||||||
testIssueSets();
|
|
||||||
testIssueMaps();
|
|
||||||
|
|
||||||
// ---
|
|
||||||
|
|
||||||
testcase("Book");
|
|
||||||
testBook<Book>();
|
|
||||||
|
|
||||||
testcase("Book");
|
|
||||||
testBook<Book>();
|
|
||||||
|
|
||||||
testBookSets();
|
|
||||||
testBookMaps();
|
|
||||||
|
|
||||||
// ---
|
|
||||||
testIssueDomainSets();
|
|
||||||
testIssueDomainMaps();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(Issue, protocol, ripple);
|
|
||||||
|
|
||||||
} // namespace ripple
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2022 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <test/jtx.h>
|
|
||||||
|
|
||||||
#include <xrpl/basics/strHex.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
class Memo_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void
|
|
||||||
testMemos()
|
|
||||||
{
|
|
||||||
testcase("Test memos");
|
|
||||||
|
|
||||||
using namespace test::jtx;
|
|
||||||
Account alice{"alice"};
|
|
||||||
|
|
||||||
Env env(*this);
|
|
||||||
env.fund(XRP(10000), alice);
|
|
||||||
env.close();
|
|
||||||
|
|
||||||
// Lambda that returns a valid JTx with a memo that we can hack up.
|
|
||||||
// This is the basis for building tests of invalid states.
|
|
||||||
auto makeJtxWithMemo = [&env, &alice]() {
|
|
||||||
JTx example = noop(alice);
|
|
||||||
memo const exampleMemo{"tic", "tac", "toe"};
|
|
||||||
exampleMemo(env, example);
|
|
||||||
return example;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A valid memo.
|
|
||||||
env(makeJtxWithMemo());
|
|
||||||
env.close();
|
|
||||||
|
|
||||||
{
|
|
||||||
// Make sure that too big a memo is flagged as invalid.
|
|
||||||
JTx memoSize = makeJtxWithMemo();
|
|
||||||
memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName]
|
|
||||||
[sfMemoData.jsonName] = std::string(2020, '0');
|
|
||||||
env(memoSize,
|
|
||||||
rpc("invalidTransaction",
|
|
||||||
"fails local checks: The memo exceeds the maximum allowed "
|
|
||||||
"size."));
|
|
||||||
|
|
||||||
// This memo is just barely small enough.
|
|
||||||
memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName]
|
|
||||||
[sfMemoData.jsonName] = std::string(2018, '1');
|
|
||||||
env(memoSize);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Put a non-Memo in the Memos array.
|
|
||||||
JTx memoNonMemo = noop(alice);
|
|
||||||
auto& jv = memoNonMemo.jv;
|
|
||||||
auto& ma = jv[sfMemos.jsonName];
|
|
||||||
auto& mi = ma[ma.size()];
|
|
||||||
auto& m = mi[sfCreatedNode.jsonName]; // CreatedNode in Memos
|
|
||||||
m[sfMemoData.jsonName] = "3030303030";
|
|
||||||
|
|
||||||
env(memoNonMemo,
|
|
||||||
rpc("invalidTransaction",
|
|
||||||
"fails local checks: A memo array may contain only Memo "
|
|
||||||
"objects."));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Put an invalid field in a Memo object.
|
|
||||||
JTx memoExtra = makeJtxWithMemo();
|
|
||||||
memoExtra
|
|
||||||
.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfFlags.jsonName] =
|
|
||||||
13;
|
|
||||||
env(memoExtra,
|
|
||||||
rpc("invalidTransaction",
|
|
||||||
"fails local checks: A memo may contain only MemoType, "
|
|
||||||
"MemoData or MemoFormat fields."));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Put a character that is not allowed in a URL in a MemoType field.
|
|
||||||
JTx memoBadChar = makeJtxWithMemo();
|
|
||||||
memoBadChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName]
|
|
||||||
[sfMemoType.jsonName] =
|
|
||||||
strHex(std::string_view("ONE<INFINITY"));
|
|
||||||
env(memoBadChar,
|
|
||||||
rpc("invalidTransaction",
|
|
||||||
"fails local checks: The MemoType and MemoFormat fields "
|
|
||||||
"may only contain characters that are allowed in URLs "
|
|
||||||
"under RFC 3986."));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Put a character that is not allowed in a URL in a MemoData field.
|
|
||||||
// That's okay.
|
|
||||||
JTx memoLegitChar = makeJtxWithMemo();
|
|
||||||
memoLegitChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName]
|
|
||||||
[sfMemoData.jsonName] =
|
|
||||||
strHex(std::string_view("ONE<INFINITY"));
|
|
||||||
env(memoLegitChar);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Put a character that is not allowed in a URL in a MemoFormat.
|
|
||||||
JTx memoBadChar = makeJtxWithMemo();
|
|
||||||
memoBadChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName]
|
|
||||||
[sfMemoFormat.jsonName] =
|
|
||||||
strHex(std::string_view("NoBraces{}InURL"));
|
|
||||||
env(memoBadChar,
|
|
||||||
rpc("invalidTransaction",
|
|
||||||
"fails local checks: The MemoType and MemoFormat fields "
|
|
||||||
"may only contain characters that are allowed in URLs "
|
|
||||||
"under RFC 3986."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void
|
|
||||||
run() override
|
|
||||||
{
|
|
||||||
testMemos();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(Memo, ripple_data, ripple);
|
|
||||||
|
|
||||||
} // namespace ripple
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,474 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <xrpl/beast/unit_test.h>
|
|
||||||
#include <xrpl/protocol/PublicKey.h>
|
|
||||||
#include <xrpl/protocol/SecretKey.h>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
class PublicKey_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using blob = std::vector<std::uint8_t>;
|
|
||||||
|
|
||||||
template <class FwdIter, class Container>
|
|
||||||
static void
|
|
||||||
hex_to_binary(FwdIter first, FwdIter last, Container& out)
|
|
||||||
{
|
|
||||||
struct Table
|
|
||||||
{
|
|
||||||
int val[256];
|
|
||||||
Table()
|
|
||||||
{
|
|
||||||
std::fill(val, val + 256, 0);
|
|
||||||
for (int i = 0; i < 10; ++i)
|
|
||||||
val['0' + i] = i;
|
|
||||||
for (int i = 0; i < 6; ++i)
|
|
||||||
{
|
|
||||||
val['A' + i] = 10 + i;
|
|
||||||
val['a' + i] = 10 + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int
|
|
||||||
operator[](int i)
|
|
||||||
{
|
|
||||||
return val[i];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static Table lut;
|
|
||||||
out.reserve(std::distance(first, last) / 2);
|
|
||||||
while (first != last)
|
|
||||||
{
|
|
||||||
auto const hi(lut[(*first++)]);
|
|
||||||
auto const lo(lut[(*first++)]);
|
|
||||||
out.push_back((hi * 16) + lo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blob
|
|
||||||
sig(std::string const& hex)
|
|
||||||
{
|
|
||||||
blob b;
|
|
||||||
hex_to_binary(hex.begin(), hex.end(), b);
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
check(std::optional<ECDSACanonicality> answer, std::string const& s)
|
|
||||||
{
|
|
||||||
return ecdsaCanonicality(makeSlice(sig(s))) == answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testCanonical()
|
|
||||||
{
|
|
||||||
testcase("Canonical");
|
|
||||||
|
|
||||||
// Fully canonical
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::fullyCanonical,
|
|
||||||
"3045"
|
|
||||||
"022100FF478110D1D4294471EC76E0157540C2181F47DEBD25D7F9E7DDCCCD47EE"
|
|
||||||
"E905"
|
|
||||||
"0220078F07CDAE6C240855D084AD91D1479609533C147C93B0AEF19BC9724D003F"
|
|
||||||
"28"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::fullyCanonical,
|
|
||||||
"3045"
|
|
||||||
"0221009218248292F1762D8A51BE80F8A7F2CD288D810CE781D5955700DA1684DF"
|
|
||||||
"1D2D"
|
|
||||||
"022041A1EE1746BFD72C9760CC93A7AAA8047D52C8833A03A20EAAE92EA19717B4"
|
|
||||||
"54"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::fullyCanonical,
|
|
||||||
"3044"
|
|
||||||
"02206A9E43775F73B6D1EC420E4DDD222A80D4C6DF5D1BEECC431A91B63C928B75"
|
|
||||||
"81"
|
|
||||||
"022023E9CC2D61DDA6F73EAA6BCB12688BEB0F434769276B3127E4044ED895C9D9"
|
|
||||||
"6B"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::fullyCanonical,
|
|
||||||
"3044"
|
|
||||||
"022056E720007221F3CD4EFBB6352741D8E5A0968D48D8D032C2FBC4F6304AD1D0"
|
|
||||||
"4E"
|
|
||||||
"02201F39EB392C20D7801C3E8D81D487E742FA84A1665E923225BD6323847C7187"
|
|
||||||
"9F"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::fullyCanonical,
|
|
||||||
"3045"
|
|
||||||
"022100FDFD5AD05518CEA0017A2DCB5C4DF61E7C73B6D3A38E7AE93210A1564E8C"
|
|
||||||
"2F12"
|
|
||||||
"0220214FF061CCC123C81D0BB9D0EDEA04CD40D96BF1425D311DA62A7096BB18EA"
|
|
||||||
"18"));
|
|
||||||
|
|
||||||
// Canonical but not fully canonical
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::canonical,
|
|
||||||
"3046"
|
|
||||||
"022100F477B3FA6F31C7CB3A0D1AD94A231FDD24B8D78862EE334CEA7CD08F6CBC"
|
|
||||||
"0A1B"
|
|
||||||
"022100928E6BCF1ED2684679730C5414AEC48FD62282B090041C41453C1D064AF5"
|
|
||||||
"97A1"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::canonical,
|
|
||||||
"3045"
|
|
||||||
"022063E7C7CA93CB2400E413A342C027D00665F8BAB9C22EF0A7B8AE3AAF092230"
|
|
||||||
"B6"
|
|
||||||
"0221008F2E8BB7D09521ABBC277717B14B93170AE6465C5A1B36561099319C4BEB"
|
|
||||||
"254C"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::canonical,
|
|
||||||
"3046"
|
|
||||||
"02210099DCA1188663DDEA506A06A7B20C2B7D8C26AFF41DECE69D6C5F7C967D32"
|
|
||||||
"625F"
|
|
||||||
"022100897658A6B1F9EEE5D140D7A332DA0BD73BB98974EA53F6201B01C1B594F2"
|
|
||||||
"86EA"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::canonical,
|
|
||||||
"3045"
|
|
||||||
"02200855DE366E4E323AA2CE2A25674401A7D11F72EC432770D07F7B57DF7387AE"
|
|
||||||
"C0"
|
|
||||||
"022100DA4C6ADDEA14888858DE2AC5B91ED9050D6972BB388DEF582628CEE32869"
|
|
||||||
"AE35"));
|
|
||||||
|
|
||||||
// valid
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::fullyCanonical,
|
|
||||||
"3006"
|
|
||||||
"020101"
|
|
||||||
"020102"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::fullyCanonical,
|
|
||||||
"3044"
|
|
||||||
"02203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df"
|
|
||||||
"0c"
|
|
||||||
"022030b61dd36543125d56b9f9f3a1f53189e5af33cdda8d77a5209aec03978fa0"
|
|
||||||
"01"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::canonical,
|
|
||||||
"3045"
|
|
||||||
"0220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f9"
|
|
||||||
"0a"
|
|
||||||
"0221008fffd599910eefe00bc803c688eca1d2ba7f6b180620eaa03488e6585db6"
|
|
||||||
"ba01"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
ECDSACanonicality::canonical,
|
|
||||||
"3046"
|
|
||||||
"022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40"
|
|
||||||
"f90a"
|
|
||||||
"0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585d"
|
|
||||||
"b6ba"));
|
|
||||||
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3005"
|
|
||||||
"0201FF"
|
|
||||||
"0200"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3006"
|
|
||||||
"020101"
|
|
||||||
"020202"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3006"
|
|
||||||
"020701"
|
|
||||||
"020102"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3006"
|
|
||||||
"020401"
|
|
||||||
"020102"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3006"
|
|
||||||
"020501"
|
|
||||||
"020102"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3006"
|
|
||||||
"020201"
|
|
||||||
"020102"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3006"
|
|
||||||
"020301"
|
|
||||||
"020202"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3006"
|
|
||||||
"020401"
|
|
||||||
"020202"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3047"
|
|
||||||
"0221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba"
|
|
||||||
"6105"
|
|
||||||
"022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e56"
|
|
||||||
"6695ed"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3144"
|
|
||||||
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
|
||||||
"05"
|
|
||||||
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
|
||||||
"ed"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3045"
|
|
||||||
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
|
||||||
"05"
|
|
||||||
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
|
||||||
"ed"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"301F"
|
|
||||||
"01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3045"
|
|
||||||
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
|
||||||
"05"
|
|
||||||
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
|
||||||
"ed00"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3044"
|
|
||||||
"01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
|
||||||
"05"
|
|
||||||
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
|
||||||
"ed"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3024"
|
|
||||||
"0200"
|
|
||||||
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
|
||||||
"ed"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3044"
|
|
||||||
"02208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
|
||||||
"05"
|
|
||||||
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
|
||||||
"ed"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3045"
|
|
||||||
"0221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba"
|
|
||||||
"6105"
|
|
||||||
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
|
||||||
"ed"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3044"
|
|
||||||
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
|
||||||
"05012"
|
|
||||||
"02d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695e"
|
|
||||||
"d"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3024"
|
|
||||||
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
|
||||||
"05"
|
|
||||||
"0200"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3044"
|
|
||||||
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
|
||||||
"05"
|
|
||||||
"0220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
|
||||||
"ed"));
|
|
||||||
BEAST_EXPECT(check(
|
|
||||||
std::nullopt,
|
|
||||||
"3045"
|
|
||||||
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
|
||||||
"05"
|
|
||||||
"0221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e5666"
|
|
||||||
"95ed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testBase58(KeyType keyType)
|
|
||||||
{
|
|
||||||
// Try converting short, long and malformed data
|
|
||||||
BEAST_EXPECT(!parseBase58<PublicKey>(TokenType::NodePublic, ""));
|
|
||||||
BEAST_EXPECT(!parseBase58<PublicKey>(TokenType::NodePublic, " "));
|
|
||||||
BEAST_EXPECT(
|
|
||||||
!parseBase58<PublicKey>(TokenType::NodePublic, "!ty89234gh45"));
|
|
||||||
|
|
||||||
auto const good = toBase58(
|
|
||||||
TokenType::NodePublic, derivePublicKey(keyType, randomSecretKey()));
|
|
||||||
|
|
||||||
// Short (non-empty) strings
|
|
||||||
{
|
|
||||||
auto s = good;
|
|
||||||
|
|
||||||
// Remove all characters from the string in random order:
|
|
||||||
std::hash<std::string> r;
|
|
||||||
|
|
||||||
while (!s.empty())
|
|
||||||
{
|
|
||||||
s.erase(r(s) % s.size(), 1);
|
|
||||||
BEAST_EXPECT(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Long strings
|
|
||||||
for (std::size_t i = 1; i != 16; i++)
|
|
||||||
{
|
|
||||||
auto s = good;
|
|
||||||
s.resize(s.size() + i, s[i % s.size()]);
|
|
||||||
BEAST_EXPECT(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strings with invalid Base58 characters
|
|
||||||
for (auto c : std::string("0IOl"))
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i != good.size(); ++i)
|
|
||||||
{
|
|
||||||
auto s = good;
|
|
||||||
s[i % s.size()] = c;
|
|
||||||
BEAST_EXPECT(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strings with incorrect prefix
|
|
||||||
{
|
|
||||||
auto s = good;
|
|
||||||
|
|
||||||
for (auto c : std::string("apsrJqtv7"))
|
|
||||||
{
|
|
||||||
s[0] = c;
|
|
||||||
BEAST_EXPECT(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try some random secret keys
|
|
||||||
std::vector<PublicKey> keys;
|
|
||||||
keys.reserve(32);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i != keys.capacity(); ++i)
|
|
||||||
keys.emplace_back(derivePublicKey(keyType, randomSecretKey()));
|
|
||||||
BEAST_EXPECT(keys.size() == 32);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i != keys.size(); ++i)
|
|
||||||
{
|
|
||||||
auto const si = toBase58(TokenType::NodePublic, keys[i]);
|
|
||||||
BEAST_EXPECT(!si.empty());
|
|
||||||
|
|
||||||
auto const ski = parseBase58<PublicKey>(TokenType::NodePublic, si);
|
|
||||||
BEAST_EXPECT(ski && (keys[i] == *ski));
|
|
||||||
|
|
||||||
for (std::size_t j = i; j != keys.size(); ++j)
|
|
||||||
{
|
|
||||||
BEAST_EXPECT((keys[i] == keys[j]) == (i == j));
|
|
||||||
|
|
||||||
auto const sj = toBase58(TokenType::NodePublic, keys[j]);
|
|
||||||
|
|
||||||
BEAST_EXPECT((si == sj) == (i == j));
|
|
||||||
|
|
||||||
auto const skj =
|
|
||||||
parseBase58<PublicKey>(TokenType::NodePublic, sj);
|
|
||||||
BEAST_EXPECT(skj && (keys[j] == *skj));
|
|
||||||
|
|
||||||
BEAST_EXPECT((*ski == *skj) == (i == j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testBase58()
|
|
||||||
{
|
|
||||||
testcase("Base58: secp256k1");
|
|
||||||
|
|
||||||
{
|
|
||||||
auto const pk1 = derivePublicKey(
|
|
||||||
KeyType::secp256k1,
|
|
||||||
generateSecretKey(
|
|
||||||
KeyType::secp256k1, generateSeed("masterpassphrase")));
|
|
||||||
|
|
||||||
auto const pk2 = parseBase58<PublicKey>(
|
|
||||||
TokenType::NodePublic,
|
|
||||||
"n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9");
|
|
||||||
BEAST_EXPECT(pk2);
|
|
||||||
|
|
||||||
BEAST_EXPECT(pk1 == *pk2);
|
|
||||||
}
|
|
||||||
|
|
||||||
testBase58(KeyType::secp256k1);
|
|
||||||
|
|
||||||
testcase("Base58: ed25519");
|
|
||||||
|
|
||||||
{
|
|
||||||
auto const pk1 = derivePublicKey(
|
|
||||||
KeyType::ed25519,
|
|
||||||
generateSecretKey(
|
|
||||||
KeyType::ed25519, generateSeed("masterpassphrase")));
|
|
||||||
|
|
||||||
auto const pk2 = parseBase58<PublicKey>(
|
|
||||||
TokenType::NodePublic,
|
|
||||||
"nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf");
|
|
||||||
BEAST_EXPECT(pk2);
|
|
||||||
|
|
||||||
BEAST_EXPECT(pk1 == *pk2);
|
|
||||||
}
|
|
||||||
|
|
||||||
testBase58(KeyType::ed25519);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testMiscOperations()
|
|
||||||
{
|
|
||||||
testcase("Miscellaneous operations");
|
|
||||||
|
|
||||||
auto const pk1 = derivePublicKey(
|
|
||||||
KeyType::secp256k1,
|
|
||||||
generateSecretKey(
|
|
||||||
KeyType::secp256k1, generateSeed("masterpassphrase")));
|
|
||||||
|
|
||||||
PublicKey pk2(pk1);
|
|
||||||
BEAST_EXPECT(pk1 == pk2);
|
|
||||||
BEAST_EXPECT(pk2 == pk1);
|
|
||||||
|
|
||||||
PublicKey pk3 = derivePublicKey(
|
|
||||||
KeyType::secp256k1,
|
|
||||||
generateSecretKey(
|
|
||||||
KeyType::secp256k1, generateSeed("arbitraryPassPhrase")));
|
|
||||||
// Testing the copy assignment operation of PublicKey class
|
|
||||||
pk3 = pk2;
|
|
||||||
BEAST_EXPECT(pk3 == pk2);
|
|
||||||
BEAST_EXPECT(pk1 == pk3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
run() override
|
|
||||||
{
|
|
||||||
testBase58();
|
|
||||||
testCanonical();
|
|
||||||
testMiscOperations();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(PublicKey, protocol, ripple);
|
|
||||||
|
|
||||||
} // namespace ripple
|
|
||||||
@@ -12,3 +12,5 @@ xrpl_add_test(basics)
|
|||||||
target_link_libraries(xrpl.test.basics PRIVATE xrpl.imports.test)
|
target_link_libraries(xrpl.test.basics PRIVATE xrpl.imports.test)
|
||||||
xrpl_add_test(crypto)
|
xrpl_add_test(crypto)
|
||||||
target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test)
|
target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test)
|
||||||
|
xrpl_add_test(protocol)
|
||||||
|
target_link_libraries(xrpl.test.protocol PRIVATE xrpl.imports.test)
|
||||||
|
|||||||
56
src/tests/libxrpl/protocol/ApiVersion.cpp
Normal file
56
src/tests/libxrpl/protocol/ApiVersion.cpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/XRPLF/rippled/
|
||||||
|
Copyright (c) 2023 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <xrpl/protocol/ApiVersion.h>
|
||||||
|
|
||||||
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
|
using namespace ripple;
|
||||||
|
|
||||||
|
TEST_SUITE_BEGIN("ApiVersion");
|
||||||
|
|
||||||
|
TEST_CASE("API versions invariants")
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
RPC::apiMinimumSupportedVersion <= RPC::apiMaximumSupportedVersion);
|
||||||
|
static_assert(
|
||||||
|
RPC::apiMinimumSupportedVersion <= RPC::apiMaximumValidVersion);
|
||||||
|
static_assert(
|
||||||
|
RPC::apiMaximumSupportedVersion <= RPC::apiMaximumValidVersion);
|
||||||
|
static_assert(RPC::apiBetaVersion <= RPC::apiMaximumValidVersion);
|
||||||
|
|
||||||
|
CHECK(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("API versions")
|
||||||
|
{
|
||||||
|
// Update when we change versions
|
||||||
|
static_assert(RPC::apiMinimumSupportedVersion >= 1);
|
||||||
|
static_assert(RPC::apiMinimumSupportedVersion < 2);
|
||||||
|
static_assert(RPC::apiMaximumSupportedVersion >= 2);
|
||||||
|
static_assert(RPC::apiMaximumSupportedVersion < 3);
|
||||||
|
static_assert(RPC::apiMaximumValidVersion >= 3);
|
||||||
|
static_assert(RPC::apiMaximumValidVersion < 4);
|
||||||
|
static_assert(RPC::apiBetaVersion >= 3);
|
||||||
|
static_assert(RPC::apiBetaVersion < 4);
|
||||||
|
|
||||||
|
CHECK(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUITE_END();
|
||||||
98
src/tests/libxrpl/protocol/BuildInfo.cpp
Normal file
98
src/tests/libxrpl/protocol/BuildInfo.cpp
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2020 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <xrpl/protocol/BuildInfo.h>
|
||||||
|
|
||||||
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
|
using namespace ripple;
|
||||||
|
|
||||||
|
TEST_SUITE_BEGIN("BuildInfo");
|
||||||
|
|
||||||
|
TEST_CASE("EncodeSoftwareVersion")
|
||||||
|
{
|
||||||
|
auto encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b7");
|
||||||
|
|
||||||
|
// the first two bytes identify the particular implementation, 0x183B
|
||||||
|
CHECK(
|
||||||
|
(encodedVersion & 0xFFFF'0000'0000'0000LLU) ==
|
||||||
|
0x183B'0000'0000'0000LLU);
|
||||||
|
|
||||||
|
// the next three bytes: major version, minor version, patch version,
|
||||||
|
// 0x010203
|
||||||
|
CHECK(
|
||||||
|
(encodedVersion & 0x0000'FFFF'FF00'0000LLU) ==
|
||||||
|
0x0000'0102'0300'0000LLU);
|
||||||
|
|
||||||
|
// the next two bits:
|
||||||
|
{
|
||||||
|
// 01 if a beta
|
||||||
|
CHECK((encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b01);
|
||||||
|
// 10 if an RC
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.4-rc7");
|
||||||
|
CHECK((encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b10);
|
||||||
|
// 11 if neither an RC nor a beta
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.5");
|
||||||
|
CHECK((encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b11);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the next six bits: rc/beta number (1-63)
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.6-b63");
|
||||||
|
CHECK((encodedVersion & 0x0000'0000'003F'0000LLU) >> 16 == 63);
|
||||||
|
|
||||||
|
// the last two bytes are zeros
|
||||||
|
CHECK((encodedVersion & 0x0000'0000'0000'FFFFLLU) == 0);
|
||||||
|
|
||||||
|
// Test some version strings with wrong formats:
|
||||||
|
// no rc/beta number
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b");
|
||||||
|
CHECK((encodedVersion & 0x0000'0000'00FF'0000LLU) == 0);
|
||||||
|
// rc/beta number out of range
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b64");
|
||||||
|
CHECK((encodedVersion & 0x0000'0000'00FF'0000LLU) == 0);
|
||||||
|
|
||||||
|
// Check that the rc/beta number of a release is 0:
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.6");
|
||||||
|
CHECK((encodedVersion & 0x0000'0000'003F'0000LLU) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("IsRippledVersion")
|
||||||
|
{
|
||||||
|
auto vFF = 0xFFFF'FFFF'FFFF'FFFFLLU;
|
||||||
|
CHECK(!BuildInfo::isRippledVersion(vFF));
|
||||||
|
auto vRippled = 0x183B'0000'0000'0000LLU;
|
||||||
|
CHECK(BuildInfo::isRippledVersion(vRippled));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("IsNewerVersion")
|
||||||
|
{
|
||||||
|
auto vFF = 0xFFFF'FFFF'FFFF'FFFFLLU;
|
||||||
|
CHECK(!BuildInfo::isNewerVersion(vFF));
|
||||||
|
|
||||||
|
auto v159 = BuildInfo::encodeSoftwareVersion("1.5.9");
|
||||||
|
CHECK(!BuildInfo::isNewerVersion(v159));
|
||||||
|
|
||||||
|
auto vCurrent = BuildInfo::getEncodedVersion();
|
||||||
|
CHECK(!BuildInfo::isNewerVersion(vCurrent));
|
||||||
|
|
||||||
|
auto vMax = BuildInfo::encodeSoftwareVersion("255.255.255");
|
||||||
|
CHECK(BuildInfo::isNewerVersion(vMax));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUITE_END();
|
||||||
179
src/tests/libxrpl/protocol/Hooks.cpp
Normal file
179
src/tests/libxrpl/protocol/Hooks.cpp
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2017 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <test/jtx.h>
|
||||||
|
|
||||||
|
#include <xrpl/protocol/Feature.h>
|
||||||
|
|
||||||
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace ripple;
|
||||||
|
|
||||||
|
TEST_SUITE_BEGIN("Hooks");
|
||||||
|
|
||||||
|
TEST_CASE("Test Hooks fields")
|
||||||
|
{
|
||||||
|
using namespace test::jtx;
|
||||||
|
|
||||||
|
std::vector<std::reference_wrapper<SField const>> fields_to_test = {
|
||||||
|
sfHookResult,
|
||||||
|
sfHookStateChangeCount,
|
||||||
|
sfHookEmitCount,
|
||||||
|
sfHookExecutionIndex,
|
||||||
|
sfHookApiVersion,
|
||||||
|
sfHookStateCount,
|
||||||
|
sfEmitGeneration,
|
||||||
|
sfHookOn,
|
||||||
|
sfHookInstructionCount,
|
||||||
|
sfEmitBurden,
|
||||||
|
sfHookReturnCode,
|
||||||
|
sfReferenceCount,
|
||||||
|
sfEmitParentTxnID,
|
||||||
|
sfEmitNonce,
|
||||||
|
sfEmitHookHash,
|
||||||
|
sfHookStateKey,
|
||||||
|
sfHookHash,
|
||||||
|
sfHookNamespace,
|
||||||
|
sfHookSetTxnID,
|
||||||
|
sfHookStateData,
|
||||||
|
sfHookReturnString,
|
||||||
|
sfHookParameterName,
|
||||||
|
sfHookParameterValue,
|
||||||
|
sfEmitCallback,
|
||||||
|
sfHookAccount,
|
||||||
|
sfEmittedTxn,
|
||||||
|
sfHook,
|
||||||
|
sfHookDefinition,
|
||||||
|
sfHookParameter,
|
||||||
|
sfHookGrant,
|
||||||
|
sfEmitDetails,
|
||||||
|
sfHookExecutions,
|
||||||
|
sfHookExecution,
|
||||||
|
sfHookParameters,
|
||||||
|
sfHooks,
|
||||||
|
sfHookGrants};
|
||||||
|
|
||||||
|
for (auto const& rf : fields_to_test)
|
||||||
|
{
|
||||||
|
SField const& f = rf.get();
|
||||||
|
|
||||||
|
STObject dummy{sfGeneric};
|
||||||
|
|
||||||
|
CHECK(!dummy.isFieldPresent(f));
|
||||||
|
|
||||||
|
switch (f.fieldType)
|
||||||
|
{
|
||||||
|
case STI_UINT8: {
|
||||||
|
dummy.setFieldU8(f, 0);
|
||||||
|
CHECK(dummy.getFieldU8(f) == 0);
|
||||||
|
|
||||||
|
dummy.setFieldU8(f, 255);
|
||||||
|
CHECK(dummy.getFieldU8(f) == 255);
|
||||||
|
|
||||||
|
CHECK(dummy.isFieldPresent(f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STI_UINT16: {
|
||||||
|
dummy.setFieldU16(f, 0);
|
||||||
|
CHECK(dummy.getFieldU16(f) == 0);
|
||||||
|
|
||||||
|
dummy.setFieldU16(f, 0xFFFFU);
|
||||||
|
CHECK(dummy.getFieldU16(f) == 0xFFFFU);
|
||||||
|
|
||||||
|
CHECK(dummy.isFieldPresent(f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STI_UINT32: {
|
||||||
|
dummy.setFieldU32(f, 0);
|
||||||
|
CHECK(dummy.getFieldU32(f) == 0);
|
||||||
|
|
||||||
|
dummy.setFieldU32(f, 0xFFFFFFFFU);
|
||||||
|
CHECK(dummy.getFieldU32(f) == 0xFFFFFFFFU);
|
||||||
|
|
||||||
|
CHECK(dummy.isFieldPresent(f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STI_UINT64: {
|
||||||
|
dummy.setFieldU64(f, 0);
|
||||||
|
CHECK(dummy.getFieldU64(f) == 0);
|
||||||
|
|
||||||
|
dummy.setFieldU64(f, 0xFFFFFFFFFFFFFFFFU);
|
||||||
|
CHECK(dummy.getFieldU64(f) == 0xFFFFFFFFFFFFFFFFU);
|
||||||
|
|
||||||
|
CHECK(dummy.isFieldPresent(f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STI_UINT256: {
|
||||||
|
uint256 u = uint256::fromVoid(
|
||||||
|
"DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDE"
|
||||||
|
"ADBEEF");
|
||||||
|
dummy.setFieldH256(f, u);
|
||||||
|
CHECK(dummy.getFieldH256(f) == u);
|
||||||
|
CHECK(dummy.isFieldPresent(f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STI_VL: {
|
||||||
|
std::vector<uint8_t> v{1, 2, 3};
|
||||||
|
dummy.setFieldVL(f, v);
|
||||||
|
CHECK(dummy.getFieldVL(f) == v);
|
||||||
|
CHECK(dummy.isFieldPresent(f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STI_ACCOUNT: {
|
||||||
|
AccountID id = *parseBase58<AccountID>(
|
||||||
|
"rwfSjJNK2YQuN64bSWn7T2eY9FJAyAPYJT");
|
||||||
|
dummy.setAccountID(f, id);
|
||||||
|
CHECK(dummy.getAccountID(f) == id);
|
||||||
|
CHECK(dummy.isFieldPresent(f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STI_OBJECT: {
|
||||||
|
dummy.emplace_back(STObject{f});
|
||||||
|
CHECK(dummy.getField(f).getFName() == f);
|
||||||
|
CHECK(dummy.isFieldPresent(f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STI_ARRAY: {
|
||||||
|
STArray dummy2{f, 2};
|
||||||
|
dummy2.push_back(STObject{sfGeneric});
|
||||||
|
dummy2.push_back(STObject{sfGeneric});
|
||||||
|
dummy.setFieldArray(f, dummy2);
|
||||||
|
CHECK(dummy.getFieldArray(f) == dummy2);
|
||||||
|
CHECK(dummy.isFieldPresent(f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
CHECK(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUITE_END();
|
||||||
@@ -17,15 +17,14 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <test/jtx.h>
|
|
||||||
|
|
||||||
#include <xrpl/basics/contract.h>
|
#include <xrpl/basics/contract.h>
|
||||||
#include <xrpl/beast/unit_test.h>
|
#include <xrpl/json/json_reader.h>
|
||||||
#include <xrpl/json/json_reader.h> // Json::Reader
|
#include <xrpl/protocol/ErrorCodes.h>
|
||||||
#include <xrpl/protocol/ErrorCodes.h> // RPC::containsError
|
#include <xrpl/protocol/STParsedJSON.h>
|
||||||
#include <xrpl/protocol/STParsedJSON.h> // STParsedJSONObject
|
|
||||||
|
|
||||||
namespace ripple {
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
|
using namespace ripple;
|
||||||
|
|
||||||
namespace InnerObjectFormatsUnitTestDetail {
|
namespace InnerObjectFormatsUnitTestDetail {
|
||||||
|
|
||||||
@@ -36,7 +35,6 @@ struct TestJSONTxt
|
|||||||
};
|
};
|
||||||
|
|
||||||
static TestJSONTxt const testArray[] = {
|
static TestJSONTxt const testArray[] = {
|
||||||
|
|
||||||
// Valid SignerEntry
|
// Valid SignerEntry
|
||||||
{R"({
|
{R"({
|
||||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||||
@@ -61,7 +59,6 @@ static TestJSONTxt const testArray[] = {
|
|||||||
"TransactionType" : "SignerListSet"
|
"TransactionType" : "SignerListSet"
|
||||||
})",
|
})",
|
||||||
false},
|
false},
|
||||||
|
|
||||||
// SignerEntry missing Account
|
// SignerEntry missing Account
|
||||||
{R"({
|
{R"({
|
||||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||||
@@ -85,7 +82,6 @@ static TestJSONTxt const testArray[] = {
|
|||||||
"TransactionType" : "SignerListSet"
|
"TransactionType" : "SignerListSet"
|
||||||
})",
|
})",
|
||||||
true},
|
true},
|
||||||
|
|
||||||
// SignerEntry missing SignerWeight
|
// SignerEntry missing SignerWeight
|
||||||
{R"({
|
{R"({
|
||||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||||
@@ -109,7 +105,6 @@ static TestJSONTxt const testArray[] = {
|
|||||||
"TransactionType" : "SignerListSet"
|
"TransactionType" : "SignerListSet"
|
||||||
})",
|
})",
|
||||||
true},
|
true},
|
||||||
|
|
||||||
// SignerEntry with unexpected Amount
|
// SignerEntry with unexpected Amount
|
||||||
{R"({
|
{R"({
|
||||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||||
@@ -135,7 +130,6 @@ static TestJSONTxt const testArray[] = {
|
|||||||
"TransactionType" : "SignerListSet"
|
"TransactionType" : "SignerListSet"
|
||||||
})",
|
})",
|
||||||
true},
|
true},
|
||||||
|
|
||||||
// SignerEntry with no Account and unexpected Amount
|
// SignerEntry with no Account and unexpected Amount
|
||||||
{R"({
|
{R"({
|
||||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||||
@@ -160,22 +154,16 @@ static TestJSONTxt const testArray[] = {
|
|||||||
"TransactionType" : "SignerListSet"
|
"TransactionType" : "SignerListSet"
|
||||||
})",
|
})",
|
||||||
true},
|
true},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace InnerObjectFormatsUnitTestDetail
|
} // namespace InnerObjectFormatsUnitTestDetail
|
||||||
|
|
||||||
class InnerObjectFormatsParsedJSON_test : public beast::unit_test::suite
|
TEST_SUITE_BEGIN("InnerObjectFormatsParsedJSON");
|
||||||
{
|
|
||||||
public:
|
TEST_CASE("InnerObjectFormatsParsedJSON")
|
||||||
void
|
|
||||||
run() override
|
|
||||||
{
|
{
|
||||||
using namespace InnerObjectFormatsUnitTestDetail;
|
using namespace InnerObjectFormatsUnitTestDetail;
|
||||||
|
|
||||||
// Instantiate a jtx::Env so debugLog writes are exercised.
|
|
||||||
test::jtx::Env env(*this);
|
|
||||||
|
|
||||||
for (auto const& test : testArray)
|
for (auto const& test : testArray)
|
||||||
{
|
{
|
||||||
Json::Value req;
|
Json::Value req;
|
||||||
@@ -188,19 +176,14 @@ public:
|
|||||||
STParsedJSONObject parsed("request", req);
|
STParsedJSONObject parsed("request", req);
|
||||||
bool const noObj = !parsed.object.has_value();
|
bool const noObj = !parsed.object.has_value();
|
||||||
if (noObj == test.expectFail)
|
if (noObj == test.expectFail)
|
||||||
{
|
CHECK(true);
|
||||||
pass();
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string errStr("Unexpected STParsedJSON result on:\n");
|
std::string errStr("Unexpected STParsedJSON result on:\n");
|
||||||
errStr += test.txt;
|
errStr += test.txt;
|
||||||
fail(errStr);
|
FAIL(errStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(InnerObjectFormatsParsedJSON, ripple_app, ripple);
|
TEST_SUITE_END();
|
||||||
|
|
||||||
} // namespace ripple
|
|
||||||
860
src/tests/libxrpl/protocol/Issue.cpp
Normal file
860
src/tests/libxrpl/protocol/Issue.cpp
Normal file
@@ -0,0 +1,860 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <xrpl/basics/UnorderedContainers.h>
|
||||||
|
#include <doctest/doctest.h>
|
||||||
|
#include <xrpl/protocol/Book.h>
|
||||||
|
#include <xrpl/protocol/Issue.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <set>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#define STL_SET_HAS_EMPLACE 1
|
||||||
|
#else
|
||||||
|
#define STL_SET_HAS_EMPLACE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||||
|
#if BEAST_MAC || BEAST_IOS
|
||||||
|
#define RIPPLE_ASSETS_ENABLE_STD_HASH 0
|
||||||
|
#else
|
||||||
|
#define RIPPLE_ASSETS_ENABLE_STD_HASH 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using Domain = uint256;
|
||||||
|
|
||||||
|
// Comparison, hash tests for uint60 (via base_uint)
|
||||||
|
template <typename Unsigned>
|
||||||
|
void
|
||||||
|
testUnsigned()
|
||||||
|
{
|
||||||
|
Unsigned const u1(1);
|
||||||
|
Unsigned const u2(2);
|
||||||
|
Unsigned const u3(3);
|
||||||
|
|
||||||
|
CHECK(u1 != u2);
|
||||||
|
CHECK(u1 < u2);
|
||||||
|
CHECK(u1 <= u2);
|
||||||
|
CHECK(u2 <= u2);
|
||||||
|
CHECK(u2 == u2);
|
||||||
|
CHECK(u2 >= u2);
|
||||||
|
CHECK(u3 >= u2);
|
||||||
|
CHECK(u3 > u2);
|
||||||
|
|
||||||
|
std::hash<Unsigned> hash;
|
||||||
|
|
||||||
|
CHECK(hash(u1) == hash(u1));
|
||||||
|
CHECK(hash(u2) == hash(u2));
|
||||||
|
CHECK(hash(u3) == hash(u3));
|
||||||
|
CHECK(hash(u1) != hash(u2));
|
||||||
|
CHECK(hash(u1) != hash(u3));
|
||||||
|
CHECK(hash(u2) != hash(u3));
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Comparison, hash tests for Issue
|
||||||
|
template <class Issue>
|
||||||
|
void
|
||||||
|
testIssue()
|
||||||
|
{
|
||||||
|
Currency const c1(1);
|
||||||
|
AccountID const i1(1);
|
||||||
|
Currency const c2(2);
|
||||||
|
AccountID const i2(2);
|
||||||
|
Currency const c3(3);
|
||||||
|
AccountID const i3(3);
|
||||||
|
|
||||||
|
CHECK(Issue(c1, i1) != Issue(c2, i1));
|
||||||
|
CHECK(Issue(c1, i1) < Issue(c2, i1));
|
||||||
|
CHECK(Issue(c1, i1) <= Issue(c2, i1));
|
||||||
|
CHECK(Issue(c2, i1) <= Issue(c2, i1));
|
||||||
|
CHECK(Issue(c2, i1) == Issue(c2, i1));
|
||||||
|
CHECK(Issue(c2, i1) >= Issue(c2, i1));
|
||||||
|
CHECK(Issue(c3, i1) >= Issue(c2, i1));
|
||||||
|
CHECK(Issue(c3, i1) > Issue(c2, i1));
|
||||||
|
CHECK(Issue(c1, i1) != Issue(c1, i2));
|
||||||
|
CHECK(Issue(c1, i1) < Issue(c1, i2));
|
||||||
|
CHECK(Issue(c1, i1) <= Issue(c1, i2));
|
||||||
|
CHECK(Issue(c1, i2) <= Issue(c1, i2));
|
||||||
|
CHECK(Issue(c1, i2) == Issue(c1, i2));
|
||||||
|
CHECK(Issue(c1, i2) >= Issue(c1, i2));
|
||||||
|
CHECK(Issue(c1, i3) >= Issue(c1, i2));
|
||||||
|
CHECK(Issue(c1, i3) > Issue(c1, i2));
|
||||||
|
|
||||||
|
std::hash<Issue> hash;
|
||||||
|
|
||||||
|
CHECK(hash(Issue(c1, i1)) == hash(Issue(c1, i1)));
|
||||||
|
CHECK(hash(Issue(c1, i2)) == hash(Issue(c1, i2)));
|
||||||
|
CHECK(hash(Issue(c1, i3)) == hash(Issue(c1, i3)));
|
||||||
|
CHECK(hash(Issue(c2, i1)) == hash(Issue(c2, i1)));
|
||||||
|
CHECK(hash(Issue(c2, i2)) == hash(Issue(c2, i2)));
|
||||||
|
CHECK(hash(Issue(c2, i3)) == hash(Issue(c2, i3)));
|
||||||
|
CHECK(hash(Issue(c3, i1)) == hash(Issue(c3, i1)));
|
||||||
|
CHECK(hash(Issue(c3, i2)) == hash(Issue(c3, i2)));
|
||||||
|
CHECK(hash(Issue(c3, i3)) == hash(Issue(c3, i3)));
|
||||||
|
CHECK(hash(Issue(c1, i1)) != hash(Issue(c1, i2)));
|
||||||
|
CHECK(hash(Issue(c1, i1)) != hash(Issue(c1, i3)));
|
||||||
|
CHECK(hash(Issue(c1, i1)) != hash(Issue(c2, i1)));
|
||||||
|
CHECK(hash(Issue(c1, i1)) != hash(Issue(c2, i2)));
|
||||||
|
CHECK(hash(Issue(c1, i1)) != hash(Issue(c2, i3)));
|
||||||
|
CHECK(hash(Issue(c1, i1)) != hash(Issue(c3, i1)));
|
||||||
|
CHECK(hash(Issue(c1, i1)) != hash(Issue(c3, i2)));
|
||||||
|
CHECK(hash(Issue(c1, i1)) != hash(Issue(c3, i3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Set>
|
||||||
|
void
|
||||||
|
testIssueSet()
|
||||||
|
{
|
||||||
|
Currency const c1(1);
|
||||||
|
AccountID const i1(1);
|
||||||
|
Currency const c2(2);
|
||||||
|
AccountID const i2(2);
|
||||||
|
Issue const a1(c1, i1);
|
||||||
|
Issue const a2(c2, i2);
|
||||||
|
|
||||||
|
{
|
||||||
|
Set c;
|
||||||
|
|
||||||
|
c.insert(a1);
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(a2);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Issue(c1, i2)) == 0);
|
||||||
|
CHECK(c.erase(Issue(c1, i1)) == 1);
|
||||||
|
CHECK(c.erase(Issue(c2, i2)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Set c;
|
||||||
|
|
||||||
|
c.insert(a1);
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(a2);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Issue(c1, i2)) == 0);
|
||||||
|
CHECK(c.erase(Issue(c1, i1)) == 1);
|
||||||
|
CHECK(c.erase(Issue(c2, i2)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
|
||||||
|
#if STL_SET_HAS_EMPLACE
|
||||||
|
c.emplace(c1, i1);
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.emplace(c2, i2);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Map>
|
||||||
|
void
|
||||||
|
testIssueMap()
|
||||||
|
{
|
||||||
|
Currency const c1(1);
|
||||||
|
AccountID const i1(1);
|
||||||
|
Currency const c2(2);
|
||||||
|
AccountID const i2(2);
|
||||||
|
Issue const a1(c1, i1);
|
||||||
|
Issue const a2(c2, i2);
|
||||||
|
|
||||||
|
{
|
||||||
|
Map c;
|
||||||
|
|
||||||
|
c.insert(std::make_pair(a1, 1));
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(std::make_pair(a2, 2));
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Issue(c1, i2)) == 0);
|
||||||
|
CHECK(c.erase(Issue(c1, i1)) == 1);
|
||||||
|
CHECK(c.erase(Issue(c2, i2)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Map c;
|
||||||
|
|
||||||
|
c.insert(std::make_pair(a1, 1));
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(std::make_pair(a2, 2));
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Issue(c1, i2)) == 0);
|
||||||
|
CHECK(c.erase(Issue(c1, i1)) == 1);
|
||||||
|
CHECK(c.erase(Issue(c2, i2)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Set>
|
||||||
|
void
|
||||||
|
testIssueDomainSet()
|
||||||
|
{
|
||||||
|
Currency const c1(1);
|
||||||
|
AccountID const i1(1);
|
||||||
|
Currency const c2(2);
|
||||||
|
AccountID const i2(2);
|
||||||
|
Issue const a1(c1, i1);
|
||||||
|
Issue const a2(c2, i2);
|
||||||
|
uint256 const domain1{1};
|
||||||
|
uint256 const domain2{2};
|
||||||
|
|
||||||
|
Set c;
|
||||||
|
|
||||||
|
c.insert(std::make_pair(a1, domain1));
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(std::make_pair(a2, domain1));
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
c.insert(std::make_pair(a2, domain2));
|
||||||
|
CHECK(c.size() == 3);
|
||||||
|
|
||||||
|
CHECK(c.erase(std::make_pair(Issue(c1, i2), domain1)) == 0);
|
||||||
|
CHECK(c.erase(std::make_pair(a1, domain1)) == 1);
|
||||||
|
CHECK(c.erase(std::make_pair(a2, domain1)) == 1);
|
||||||
|
CHECK(c.erase(std::make_pair(a2, domain2)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Map>
|
||||||
|
void
|
||||||
|
testIssueDomainMap()
|
||||||
|
{
|
||||||
|
Currency const c1(1);
|
||||||
|
AccountID const i1(1);
|
||||||
|
Currency const c2(2);
|
||||||
|
AccountID const i2(2);
|
||||||
|
Issue const a1(c1, i1);
|
||||||
|
Issue const a2(c2, i2);
|
||||||
|
uint256 const domain1{1};
|
||||||
|
uint256 const domain2{2};
|
||||||
|
|
||||||
|
Map c;
|
||||||
|
|
||||||
|
c.insert(std::make_pair(std::make_pair(a1, domain1), 1));
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(std::make_pair(std::make_pair(a2, domain1), 2));
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
c.insert(std::make_pair(std::make_pair(a2, domain2), 2));
|
||||||
|
CHECK(c.size() == 3);
|
||||||
|
|
||||||
|
CHECK(c.erase(std::make_pair(Issue(c1, i2), domain1)) == 0);
|
||||||
|
CHECK(c.erase(std::make_pair(a1, domain1)) == 1);
|
||||||
|
CHECK(c.erase(std::make_pair(a2, domain1)) == 1);
|
||||||
|
CHECK(c.erase(std::make_pair(a2, domain2)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Comparison, hash tests for Book
|
||||||
|
template <class Book>
|
||||||
|
void
|
||||||
|
testBook()
|
||||||
|
{
|
||||||
|
Currency const c1(1);
|
||||||
|
AccountID const i1(1);
|
||||||
|
Currency const c2(2);
|
||||||
|
AccountID const i2(2);
|
||||||
|
Currency const c3(3);
|
||||||
|
AccountID const i3(3);
|
||||||
|
|
||||||
|
Issue a1(c1, i1);
|
||||||
|
Issue a2(c1, i2);
|
||||||
|
Issue a3(c2, i2);
|
||||||
|
Issue a4(c3, i2);
|
||||||
|
uint256 const domain1{1};
|
||||||
|
uint256 const domain2{2};
|
||||||
|
|
||||||
|
// Books without domains
|
||||||
|
CHECK(Book(a1, a2, std::nullopt) != Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a1, a2, std::nullopt) < Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a1, a2, std::nullopt) <= Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a2, a3, std::nullopt) <= Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a2, a3, std::nullopt) >= Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a3, a4, std::nullopt) >= Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a3, a4, std::nullopt) > Book(a2, a3, std::nullopt));
|
||||||
|
|
||||||
|
// test domain books
|
||||||
|
{
|
||||||
|
// Books with different domains
|
||||||
|
CHECK(Book(a2, a3, domain1) != Book(a2, a3, domain2));
|
||||||
|
CHECK(Book(a2, a3, domain1) < Book(a2, a3, domain2));
|
||||||
|
CHECK(Book(a2, a3, domain2) > Book(a2, a3, domain1));
|
||||||
|
|
||||||
|
// One Book has a domain, the other does not
|
||||||
|
CHECK(Book(a2, a3, domain1) != Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a2, a3, std::nullopt) < Book(a2, a3, domain1));
|
||||||
|
CHECK(Book(a2, a3, domain1) > Book(a2, a3, std::nullopt));
|
||||||
|
|
||||||
|
// Both Books have the same domain
|
||||||
|
CHECK(Book(a2, a3, domain1) == Book(a2, a3, domain1));
|
||||||
|
CHECK(Book(a2, a3, domain2) == Book(a2, a3, domain2));
|
||||||
|
CHECK(
|
||||||
|
Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt));
|
||||||
|
|
||||||
|
// Both Books have no domain
|
||||||
|
CHECK(
|
||||||
|
Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt));
|
||||||
|
|
||||||
|
// Testing comparisons with >= and <=
|
||||||
|
|
||||||
|
// When comparing books with domain1 vs domain2
|
||||||
|
CHECK(Book(a2, a3, domain1) <= Book(a2, a3, domain2));
|
||||||
|
CHECK(Book(a2, a3, domain2) >= Book(a2, a3, domain1));
|
||||||
|
CHECK(Book(a2, a3, domain1) >= Book(a2, a3, domain1));
|
||||||
|
CHECK(Book(a2, a3, domain2) <= Book(a2, a3, domain2));
|
||||||
|
|
||||||
|
// One Book has domain1 and the other has no domain
|
||||||
|
CHECK(Book(a2, a3, domain1) > Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a2, a3, std::nullopt) < Book(a2, a3, domain1));
|
||||||
|
|
||||||
|
// One Book has domain2 and the other has no domain
|
||||||
|
CHECK(Book(a2, a3, domain2) > Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a2, a3, std::nullopt) < Book(a2, a3, domain2));
|
||||||
|
|
||||||
|
// Comparing two Books with no domains
|
||||||
|
CHECK(
|
||||||
|
Book(a2, a3, std::nullopt) <= Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(
|
||||||
|
Book(a2, a3, std::nullopt) >= Book(a2, a3, std::nullopt));
|
||||||
|
|
||||||
|
// Test case where domain1 is less than domain2
|
||||||
|
CHECK(Book(a2, a3, domain1) <= Book(a2, a3, domain2));
|
||||||
|
CHECK(Book(a2, a3, domain2) >= Book(a2, a3, domain1));
|
||||||
|
|
||||||
|
// Test case where domain2 is equal to domain1
|
||||||
|
CHECK(Book(a2, a3, domain1) >= Book(a2, a3, domain1));
|
||||||
|
CHECK(Book(a2, a3, domain1) <= Book(a2, a3, domain1));
|
||||||
|
|
||||||
|
// More test cases involving a4 (with domain2)
|
||||||
|
|
||||||
|
// Comparing Book with domain2 (a4) to a Book with domain1
|
||||||
|
CHECK(Book(a2, a3, domain1) < Book(a3, a4, domain2));
|
||||||
|
CHECK(Book(a3, a4, domain2) > Book(a2, a3, domain1));
|
||||||
|
|
||||||
|
// Comparing Book with domain2 (a4) to a Book with no domain
|
||||||
|
CHECK(Book(a3, a4, domain2) > Book(a2, a3, std::nullopt));
|
||||||
|
CHECK(Book(a2, a3, std::nullopt) < Book(a3, a4, domain2));
|
||||||
|
|
||||||
|
// Comparing Book with domain2 (a4) to a Book with the same domain
|
||||||
|
CHECK(Book(a3, a4, domain2) == Book(a3, a4, domain2));
|
||||||
|
|
||||||
|
// Comparing Book with domain2 (a4) to a Book with domain1
|
||||||
|
CHECK(Book(a2, a3, domain1) < Book(a3, a4, domain2));
|
||||||
|
CHECK(Book(a3, a4, domain2) > Book(a2, a3, domain1));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::hash<Book> hash;
|
||||||
|
|
||||||
|
// log << std::hex << hash (Book (a1, a2));
|
||||||
|
// log << std::hex << hash (Book (a1, a2));
|
||||||
|
//
|
||||||
|
// log << std::hex << hash (Book (a1, a3));
|
||||||
|
// log << std::hex << hash (Book (a1, a3));
|
||||||
|
//
|
||||||
|
// log << std::hex << hash (Book (a1, a4));
|
||||||
|
// log << std::hex << hash (Book (a1, a4));
|
||||||
|
//
|
||||||
|
// log << std::hex << hash (Book (a2, a3));
|
||||||
|
// log << std::hex << hash (Book (a2, a3));
|
||||||
|
//
|
||||||
|
// log << std::hex << hash (Book (a2, a4));
|
||||||
|
// log << std::hex << hash (Book (a2, a4));
|
||||||
|
//
|
||||||
|
// log << std::hex << hash (Book (a3, a4));
|
||||||
|
// log << std::hex << hash (Book (a3, a4));
|
||||||
|
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, std::nullopt)) ==
|
||||||
|
hash(Book(a1, a2, std::nullopt)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a3, std::nullopt)) ==
|
||||||
|
hash(Book(a1, a3, std::nullopt)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a4, std::nullopt)) ==
|
||||||
|
hash(Book(a1, a4, std::nullopt)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a3, std::nullopt)) ==
|
||||||
|
hash(Book(a2, a3, std::nullopt)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a4, std::nullopt)) ==
|
||||||
|
hash(Book(a2, a4, std::nullopt)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a3, a4, std::nullopt)) ==
|
||||||
|
hash(Book(a3, a4, std::nullopt)));
|
||||||
|
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, std::nullopt)) !=
|
||||||
|
hash(Book(a1, a3, std::nullopt)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, std::nullopt)) !=
|
||||||
|
hash(Book(a1, a4, std::nullopt)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, std::nullopt)) !=
|
||||||
|
hash(Book(a2, a3, std::nullopt)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, std::nullopt)) !=
|
||||||
|
hash(Book(a2, a4, std::nullopt)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, std::nullopt)) !=
|
||||||
|
hash(Book(a3, a4, std::nullopt)));
|
||||||
|
|
||||||
|
// Books with domain
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, domain1)) == hash(Book(a1, a2, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a3, domain1)) == hash(Book(a1, a3, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a4, domain1)) == hash(Book(a1, a4, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a3, domain1)) == hash(Book(a2, a3, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a4, domain1)) == hash(Book(a2, a4, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a3, a4, domain1)) == hash(Book(a3, a4, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, std::nullopt)) ==
|
||||||
|
hash(Book(a1, a2, std::nullopt)));
|
||||||
|
|
||||||
|
// Comparing Books with domain1 vs no domain
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, std::nullopt)) != hash(Book(a1, a2, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a3, std::nullopt)) != hash(Book(a1, a3, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a4, std::nullopt)) != hash(Book(a1, a4, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a3, std::nullopt)) != hash(Book(a2, a3, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a4, std::nullopt)) != hash(Book(a2, a4, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a3, a4, std::nullopt)) != hash(Book(a3, a4, domain1)));
|
||||||
|
|
||||||
|
// Books with domain1 but different Issues
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, domain1)) != hash(Book(a1, a3, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, domain1)) != hash(Book(a1, a4, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a3, domain1)) != hash(Book(a2, a4, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, domain1)) != hash(Book(a2, a3, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a4, domain1)) != hash(Book(a3, a4, domain1)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a3, a4, domain1)) != hash(Book(a1, a4, domain1)));
|
||||||
|
|
||||||
|
// Books with domain1 and domain2
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a2, domain1)) != hash(Book(a1, a2, domain2)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a3, domain1)) != hash(Book(a1, a3, domain2)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a1, a4, domain1)) != hash(Book(a1, a4, domain2)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a3, domain1)) != hash(Book(a2, a3, domain2)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a2, a4, domain1)) != hash(Book(a2, a4, domain2)));
|
||||||
|
CHECK(
|
||||||
|
hash(Book(a3, a4, domain1)) != hash(Book(a3, a4, domain2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class Set>
|
||||||
|
void
|
||||||
|
testBookSet()
|
||||||
|
{
|
||||||
|
Currency const c1(1);
|
||||||
|
AccountID const i1(1);
|
||||||
|
Currency const c2(2);
|
||||||
|
AccountID const i2(2);
|
||||||
|
Issue const a1(c1, i1);
|
||||||
|
Issue const a2(c2, i2);
|
||||||
|
Book const b1(a1, a2, std::nullopt);
|
||||||
|
Book const b2(a2, a1, std::nullopt);
|
||||||
|
|
||||||
|
uint256 const domain1{1};
|
||||||
|
uint256 const domain2{2};
|
||||||
|
|
||||||
|
Book const b1_d1(a1, a2, domain1);
|
||||||
|
Book const b2_d1(a2, a1, domain1);
|
||||||
|
Book const b1_d2(a1, a2, domain2);
|
||||||
|
Book const b2_d2(a2, a1, domain2);
|
||||||
|
|
||||||
|
{
|
||||||
|
Set c;
|
||||||
|
|
||||||
|
c.insert(b1);
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(b2);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a1, std::nullopt)) == 0);
|
||||||
|
CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Set c;
|
||||||
|
|
||||||
|
c.insert(b1);
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(b2);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a1, std::nullopt)) == 0);
|
||||||
|
CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
|
||||||
|
#if STL_SET_HAS_EMPLACE
|
||||||
|
c.emplace(a1, a2);
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.emplace(a2, a1);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Set c;
|
||||||
|
|
||||||
|
c.insert(b1_d1);
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(b2_d1);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
c.insert(b1_d2);
|
||||||
|
CHECK(c.size() == 3);
|
||||||
|
c.insert(b2_d2);
|
||||||
|
CHECK(c.size() == 4);
|
||||||
|
|
||||||
|
// Try removing non-existent elements
|
||||||
|
CHECK(c.erase(Book(a2, a2, domain1)) == 0);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a2, domain1)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, domain1)) == 1);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a2, domain2)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, domain2)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Set c;
|
||||||
|
|
||||||
|
c.insert(b1);
|
||||||
|
c.insert(b2);
|
||||||
|
c.insert(b1_d1);
|
||||||
|
c.insert(b2_d1);
|
||||||
|
CHECK(c.size() == 4);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a2, domain1)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, domain1)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Map>
|
||||||
|
void
|
||||||
|
testBookMap()
|
||||||
|
{
|
||||||
|
Currency const c1(1);
|
||||||
|
AccountID const i1(1);
|
||||||
|
Currency const c2(2);
|
||||||
|
AccountID const i2(2);
|
||||||
|
Issue const a1(c1, i1);
|
||||||
|
Issue const a2(c2, i2);
|
||||||
|
Book const b1(a1, a2, std::nullopt);
|
||||||
|
Book const b2(a2, a1, std::nullopt);
|
||||||
|
|
||||||
|
uint256 const domain1{1};
|
||||||
|
uint256 const domain2{2};
|
||||||
|
|
||||||
|
Book const b1_d1(a1, a2, domain1);
|
||||||
|
Book const b2_d1(a2, a1, domain1);
|
||||||
|
Book const b1_d2(a1, a2, domain2);
|
||||||
|
Book const b2_d2(a2, a1, domain2);
|
||||||
|
|
||||||
|
// typename Map::value_type value_type;
|
||||||
|
// std::pair <Book const, int> value_type;
|
||||||
|
|
||||||
|
{
|
||||||
|
Map c;
|
||||||
|
|
||||||
|
// c.insert (value_type (b1, 1));
|
||||||
|
c.insert(std::make_pair(b1, 1));
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
// c.insert (value_type (b2, 2));
|
||||||
|
c.insert(std::make_pair(b2, 1));
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a1, std::nullopt)) == 0);
|
||||||
|
CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Map c;
|
||||||
|
|
||||||
|
// c.insert (value_type (b1, 1));
|
||||||
|
c.insert(std::make_pair(b1, 1));
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
// c.insert (value_type (b2, 2));
|
||||||
|
c.insert(std::make_pair(b2, 1));
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a1, std::nullopt)) == 0);
|
||||||
|
CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Map c;
|
||||||
|
|
||||||
|
c.insert(std::make_pair(b1_d1, 10));
|
||||||
|
CHECK(c.size() == 1);
|
||||||
|
c.insert(std::make_pair(b2_d1, 20));
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
c.insert(std::make_pair(b1_d2, 30));
|
||||||
|
CHECK(c.size() == 3);
|
||||||
|
c.insert(std::make_pair(b2_d2, 40));
|
||||||
|
CHECK(c.size() == 4);
|
||||||
|
|
||||||
|
// Try removing non-existent elements
|
||||||
|
CHECK(c.erase(Book(a2, a2, domain1)) == 0);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a2, domain1)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, domain1)) == 1);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a2, domain2)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, domain2)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Map c;
|
||||||
|
|
||||||
|
c.insert(std::make_pair(b1, 1));
|
||||||
|
c.insert(std::make_pair(b2, 2));
|
||||||
|
c.insert(std::make_pair(b1_d1, 3));
|
||||||
|
c.insert(std::make_pair(b2_d1, 4));
|
||||||
|
CHECK(c.size() == 4);
|
||||||
|
|
||||||
|
// Try removing non-existent elements
|
||||||
|
CHECK(c.erase(Book(a1, a1, domain1)) == 0);
|
||||||
|
CHECK(c.erase(Book(a2, a2, domain2)) == 0);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1);
|
||||||
|
CHECK(c.size() == 2);
|
||||||
|
|
||||||
|
CHECK(c.erase(Book(a1, a2, domain1)) == 1);
|
||||||
|
CHECK(c.erase(Book(a2, a1, domain1)) == 1);
|
||||||
|
CHECK(c.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// End of helper functions.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
|
using namespace ripple;
|
||||||
|
|
||||||
|
TEST_SUITE_BEGIN("Issue");
|
||||||
|
|
||||||
|
TEST_CASE("Unsigned types")
|
||||||
|
{
|
||||||
|
testUnsigned<Currency>();
|
||||||
|
testUnsigned<AccountID>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Issue")
|
||||||
|
{
|
||||||
|
testIssue<Issue>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Issue sets")
|
||||||
|
{
|
||||||
|
INFO("std::set <Issue>");
|
||||||
|
testIssueSet<std::set<Issue>>();
|
||||||
|
|
||||||
|
INFO("std::set <Issue>");
|
||||||
|
testIssueSet<std::set<Issue>>();
|
||||||
|
|
||||||
|
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||||
|
INFO("std::unordered_set <Issue>");
|
||||||
|
testIssueSet<std::unordered_set<Issue>>();
|
||||||
|
|
||||||
|
INFO("std::unordered_set <Issue>");
|
||||||
|
testIssueSet<std::unordered_set<Issue>>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
INFO("hash_set <Issue>");
|
||||||
|
testIssueSet<hash_set<Issue>>();
|
||||||
|
|
||||||
|
INFO("hash_set <Issue>");
|
||||||
|
testIssueSet<hash_set<Issue>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Issue maps")
|
||||||
|
{
|
||||||
|
INFO("std::map <Issue, int>");
|
||||||
|
testIssueMap<std::map<Issue, int>>();
|
||||||
|
|
||||||
|
INFO("std::map <Issue, int>");
|
||||||
|
testIssueMap<std::map<Issue, int>>();
|
||||||
|
|
||||||
|
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||||
|
INFO("std::unordered_map <Issue, int>");
|
||||||
|
testIssueMap<std::unordered_map<Issue, int>>();
|
||||||
|
|
||||||
|
INFO("std::unordered_map <Issue, int>");
|
||||||
|
testIssueMap<std::unordered_map<Issue, int>>();
|
||||||
|
|
||||||
|
INFO("hash_map <Issue, int>");
|
||||||
|
testIssueMap<hash_map<Issue, int>>();
|
||||||
|
|
||||||
|
INFO("hash_map <Issue, int>");
|
||||||
|
testIssueMap<hash_map<Issue, int>>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Book")
|
||||||
|
{
|
||||||
|
testBook<Book>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Book sets")
|
||||||
|
{
|
||||||
|
INFO("std::set <Book>");
|
||||||
|
testBookSet<std::set<Book>>();
|
||||||
|
|
||||||
|
INFO("std::set <Book>");
|
||||||
|
testBookSet<std::set<Book>>();
|
||||||
|
|
||||||
|
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||||
|
INFO("std::unordered_set <Book>");
|
||||||
|
testBookSet<std::unordered_set<Book>>();
|
||||||
|
|
||||||
|
INFO("std::unordered_set <Book>");
|
||||||
|
testBookSet<std::unordered_set<Book>>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
INFO("hash_set <Book>");
|
||||||
|
testBookSet<hash_set<Book>>();
|
||||||
|
|
||||||
|
INFO("hash_set <Book>");
|
||||||
|
testBookSet<hash_set<Book>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Book maps")
|
||||||
|
{
|
||||||
|
INFO("std::map <Book, int>");
|
||||||
|
testBookMap<std::map<Book, int>>();
|
||||||
|
|
||||||
|
INFO("std::map <Book, int>");
|
||||||
|
testBookMap<std::map<Book, int>>();
|
||||||
|
|
||||||
|
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||||
|
INFO("std::unordered_map <Book, int>");
|
||||||
|
testBookMap<std::unordered_map<Book, int>>();
|
||||||
|
|
||||||
|
INFO("std::unordered_map <Book, int>");
|
||||||
|
testBookMap<std::unordered_map<Book, int>>();
|
||||||
|
|
||||||
|
INFO("hash_map <Book, int>");
|
||||||
|
testBookMap<hash_map<Book, int>>();
|
||||||
|
|
||||||
|
INFO("hash_map <Book, int>");
|
||||||
|
testBookMap<hash_map<Book, int>>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Issue domain sets")
|
||||||
|
{
|
||||||
|
INFO("std::set <std::pair<Issue, Domain>>");
|
||||||
|
testIssueDomainSet<std::set<std::pair<Issue, Domain>>>();
|
||||||
|
|
||||||
|
INFO("std::set <std::pair<Issue, Domain>>");
|
||||||
|
testIssueDomainSet<std::set<std::pair<Issue, Domain>>>();
|
||||||
|
|
||||||
|
INFO("hash_set <std::pair<Issue, Domain>>");
|
||||||
|
testIssueDomainSet<hash_set<std::pair<Issue, Domain>>>();
|
||||||
|
|
||||||
|
INFO("hash_set <std::pair<Issue, Domain>>");
|
||||||
|
testIssueDomainSet<hash_set<std::pair<Issue, Domain>>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Issue domain maps")
|
||||||
|
{
|
||||||
|
INFO("std::map <std::pair<Issue, Domain>, int>");
|
||||||
|
testIssueDomainMap<std::map<std::pair<Issue, Domain>, int>>();
|
||||||
|
|
||||||
|
INFO("std::map <std::pair<Issue, Domain>, int>");
|
||||||
|
testIssueDomainMap<std::map<std::pair<Issue, Domain>, int>>();
|
||||||
|
|
||||||
|
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||||
|
INFO("hash_map <std::pair<Issue, Domain>, int>");
|
||||||
|
testIssueDomainMap<hash_map<std::pair<Issue, Domain>, int>>();
|
||||||
|
|
||||||
|
INFO("hash_map <std::pair<Issue, Domain>, int>");
|
||||||
|
testIssueDomainMap<hash_map<std::pair<Issue, Domain>, int>>();
|
||||||
|
|
||||||
|
INFO("hardened_hash_map <std::pair<Issue, Domain>, int>");
|
||||||
|
testIssueDomainMap<hardened_hash_map<std::pair<Issue, Domain>, int>>();
|
||||||
|
|
||||||
|
INFO("hardened_hash_map <std::pair<Issue, Domain>, int>");
|
||||||
|
testIssueDomainMap<hardened_hash_map<std::pair<Issue, Domain>, int>>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUITE_END();
|
||||||
|
|
||||||
|
|
||||||
129
src/tests/libxrpl/protocol/Memo.cpp
Normal file
129
src/tests/libxrpl/protocol/Memo.cpp
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2022 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <test/jtx.h>
|
||||||
|
#include <doctest/doctest.h>
|
||||||
|
#include <xrpl/beast/unit_test.h>
|
||||||
|
|
||||||
|
#include <xrpl/basics/strHex.h>
|
||||||
|
|
||||||
|
using namespace ripple;
|
||||||
|
|
||||||
|
TEST_SUITE_BEGIN("Memo");
|
||||||
|
|
||||||
|
TEST_CASE("Memo")
|
||||||
|
{
|
||||||
|
struct DummySuite : beast::unit_test::suite
|
||||||
|
{
|
||||||
|
void run() override {}
|
||||||
|
} suite;
|
||||||
|
|
||||||
|
using namespace test::jtx;
|
||||||
|
Account alice{"alice"};
|
||||||
|
|
||||||
|
Env env{suite};
|
||||||
|
env.fund(XRP(10000), alice);
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
// Lambda that returns a valid JTx with a memo that we can hack up.
|
||||||
|
// This is the basis for building tests of invalid states.
|
||||||
|
auto makeJtxWithMemo = [&env, &alice]() {
|
||||||
|
JTx example = noop(alice);
|
||||||
|
memo const exampleMemo{"tic", "tac", "toe"};
|
||||||
|
exampleMemo(env, example);
|
||||||
|
return example;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A valid memo.
|
||||||
|
env(makeJtxWithMemo());
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Make sure that too big a memo is flagged as invalid.
|
||||||
|
JTx memoSize = makeJtxWithMemo();
|
||||||
|
memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfMemoData.jsonName] =
|
||||||
|
std::string(2020, '0');
|
||||||
|
env(memoSize,
|
||||||
|
rpc(
|
||||||
|
"invalidTransaction",
|
||||||
|
"fails local checks: The memo exceeds the maximum allowed size."));
|
||||||
|
|
||||||
|
// This memo is just barely small enough.
|
||||||
|
memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfMemoData.jsonName] =
|
||||||
|
std::string(2018, '1');
|
||||||
|
env(memoSize);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Put a non-Memo in the Memos array.
|
||||||
|
JTx memoNonMemo = noop(alice);
|
||||||
|
auto& jv = memoNonMemo.jv;
|
||||||
|
auto& ma = jv[sfMemos.jsonName];
|
||||||
|
auto& mi = ma[ma.size()];
|
||||||
|
auto& m = mi[sfCreatedNode.jsonName]; // CreatedNode in Memos
|
||||||
|
m[sfMemoData.jsonName] = "3030303030";
|
||||||
|
|
||||||
|
env(
|
||||||
|
memoNonMemo,
|
||||||
|
rpc(
|
||||||
|
"invalidTransaction",
|
||||||
|
"fails local checks: A memo array may contain only Memo objects."));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Put an invalid field in a Memo object.
|
||||||
|
JTx memoExtra = makeJtxWithMemo();
|
||||||
|
memoExtra.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfFlags.jsonName] = 13;
|
||||||
|
env(
|
||||||
|
memoExtra,
|
||||||
|
rpc(
|
||||||
|
"invalidTransaction",
|
||||||
|
"fails local checks: A memo may contain only MemoType, MemoData or MemoFormat fields."));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Put a character that is not allowed in a URL in a MemoType field.
|
||||||
|
JTx memoBadChar = makeJtxWithMemo();
|
||||||
|
memoBadChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfMemoType.jsonName] =
|
||||||
|
strHex(std::string_view("ONE<INFINITY"));
|
||||||
|
env(
|
||||||
|
memoBadChar,
|
||||||
|
rpc(
|
||||||
|
"invalidTransaction",
|
||||||
|
"fails local checks: The MemoType and MemoFormat fields may only contain characters that are allowed in URLs under RFC 3986."));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Put a character that is not allowed in a URL in a MemoData field.
|
||||||
|
// That's okay.
|
||||||
|
JTx memoLegitChar = makeJtxWithMemo();
|
||||||
|
memoLegitChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfMemoData.jsonName] =
|
||||||
|
strHex(std::string_view("ONE<INFINITY"));
|
||||||
|
env(memoLegitChar);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Put a character that is not allowed in a URL in a MemoFormat.
|
||||||
|
JTx memoBadChar = makeJtxWithMemo();
|
||||||
|
memoBadChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfMemoFormat.jsonName] =
|
||||||
|
strHex(std::string_view("NoBraces{}InURL"));
|
||||||
|
env(
|
||||||
|
memoBadChar,
|
||||||
|
rpc(
|
||||||
|
"invalidTransaction",
|
||||||
|
"fails local checks: The MemoType and MemoFormat fields may only contain characters that are allowed in URLs under RFC 3986."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUITE_END();
|
||||||
646
src/tests/libxrpl/protocol/MultiApiJson.cpp
Normal file
646
src/tests/libxrpl/protocol/MultiApiJson.cpp
Normal file
@@ -0,0 +1,646 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/XRPLF/rippled/
|
||||||
|
Copyright (c) 2023 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <doctest/doctest.h>
|
||||||
|
#include <xrpl/protocol/MultiApiJson.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// This needs to be in a namespace because of deduction guide
|
||||||
|
template <typename... Ts>
|
||||||
|
struct Overload : Ts...
|
||||||
|
{
|
||||||
|
using Ts::operator()...;
|
||||||
|
};
|
||||||
|
template <typename... Ts>
|
||||||
|
Overload(Ts...) -> Overload<Ts...>;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
static auto
|
||||||
|
makeJson(char const* key, int val)
|
||||||
|
{
|
||||||
|
Json::Value obj(Json::objectValue);
|
||||||
|
obj[key] = val;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MultiApiJsonFixture
|
||||||
|
{
|
||||||
|
using MultiApiJson13 = ripple::detail::MultiApiJson<1, 3>;
|
||||||
|
|
||||||
|
Json::Value const obj1{makeJson("value", 1)};
|
||||||
|
Json::Value const obj2{makeJson("value", 2)};
|
||||||
|
Json::Value const obj3{makeJson("value", 3)};
|
||||||
|
Json::Value const jsonNull{};
|
||||||
|
|
||||||
|
MultiApiJsonFixture() = default;
|
||||||
|
};
|
||||||
|
TEST_SUITE_BEGIN("MultiApiJson");
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(
|
||||||
|
MultiApiJsonFixture,
|
||||||
|
"forApiVersions, forAllApiVersions",
|
||||||
|
"[MultiApiJson]")
|
||||||
|
{
|
||||||
|
using ripple::detail::MultiApiJson;
|
||||||
|
|
||||||
|
MultiApiJson13 subject{};
|
||||||
|
static_assert(sizeof(subject) == sizeof(subject.val));
|
||||||
|
static_assert(subject.size == subject.val.size());
|
||||||
|
static_assert(
|
||||||
|
std::is_same_v<decltype(subject.val), std::array<Json::Value, 3>>);
|
||||||
|
|
||||||
|
CHECK(subject.val.size() == 3);
|
||||||
|
CHECK(subject.val == std::array<Json::Value, 3>{jsonNull, jsonNull, jsonNull});
|
||||||
|
|
||||||
|
subject.val[0] = obj1;
|
||||||
|
subject.val[1] = obj2;
|
||||||
|
|
||||||
|
// Some static data for test inputs
|
||||||
|
static int const primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23,
|
||||||
|
29, 31, 37, 41, 43, 47, 53, 59, 61,
|
||||||
|
67, 71, 73, 79, 83, 89, 97};
|
||||||
|
static_assert(std::size(primes) > RPC::apiMaximumValidVersion);
|
||||||
|
|
||||||
|
MultiApiJson13 s1{};
|
||||||
|
static_assert(
|
||||||
|
s1.size ==
|
||||||
|
RPC::apiMaximumValidVersion + 1 - RPC::apiMinimumSupportedVersion);
|
||||||
|
|
||||||
|
int productAllVersions = 1;
|
||||||
|
for (unsigned i = RPC::apiMinimumSupportedVersion;
|
||||||
|
i <= RPC::apiMaximumValidVersion;
|
||||||
|
++i)
|
||||||
|
{
|
||||||
|
auto const index = i - RPC::apiMinimumSupportedVersion;
|
||||||
|
CHECK(index == s1.index(i));
|
||||||
|
CHECK(s1.valid(i));
|
||||||
|
s1.val[index] = makeJson("value", primes[i]);
|
||||||
|
productAllVersions *= primes[i];
|
||||||
|
}
|
||||||
|
CHECK(!s1.valid(0));
|
||||||
|
CHECK(!s1.valid(RPC::apiMaximumValidVersion + 1));
|
||||||
|
CHECK(
|
||||||
|
!s1.valid(std::numeric_limits<
|
||||||
|
decltype(RPC::apiMaximumValidVersion.value)>::max()));
|
||||||
|
|
||||||
|
int result = 1;
|
||||||
|
static_assert(
|
||||||
|
RPC::apiMinimumSupportedVersion + 1 <= RPC::apiMaximumValidVersion);
|
||||||
|
forApiVersions<
|
||||||
|
RPC::apiMinimumSupportedVersion,
|
||||||
|
RPC::apiMinimumSupportedVersion + 1>(
|
||||||
|
std::as_const(s1).visit(),
|
||||||
|
[](
|
||||||
|
Json::Value const& json,
|
||||||
|
unsigned int version,
|
||||||
|
int* result) {
|
||||||
|
CHECK(
|
||||||
|
version >= RPC::apiMinimumSupportedVersion &&
|
||||||
|
version <= RPC::apiMinimumSupportedVersion + 1);
|
||||||
|
if (CHECK(json.isMember("value")))
|
||||||
|
{
|
||||||
|
*result *= json["value"].asInt();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&result);
|
||||||
|
CHECK(
|
||||||
|
result ==
|
||||||
|
primes[RPC::apiMinimumSupportedVersion] *
|
||||||
|
primes[RPC::apiMinimumSupportedVersion + 1]);
|
||||||
|
|
||||||
|
// Check all the values with mutable data
|
||||||
|
forAllApiVersions(
|
||||||
|
s1.visit(), [&s1](Json::Value& json, auto version) {
|
||||||
|
CHECK(s1.val[s1.index(version)] == json);
|
||||||
|
if (CHECK(json.isMember("value")))
|
||||||
|
{
|
||||||
|
CHECK(json["value"].asInt() == primes[version]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
result = 1;
|
||||||
|
forAllApiVersions(
|
||||||
|
std::as_const(s1).visit(),
|
||||||
|
[](
|
||||||
|
Json::Value const& json,
|
||||||
|
unsigned int version,
|
||||||
|
int* result) {
|
||||||
|
CHECK(
|
||||||
|
version >= RPC::apiMinimumSupportedVersion &&
|
||||||
|
version <= RPC::apiMaximumValidVersion);
|
||||||
|
if (CHECK(json.isMember("value")))
|
||||||
|
{
|
||||||
|
*result *= json["value"].asInt();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&result);
|
||||||
|
|
||||||
|
CHECK(result == productAllVersions);
|
||||||
|
|
||||||
|
// Several overloads we want to fail
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return !requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](Json::Value&, auto) {}); // missing const
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return !requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](Json::Value&) {}); // missing const
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return !requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[]() {}); // missing parameters
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return !requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](auto) {},
|
||||||
|
1); // missing parameters
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return !requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](auto, auto) {},
|
||||||
|
1); // missing parameters
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return !requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](auto, auto, char const*) {},
|
||||||
|
1); // parameter type mismatch
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
|
||||||
|
// Sanity checks
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](auto) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](Json::Value const&) {});
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](auto...) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](Json::Value const&, auto...) {});
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](Json::Value&, auto, auto, auto...) {},
|
||||||
|
0,
|
||||||
|
"");
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[]<unsigned int Version>(
|
||||||
|
Json::Value const&,
|
||||||
|
std::integral_constant<unsigned int, Version>,
|
||||||
|
int,
|
||||||
|
char const*) {},
|
||||||
|
0,
|
||||||
|
"");
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](auto...) {});
|
||||||
|
};
|
||||||
|
}(std::move(s1)));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
forAllApiVersions(
|
||||||
|
std::forward<decltype(v)>(v).visit(), //
|
||||||
|
[](auto...) {});
|
||||||
|
};
|
||||||
|
}(std::move(std::as_const(s1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(
|
||||||
|
MultiApiJsonFixture,
|
||||||
|
"default copy construction / assignment",
|
||||||
|
"[MultiApiJson]")
|
||||||
|
{
|
||||||
|
using ripple::detail::MultiApiJson;
|
||||||
|
|
||||||
|
MultiApiJson13 subject{};
|
||||||
|
subject.val[0] = obj1;
|
||||||
|
subject.val[1] = obj2;
|
||||||
|
|
||||||
|
MultiApiJson13 x{subject};
|
||||||
|
|
||||||
|
CHECK(x.val.size() == subject.val.size());
|
||||||
|
CHECK(x.val[0] == subject.val[0]);
|
||||||
|
CHECK(x.val[1] == subject.val[1]);
|
||||||
|
CHECK(x.val[2] == subject.val[2]);
|
||||||
|
CHECK(x.val == subject.val);
|
||||||
|
CHECK(&x.val[0] != &subject.val[0]);
|
||||||
|
CHECK(&x.val[1] != &subject.val[1]);
|
||||||
|
CHECK(&x.val[2] != &subject.val[2]);
|
||||||
|
|
||||||
|
MultiApiJson13 y;
|
||||||
|
CHECK((y.val == std::array<Json::Value, 3>{}));
|
||||||
|
y = subject;
|
||||||
|
CHECK(y.val == subject.val);
|
||||||
|
CHECK(&y.val[0] != &subject.val[0]);
|
||||||
|
CHECK(&y.val[1] != &subject.val[1]);
|
||||||
|
CHECK(&y.val[2] != &subject.val[2]);
|
||||||
|
|
||||||
|
y = std::move(x);
|
||||||
|
CHECK(y.val == subject.val);
|
||||||
|
CHECK(&y.val[0] != &subject.val[0]);
|
||||||
|
CHECK(&y.val[1] != &subject.val[1]);
|
||||||
|
CHECK(&y.val[2] != &subject.val[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(MultiApiJsonFixture, "set", "[MultiApiJson]")
|
||||||
|
{
|
||||||
|
using ripple::detail::MultiApiJson;
|
||||||
|
|
||||||
|
auto x = MultiApiJson<1, 2>{Json::objectValue};
|
||||||
|
x.set("name1", 42);
|
||||||
|
CHECK(x.val[0].isMember("name1"));
|
||||||
|
CHECK(x.val[1].isMember("name1"));
|
||||||
|
CHECK(x.val[0]["name1"].isInt());
|
||||||
|
CHECK(x.val[1]["name1"].isInt());
|
||||||
|
CHECK(x.val[0]["name1"].asInt() == 42);
|
||||||
|
CHECK(x.val[1]["name1"].asInt() == 42);
|
||||||
|
|
||||||
|
x.set("name2", "bar");
|
||||||
|
CHECK(x.val[0].isMember("name2"));
|
||||||
|
CHECK(x.val[1].isMember("name2"));
|
||||||
|
CHECK(x.val[0]["name2"].isString());
|
||||||
|
CHECK(x.val[1]["name2"].isString());
|
||||||
|
CHECK(x.val[0]["name2"].asString() == "bar");
|
||||||
|
CHECK(x.val[1]["name2"].asString() == "bar");
|
||||||
|
|
||||||
|
// Tests of requires clause - these are expected to match
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires { v.set("name", Json::nullValue); };
|
||||||
|
}(x));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires { v.set("name", "value"); };
|
||||||
|
}(x));
|
||||||
|
static_assert(
|
||||||
|
[](auto&& v) { return requires { v.set("name", true); }; }(x));
|
||||||
|
static_assert(
|
||||||
|
[](auto&& v) { return requires { v.set("name", 42); }; }(x));
|
||||||
|
|
||||||
|
// Tests of requires clause - these are expected NOT to match
|
||||||
|
struct foo_t final {};
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return !requires { v.set("name", foo_t{}); };
|
||||||
|
}(x));
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return !requires { v.set("name", std::nullopt); };
|
||||||
|
}(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(MultiApiJsonFixture, "isMember", "[MultiApiJson]")
|
||||||
|
{
|
||||||
|
using ripple::detail::MultiApiJson;
|
||||||
|
|
||||||
|
MultiApiJson13 subject{};
|
||||||
|
subject.val[0] = obj1;
|
||||||
|
subject.val[1] = obj2;
|
||||||
|
|
||||||
|
// Well defined behaviour even if we have different types of members
|
||||||
|
CHECK(subject.isMember("foo") == decltype(subject)::none);
|
||||||
|
|
||||||
|
{
|
||||||
|
// All variants have element "One", none have element "Two"
|
||||||
|
MultiApiJson<1, 2> s1{};
|
||||||
|
s1.val[0] = makeJson("One", 12);
|
||||||
|
s1.val[1] = makeJson("One", 42);
|
||||||
|
CHECK(s1.isMember("One") == decltype(s1)::all);
|
||||||
|
CHECK(s1.isMember("Two") == decltype(s1)::none);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Some variants have element "One" and some have "Two"
|
||||||
|
MultiApiJson<1, 2> s2{};
|
||||||
|
s2.val[0] = makeJson("One", 12);
|
||||||
|
s2.val[1] = makeJson("Two", 42);
|
||||||
|
CHECK(s2.isMember("One") == decltype(s2)::some);
|
||||||
|
CHECK(s2.isMember("Two") == decltype(s2)::some);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Not all variants have element "One", because last one is null
|
||||||
|
MultiApiJson<1, 3> s3{};
|
||||||
|
s3.val[0] = makeJson("One", 12);
|
||||||
|
s3.val[1] = makeJson("One", 42);
|
||||||
|
CHECK(s3.isMember("One") == decltype(s3)::some);
|
||||||
|
CHECK(s3.isMember("Two") == decltype(s3)::none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(MultiApiJsonFixture, "visitor", "[MultiApiJson]")
|
||||||
|
{
|
||||||
|
using ripple::detail::MultiApiJson;
|
||||||
|
|
||||||
|
MultiApiJson13 s1{};
|
||||||
|
s1.val[0] = makeJson("value", 2);
|
||||||
|
s1.val[1] = makeJson("value", 3);
|
||||||
|
s1.val[2] = makeJson("value", 5);
|
||||||
|
|
||||||
|
CHECK(not s1.valid(0));
|
||||||
|
CHECK(s1.index(0) == 0);
|
||||||
|
|
||||||
|
CHECK(s1.valid(1));
|
||||||
|
CHECK(s1.index(1) == 0);
|
||||||
|
|
||||||
|
CHECK(not s1.valid(4));
|
||||||
|
|
||||||
|
// Test different overloads
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visitor(
|
||||||
|
v,
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
[](Json::Value&, std::integral_constant<unsigned, 1>) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
CHECK(
|
||||||
|
s1.visitor(
|
||||||
|
s1,
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
Overload{
|
||||||
|
[](Json::Value& v,
|
||||||
|
std::integral_constant<unsigned, 1>) {
|
||||||
|
return v["value"].asInt();
|
||||||
|
},
|
||||||
|
[](Json::Value const&, auto) { return 0; },
|
||||||
|
[](auto, auto) { return 0; }}) == 2);
|
||||||
|
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visitor(
|
||||||
|
v,
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
[](Json::Value&) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
CHECK(
|
||||||
|
s1.visitor(
|
||||||
|
s1,
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
Overload{
|
||||||
|
[](Json::Value& v) { return v["value"].asInt(); },
|
||||||
|
[](Json::Value const&) { return 0; },
|
||||||
|
[](auto...) { return 0; }}) == 2);
|
||||||
|
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visitor(
|
||||||
|
v,
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
[](Json::Value const&,
|
||||||
|
std::integral_constant<unsigned, 1>) {});
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
CHECK(
|
||||||
|
s1.visitor(
|
||||||
|
std::as_const(s1),
|
||||||
|
std::integral_constant<unsigned, 2>{},
|
||||||
|
Overload{
|
||||||
|
[](Json::Value const& v,
|
||||||
|
std::integral_constant<unsigned, 2>) {
|
||||||
|
return v["value"].asInt();
|
||||||
|
},
|
||||||
|
[](Json::Value&, auto) { return 0; },
|
||||||
|
[](auto, auto) { return 0; }}) == 3);
|
||||||
|
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visitor(
|
||||||
|
v,
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
[](auto, auto, auto...) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visitor(v, 1, [](auto, auto, auto...) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visitor(v, 1, [](auto, auto, auto...) {}, "");
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visitor(v, 1, [](auto, auto, auto, auto...) {}, "");
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(MultiApiJsonFixture, "visit", "[MultiApiJson]")
|
||||||
|
{
|
||||||
|
using ripple::detail::MultiApiJson;
|
||||||
|
|
||||||
|
MultiApiJson13 s1{};
|
||||||
|
s1.val[0] = makeJson("value", 2);
|
||||||
|
s1.val[1] = makeJson("value", 3);
|
||||||
|
s1.val[2] = makeJson("value", 5);
|
||||||
|
|
||||||
|
// Test different overloads
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visit(
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
[](Json::Value&, std::integral_constant<unsigned, 1>) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
CHECK(
|
||||||
|
s1.visit(
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
Overload{
|
||||||
|
[](Json::Value& v,
|
||||||
|
std::integral_constant<unsigned, 1>) {
|
||||||
|
return v["value"].asInt();
|
||||||
|
},
|
||||||
|
[](Json::Value const&, auto) { return 0; },
|
||||||
|
[](auto, auto) { return 0; }}) == 2);
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visit()(
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
[](Json::Value&, std::integral_constant<unsigned, 1>) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
CHECK(
|
||||||
|
s1.visit()(std::integral_constant<unsigned, 1>{},
|
||||||
|
Overload{[](Json::Value& v,
|
||||||
|
std::integral_constant<unsigned, 1>) {
|
||||||
|
return v["value"].asInt();
|
||||||
|
},
|
||||||
|
[](Json::Value const&, auto) { return 0; },
|
||||||
|
[](auto, auto) { return 0; }}) == 2);
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visit(
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
[](Json::Value&) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
CHECK(
|
||||||
|
s1.visit(
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
Overload{
|
||||||
|
[](Json::Value& v) { return v["value"].asInt(); },
|
||||||
|
[](Json::Value const&) { return 0; },
|
||||||
|
[](auto...) { return 0; }}) == 2);
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visit()(std::integral_constant<unsigned, 1>{}, [](Json::Value&) {});
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
CHECK(
|
||||||
|
s1.visit()(std::integral_constant<unsigned, 1>{},
|
||||||
|
Overload{[](Json::Value& v) { return v["value"].asInt(); },
|
||||||
|
[](Json::Value const&) { return 0; },
|
||||||
|
[](auto...) { return 0; }}) == 2);
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visit(
|
||||||
|
std::integral_constant<unsigned, 1>{},
|
||||||
|
[](Json::Value const&,
|
||||||
|
std::integral_constant<unsigned, 1>) {});
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
CHECK(
|
||||||
|
std::as_const(s1).visit(
|
||||||
|
std::integral_constant<unsigned, 2>{},
|
||||||
|
Overload{
|
||||||
|
[](Json::Value const& v,
|
||||||
|
std::integral_constant<unsigned, 2>) {
|
||||||
|
return v["value"].asInt();
|
||||||
|
},
|
||||||
|
[](Json::Value&, auto) { return 0; },
|
||||||
|
[](auto, auto) { return 0; }}) == 3);
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visit()(std::integral_constant<unsigned, 1>{},
|
||||||
|
[](Json::Value const&,
|
||||||
|
std::integral_constant<unsigned, 1>) {});
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
CHECK(
|
||||||
|
std::as_const(s1).visit()(std::integral_constant<unsigned, 2>{},
|
||||||
|
Overload{[](Json::Value const& v,
|
||||||
|
std::integral_constant<unsigned,
|
||||||
|
2>) {
|
||||||
|
return v["value"].asInt();
|
||||||
|
},
|
||||||
|
[](Json::Value&, auto) { return 0; },
|
||||||
|
[](auto, auto) { return 0; }}) == 3);
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visit(
|
||||||
|
std::integral_constant<unsigned, 1>{}, [](Json::Value const&) {});
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
CHECK(
|
||||||
|
std::as_const(s1).visit(
|
||||||
|
std::integral_constant<unsigned, 2>{},
|
||||||
|
Overload{
|
||||||
|
[](Json::Value const& v) { return v["value"].asInt(); },
|
||||||
|
[](Json::Value&) { return 0; },
|
||||||
|
[](auto...) { return 0; }}) == 3);
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visit()(std::integral_constant<unsigned, 1>{},
|
||||||
|
[](Json::Value const&) {});
|
||||||
|
};
|
||||||
|
}(std::as_const(s1)));
|
||||||
|
CHECK(
|
||||||
|
std::as_const(s1).visit()(std::integral_constant<unsigned, 2>{},
|
||||||
|
Overload{[](Json::Value const& v) {
|
||||||
|
return v["value"].asInt();
|
||||||
|
},
|
||||||
|
[](Json::Value&) { return 0; },
|
||||||
|
[](auto...) { return 0; }}) == 3);
|
||||||
|
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires { v.visit(v, 1, [](auto, auto, auto...) {}); };
|
||||||
|
}(s1));
|
||||||
|
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires { v.visit(v, 1, [](auto, auto, auto...) {}, ""); };
|
||||||
|
}(s1));
|
||||||
|
|
||||||
|
static_assert([](auto&& v) {
|
||||||
|
return requires {
|
||||||
|
v.visit(v, 1, [](auto, auto, auto, auto...) {}, "");
|
||||||
|
};
|
||||||
|
}(s1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUITE_END();
|
||||||
507
src/tests/libxrpl/protocol/PublicKey.cpp
Normal file
507
src/tests/libxrpl/protocol/PublicKey.cpp
Normal file
@@ -0,0 +1,507 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <doctest/doctest.h>
|
||||||
|
#include <xrpl/protocol/PublicKey.h>
|
||||||
|
#include <xrpl/protocol/SecretKey.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using blob = std::vector<std::uint8_t>;
|
||||||
|
|
||||||
|
template <class FwdIter, class Container>
|
||||||
|
void
|
||||||
|
hex_to_binary(FwdIter first, FwdIter last, Container& out)
|
||||||
|
{
|
||||||
|
struct Table
|
||||||
|
{
|
||||||
|
int val[256];
|
||||||
|
Table()
|
||||||
|
{
|
||||||
|
std::fill(val, val + 256, 0);
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
val['0' + i] = i;
|
||||||
|
for (int i = 0; i < 6; ++i)
|
||||||
|
{
|
||||||
|
val['A' + i] = 10 + i;
|
||||||
|
val['a' + i] = 10 + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int
|
||||||
|
operator[](int i)
|
||||||
|
{
|
||||||
|
return val[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static Table lut;
|
||||||
|
out.reserve(std::distance(first, last) / 2);
|
||||||
|
while (first != last)
|
||||||
|
{
|
||||||
|
auto const hi(lut[(*first++)]);
|
||||||
|
auto const lo(lut[(*first++)]);
|
||||||
|
out.push_back((hi * 16) + lo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blob
|
||||||
|
sig(std::string const& hex)
|
||||||
|
{
|
||||||
|
blob b;
|
||||||
|
hex_to_binary(hex.begin(), hex.end(), b);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
check(std::optional<ECDSACanonicality> answer, std::string const& s)
|
||||||
|
{
|
||||||
|
return ecdsaCanonicality(makeSlice(sig(s))) == answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_SUITE_BEGIN("PublicKey");
|
||||||
|
|
||||||
|
TEST_CASE("Base58")
|
||||||
|
{
|
||||||
|
INFO("Base58: secp256k1");
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const pk1 = derivePublicKey(
|
||||||
|
KeyType::secp256k1,
|
||||||
|
generateSecretKey(
|
||||||
|
KeyType::secp256k1, generateSeed("masterpassphrase")));
|
||||||
|
|
||||||
|
auto const pk2 = parseBase58<PublicKey>(
|
||||||
|
TokenType::NodePublic,
|
||||||
|
"n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9");
|
||||||
|
CHECK(pk2);
|
||||||
|
|
||||||
|
CHECK(pk1 == *pk2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try converting short, long and malformed data for secp256k1 keys
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, ""));
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, " "));
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, "!ty89234gh45"));
|
||||||
|
|
||||||
|
auto good = toBase58(
|
||||||
|
TokenType::NodePublic, derivePublicKey(KeyType::secp256k1, randomSecretKey()));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = good;
|
||||||
|
std::hash<std::string> r;
|
||||||
|
while (!s.empty())
|
||||||
|
{
|
||||||
|
s.erase(r(s) % s.size(), 1);
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t i = 1; i != 16; i++)
|
||||||
|
{
|
||||||
|
auto s = good;
|
||||||
|
s.resize(s.size() + i, s[i % s.size()]);
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto c : std::string("0IOl"))
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i != good.size(); ++i)
|
||||||
|
{
|
||||||
|
auto s = good;
|
||||||
|
s[i % s.size()] = c;
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = good;
|
||||||
|
for (auto c : std::string("apsrJqtv7"))
|
||||||
|
{
|
||||||
|
s[0] = c;
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PublicKey> keys;
|
||||||
|
keys.reserve(32);
|
||||||
|
for (std::size_t i = 0; i != keys.capacity(); ++i)
|
||||||
|
keys.emplace_back(derivePublicKey(KeyType::secp256k1, randomSecretKey()));
|
||||||
|
CHECK(keys.size() == 32);
|
||||||
|
for (std::size_t i = 0; i != keys.size(); ++i)
|
||||||
|
{
|
||||||
|
auto const si = toBase58(TokenType::NodePublic, keys[i]);
|
||||||
|
CHECK(!si.empty());
|
||||||
|
auto const ski = parseBase58<PublicKey>(TokenType::NodePublic, si);
|
||||||
|
CHECK(ski);
|
||||||
|
CHECK(keys[i] == *ski);
|
||||||
|
for (std::size_t j = i; j != keys.size(); ++j)
|
||||||
|
{
|
||||||
|
CHECK((keys[i] == keys[j]) == (i == j));
|
||||||
|
auto const sj = toBase58(TokenType::NodePublic, keys[j]);
|
||||||
|
CHECK((si == sj) == (i == j));
|
||||||
|
auto const skj = parseBase58<PublicKey>(TokenType::NodePublic, sj);
|
||||||
|
CHECK(skj);
|
||||||
|
CHECK(keys[j] == *skj);
|
||||||
|
CHECK((*ski == *skj) == (i == j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO("Base58: ed25519");
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const pk1 = derivePublicKey(
|
||||||
|
KeyType::ed25519,
|
||||||
|
generateSecretKey(
|
||||||
|
KeyType::ed25519, generateSeed("masterpassphrase")));
|
||||||
|
|
||||||
|
auto const pk2 = parseBase58<PublicKey>(
|
||||||
|
TokenType::NodePublic,
|
||||||
|
"nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf");
|
||||||
|
CHECK(pk2);
|
||||||
|
|
||||||
|
CHECK(pk1 == *pk2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeat Base58 conversion tests for ed25519 keys
|
||||||
|
good = toBase58(
|
||||||
|
TokenType::NodePublic, derivePublicKey(KeyType::ed25519, randomSecretKey()));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = good;
|
||||||
|
std::hash<std::string> r;
|
||||||
|
while (!s.empty())
|
||||||
|
{
|
||||||
|
s.erase(r(s) % s.size(), 1);
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t i = 1; i != 16; i++)
|
||||||
|
{
|
||||||
|
auto s = good;
|
||||||
|
s.resize(s.size() + i, s[i % s.size()]);
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto c : std::string("0IOl"))
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i != good.size(); ++i)
|
||||||
|
{
|
||||||
|
auto s = good;
|
||||||
|
s[i % s.size()] = c;
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = good;
|
||||||
|
for (auto c : std::string("apsrJqtv7"))
|
||||||
|
{
|
||||||
|
s[0] = c;
|
||||||
|
CHECK(!parseBase58<PublicKey>(TokenType::NodePublic, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.clear();
|
||||||
|
for (std::size_t i = 0; i != 32; ++i)
|
||||||
|
keys.emplace_back(derivePublicKey(KeyType::ed25519, randomSecretKey()));
|
||||||
|
CHECK(keys.size() == 32);
|
||||||
|
for (std::size_t i = 0; i != keys.size(); ++i)
|
||||||
|
{
|
||||||
|
auto const si = toBase58(TokenType::NodePublic, keys[i]);
|
||||||
|
CHECK(!si.empty());
|
||||||
|
auto const ski = parseBase58<PublicKey>(TokenType::NodePublic, si);
|
||||||
|
CHECK(ski);
|
||||||
|
CHECK(keys[i] == *ski);
|
||||||
|
for (std::size_t j = i; j != keys.size(); ++j)
|
||||||
|
{
|
||||||
|
CHECK((keys[i] == keys[j]) == (i == j));
|
||||||
|
auto const sj = toBase58(TokenType::NodePublic, keys[j]);
|
||||||
|
CHECK((si == sj) == (i == j));
|
||||||
|
auto const skj = parseBase58<PublicKey>(TokenType::NodePublic, sj);
|
||||||
|
CHECK(skj);
|
||||||
|
CHECK(keys[j] == *skj);
|
||||||
|
CHECK((*ski == *skj) == (i == j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Canonical")
|
||||||
|
{
|
||||||
|
INFO("Canonical");
|
||||||
|
|
||||||
|
// Fully canonical
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::fullyCanonical,
|
||||||
|
"3045"
|
||||||
|
"022100FF478110D1D4294471EC76E0157540C2181F47DEBD25D7F9E7DDCCCD47EE"
|
||||||
|
"E905"
|
||||||
|
"0220078F07CDAE6C240855D084AD91D1479609533C147C93B0AEF19BC9724D003F"
|
||||||
|
"28"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::fullyCanonical,
|
||||||
|
"3045"
|
||||||
|
"0221009218248292F1762D8A51BE80F8A7F2CD288D810CE781D5955700DA1684DF"
|
||||||
|
"1D2D"
|
||||||
|
"022041A1EE1746BFD72C9760CC93A7AAA8047D52C8833A03A20EAAE92EA19717B4"
|
||||||
|
"54"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::fullyCanonical,
|
||||||
|
"3044"
|
||||||
|
"02206A9E43775F73B6D1EC420E4DDD222A80D4C6DF5D1BEECC431A91B63C928B75"
|
||||||
|
"81"
|
||||||
|
"022023E9CC2D61DDA6F73EAA6BCB12688BEB0F434769276B3127E4044ED895C9D9"
|
||||||
|
"6B"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::fullyCanonical,
|
||||||
|
"3044"
|
||||||
|
"022056E720007221F3CD4EFBB6352741D8E5A0968D48D8D032C2FBC4F6304AD1D0"
|
||||||
|
"4E"
|
||||||
|
"02201F39EB392C20D7801C3E8D81D487E742FA84A1665E923225BD6323847C7187"
|
||||||
|
"9F"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::fullyCanonical,
|
||||||
|
"3045"
|
||||||
|
"022100FDFD5AD05518CEA0017A2DCB5C4DF61E7C73B6D3A38E7AE93210A1564E8C"
|
||||||
|
"2F12"
|
||||||
|
"0220214FF061CCC123C81D0BB9D0EDEA04CD40D96BF1425D311DA62A7096BB18EA"
|
||||||
|
"18"));
|
||||||
|
|
||||||
|
// Canonical but not fully canonical
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::canonical,
|
||||||
|
"3046"
|
||||||
|
"022100F477B3FA6F31C7CB3A0D1AD94A231FDD24B8D78862EE334CEA7CD08F6CBC"
|
||||||
|
"0A1B"
|
||||||
|
"022100928E6BCF1ED2684679730C5414AEC48FD62282B090041C41453C1D064AF5"
|
||||||
|
"97A1"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::canonical,
|
||||||
|
"3045"
|
||||||
|
"022063E7C7CA93CB2400E413A342C027D00665F8BAB9C22EF0A7B8AE3AAF092230"
|
||||||
|
"B6"
|
||||||
|
"0221008F2E8BB7D09521ABBC277717B14B93170AE6465C5A1B36561099319C4BEB"
|
||||||
|
"254C"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::canonical,
|
||||||
|
"3046"
|
||||||
|
"02210099DCA1188663DDEA506A06A7B20C2B7D8C26AFF41DECE69D6C5F7C967D32"
|
||||||
|
"625F"
|
||||||
|
"022100897658A6B1F9EEE5D140D7A332DA0BD73BB98974EA53F6201B01C1B594F2"
|
||||||
|
"86EA"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::canonical,
|
||||||
|
"3045"
|
||||||
|
"02200855DE366E4E323AA2CE2A25674401A7D11F72EC432770D07F7B57DF7387AE"
|
||||||
|
"C0"
|
||||||
|
"022100DA4C6ADDEA14888858DE2AC5B91ED9050D6972BB388DEF582628CEE32869"
|
||||||
|
"AE35"));
|
||||||
|
|
||||||
|
// valid
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::fullyCanonical,
|
||||||
|
"3006"
|
||||||
|
"020101"
|
||||||
|
"020102"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::fullyCanonical,
|
||||||
|
"3044"
|
||||||
|
"02203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df"
|
||||||
|
"0c"
|
||||||
|
"022030b61dd36543125d56b9f9f3a1f53189e5af33cdda8d77a5209aec03978fa0"
|
||||||
|
"01"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::canonical,
|
||||||
|
"3045"
|
||||||
|
"0220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f9"
|
||||||
|
"0a"
|
||||||
|
"0221008fffd599910eefe00bc803c688eca1d2ba7f6b180620eaa03488e6585db6"
|
||||||
|
"ba01"));
|
||||||
|
CHECK(check(
|
||||||
|
ECDSACanonicality::canonical,
|
||||||
|
"3046"
|
||||||
|
"022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40"
|
||||||
|
"f90a"
|
||||||
|
"0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585d"
|
||||||
|
"b6ba"));
|
||||||
|
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3005"
|
||||||
|
"0201FF"
|
||||||
|
"0200"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3006"
|
||||||
|
"020101"
|
||||||
|
"020202"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3006"
|
||||||
|
"020701"
|
||||||
|
"020102"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3006"
|
||||||
|
"020401"
|
||||||
|
"020102"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3006"
|
||||||
|
"020501"
|
||||||
|
"020102"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3006"
|
||||||
|
"020201"
|
||||||
|
"020102"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3006"
|
||||||
|
"020301"
|
||||||
|
"020202"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3006"
|
||||||
|
"020401"
|
||||||
|
"020202"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3047"
|
||||||
|
"0221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba"
|
||||||
|
"6105"
|
||||||
|
"022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e56"
|
||||||
|
"6695ed"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3144"
|
||||||
|
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
||||||
|
"05"
|
||||||
|
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
||||||
|
"ed"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3045"
|
||||||
|
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
||||||
|
"05"
|
||||||
|
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
||||||
|
"ed"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"301F"
|
||||||
|
"01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3045"
|
||||||
|
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
||||||
|
"05"
|
||||||
|
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
||||||
|
"ed00"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3044"
|
||||||
|
"01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
||||||
|
"05"
|
||||||
|
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
||||||
|
"ed"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3024"
|
||||||
|
"0200"
|
||||||
|
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
||||||
|
"ed"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3044"
|
||||||
|
"02208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
||||||
|
"05"
|
||||||
|
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
||||||
|
"ed"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3045"
|
||||||
|
"0221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba"
|
||||||
|
"6105"
|
||||||
|
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
||||||
|
"ed"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3044"
|
||||||
|
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
||||||
|
"05012"
|
||||||
|
"02d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695e"
|
||||||
|
"d"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3024"
|
||||||
|
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
||||||
|
"05"
|
||||||
|
"0200"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3044"
|
||||||
|
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
||||||
|
"05"
|
||||||
|
"0220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695"
|
||||||
|
"ed"));
|
||||||
|
CHECK(check(
|
||||||
|
std::nullopt,
|
||||||
|
"3045"
|
||||||
|
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61"
|
||||||
|
"05"
|
||||||
|
"0221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e5666"
|
||||||
|
"95ed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Miscellaneous operations")
|
||||||
|
{
|
||||||
|
INFO("Miscellaneous operations");
|
||||||
|
|
||||||
|
auto const pk1 = derivePublicKey(
|
||||||
|
KeyType::secp256k1,
|
||||||
|
generateSecretKey(
|
||||||
|
KeyType::secp256k1, generateSeed("masterpassphrase")));
|
||||||
|
|
||||||
|
PublicKey pk2(pk1);
|
||||||
|
CHECK(pk1 == pk2);
|
||||||
|
CHECK(pk2 == pk1);
|
||||||
|
|
||||||
|
PublicKey pk3 = derivePublicKey(
|
||||||
|
KeyType::secp256k1,
|
||||||
|
generateSecretKey(
|
||||||
|
KeyType::secp256k1, generateSeed("arbitraryPassPhrase")));
|
||||||
|
pk3 = pk2;
|
||||||
|
CHECK(pk3 == pk2);
|
||||||
|
CHECK(pk1 == pk3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUITE_END();
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
2
src/tests/libxrpl/protocol/main.cpp
Normal file
2
src/tests/libxrpl/protocol/main.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||||
|
#include <doctest/doctest.h>
|
||||||
Reference in New Issue
Block a user