mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 19:25:51 +00:00
Compare commits
2 Commits
dangell7/c
...
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)
|
||||
xrpl_add_test(crypto)
|
||||
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/beast/unit_test.h>
|
||||
#include <xrpl/json/json_reader.h> // Json::Reader
|
||||
#include <xrpl/protocol/ErrorCodes.h> // RPC::containsError
|
||||
#include <xrpl/protocol/STParsedJSON.h> // STParsedJSONObject
|
||||
#include <xrpl/json/json_reader.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
|
||||
namespace ripple {
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace ripple;
|
||||
|
||||
namespace InnerObjectFormatsUnitTestDetail {
|
||||
|
||||
@@ -36,7 +35,6 @@ struct TestJSONTxt
|
||||
};
|
||||
|
||||
static TestJSONTxt const testArray[] = {
|
||||
|
||||
// Valid SignerEntry
|
||||
{R"({
|
||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||
@@ -61,7 +59,6 @@ static TestJSONTxt const testArray[] = {
|
||||
"TransactionType" : "SignerListSet"
|
||||
})",
|
||||
false},
|
||||
|
||||
// SignerEntry missing Account
|
||||
{R"({
|
||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||
@@ -85,7 +82,6 @@ static TestJSONTxt const testArray[] = {
|
||||
"TransactionType" : "SignerListSet"
|
||||
})",
|
||||
true},
|
||||
|
||||
// SignerEntry missing SignerWeight
|
||||
{R"({
|
||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||
@@ -109,7 +105,6 @@ static TestJSONTxt const testArray[] = {
|
||||
"TransactionType" : "SignerListSet"
|
||||
})",
|
||||
true},
|
||||
|
||||
// SignerEntry with unexpected Amount
|
||||
{R"({
|
||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||
@@ -135,7 +130,6 @@ static TestJSONTxt const testArray[] = {
|
||||
"TransactionType" : "SignerListSet"
|
||||
})",
|
||||
true},
|
||||
|
||||
// SignerEntry with no Account and unexpected Amount
|
||||
{R"({
|
||||
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||
@@ -160,47 +154,36 @@ static TestJSONTxt const testArray[] = {
|
||||
"TransactionType" : "SignerListSet"
|
||||
})",
|
||||
true},
|
||||
|
||||
};
|
||||
|
||||
} // namespace InnerObjectFormatsUnitTestDetail
|
||||
|
||||
class InnerObjectFormatsParsedJSON_test : public beast::unit_test::suite
|
||||
TEST_SUITE_BEGIN("InnerObjectFormatsParsedJSON");
|
||||
|
||||
TEST_CASE("InnerObjectFormatsParsedJSON")
|
||||
{
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
using namespace InnerObjectFormatsUnitTestDetail;
|
||||
|
||||
for (auto const& test : testArray)
|
||||
{
|
||||
using namespace InnerObjectFormatsUnitTestDetail;
|
||||
|
||||
// Instantiate a jtx::Env so debugLog writes are exercised.
|
||||
test::jtx::Env env(*this);
|
||||
|
||||
for (auto const& test : testArray)
|
||||
Json::Value req;
|
||||
Json::Reader().parse(test.txt, req);
|
||||
if (RPC::contains_error(req))
|
||||
{
|
||||
Json::Value req;
|
||||
Json::Reader().parse(test.txt, req);
|
||||
if (RPC::contains_error(req))
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"Internal InnerObjectFormatsParsedJSON error. Bad JSON.");
|
||||
}
|
||||
STParsedJSONObject parsed("request", req);
|
||||
bool const noObj = !parsed.object.has_value();
|
||||
if (noObj == test.expectFail)
|
||||
{
|
||||
pass();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string errStr("Unexpected STParsedJSON result on:\n");
|
||||
errStr += test.txt;
|
||||
fail(errStr);
|
||||
}
|
||||
Throw<std::runtime_error>(
|
||||
"Internal InnerObjectFormatsParsedJSON error. Bad JSON.");
|
||||
}
|
||||
STParsedJSONObject parsed("request", req);
|
||||
bool const noObj = !parsed.object.has_value();
|
||||
if (noObj == test.expectFail)
|
||||
CHECK(true);
|
||||
else
|
||||
{
|
||||
std::string errStr("Unexpected STParsedJSON result on:\n");
|
||||
errStr += test.txt;
|
||||
FAIL(errStr);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(InnerObjectFormatsParsedJSON, ripple_app, ripple);
|
||||
|
||||
} // namespace ripple
|
||||
TEST_SUITE_END();
|
||||
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