diff --git a/src/test/protocol/ApiVersion_test.cpp b/src/test/protocol/ApiVersion_test.cpp deleted file mode 100644 index 2dc4f4d6bb..0000000000 --- a/src/test/protocol/ApiVersion_test.cpp +++ /dev/null @@ -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 -#include -#include - -#include -#include -#include -#include -#include -#include - -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 diff --git a/src/test/protocol/BuildInfo_test.cpp b/src/test/protocol/BuildInfo_test.cpp deleted file mode 100644 index 2c40681603..0000000000 --- a/src/test/protocol/BuildInfo_test.cpp +++ /dev/null @@ -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 -#include - -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 diff --git a/src/test/protocol/Hooks_test.cpp b/src/test/protocol/Hooks_test.cpp deleted file mode 100644 index 0637b52efa..0000000000 --- a/src/test/protocol/Hooks_test.cpp +++ /dev/null @@ -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 - -#include - -#include -#include - -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> 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 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( - "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 diff --git a/src/test/protocol/Issue_test.cpp b/src/test/protocol/Issue_test.cpp deleted file mode 100644 index 35f3a3bd8c..0000000000 --- a/src/test/protocol/Issue_test.cpp +++ /dev/null @@ -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 -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#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 - 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 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 - 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 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 - 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 - 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 - 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 - 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 >"); - testIssueDomainSet>>(); - - testcase("std::set >"); - testIssueDomainSet>>(); - - testcase("hash_set >"); - testIssueDomainSet>>(); - - testcase("hash_set >"); - testIssueDomainSet>>(); - } - - void - testIssueDomainMaps() - { - testcase("std::map , int>"); - testIssueDomainMap, int>>(); - - testcase("std::map , int>"); - testIssueDomainMap, int>>(); - -#if RIPPLE_ASSETS_ENABLE_STD_HASH - testcase("hash_map , int>"); - testIssueDomainMap, int>>(); - - testcase("hash_map , int>"); - testIssueDomainMap, int>>(); - - testcase("hardened_hash_map , int>"); - testIssueDomainMap, int>>(); - - testcase("hardened_hash_map , int>"); - testIssueDomainMap, int>>(); -#endif - } - - void - testIssueSets() - { - testcase("std::set "); - testIssueSet>(); - - testcase("std::set "); - testIssueSet>(); - -#if RIPPLE_ASSETS_ENABLE_STD_HASH - testcase("std::unordered_set "); - testIssueSet>(); - - testcase("std::unordered_set "); - testIssueSet>(); -#endif - - testcase("hash_set "); - testIssueSet>(); - - testcase("hash_set "); - testIssueSet>(); - } - - void - testIssueMaps() - { - testcase("std::map "); - testIssueMap>(); - - testcase("std::map "); - testIssueMap>(); - -#if RIPPLE_ASSETS_ENABLE_STD_HASH - testcase("std::unordered_map "); - testIssueMap>(); - - testcase("std::unordered_map "); - testIssueMap>(); - - testcase("hash_map "); - testIssueMap>(); - - testcase("hash_map "); - testIssueMap>(); - -#endif - } - - //-------------------------------------------------------------------------- - - // Comparison, hash tests for Book - template - 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 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 - 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 - 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 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 "); - testBookSet>(); - - testcase("std::set "); - testBookSet>(); - -#if RIPPLE_ASSETS_ENABLE_STD_HASH - testcase("std::unordered_set "); - testBookSet>(); - - testcase("std::unordered_set "); - testBookSet>(); -#endif - - testcase("hash_set "); - testBookSet>(); - - testcase("hash_set "); - testBookSet>(); - } - - void - testBookMaps() - { - testcase("std::map "); - testBookMap>(); - - testcase("std::map "); - testBookMap>(); - -#if RIPPLE_ASSETS_ENABLE_STD_HASH - testcase("std::unordered_map "); - testBookMap>(); - - testcase("std::unordered_map "); - testBookMap>(); - - testcase("hash_map "); - testBookMap>(); - - testcase("hash_map "); - testBookMap>(); -#endif - } - - //-------------------------------------------------------------------------- - - void - run() override - { - testcase("Currency"); - testUnsigned(); - - testcase("AccountID"); - testUnsigned(); - - // --- - - testcase("Issue"); - testIssue(); - - testcase("Issue"); - testIssue(); - - testIssueSets(); - testIssueMaps(); - - // --- - - testcase("Book"); - testBook(); - - testcase("Book"); - testBook(); - - testBookSets(); - testBookMaps(); - - // --- - testIssueDomainSets(); - testIssueDomainMaps(); - } -}; - -BEAST_DEFINE_TESTSUITE(Issue, protocol, ripple); - -} // namespace ripple diff --git a/src/test/protocol/Memo_test.cpp b/src/test/protocol/Memo_test.cpp deleted file mode 100644 index a7fa846a4d..0000000000 --- a/src/test/protocol/Memo_test.cpp +++ /dev/null @@ -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 - -#include - -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 -#include - -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -namespace { - -// This needs to be in a namespace because of deduction guide -template -struct Overload : Ts... -{ - using Ts::operator()...; -}; -template -Overload(Ts...) -> Overload; - -} // namespace - -struct MultiApiJson_test : beast::unit_test::suite -{ - static auto - makeJson(char const* key, int val) - { - Json::Value obj1(Json::objectValue); - obj1[key] = val; - return obj1; - } - - void - run() override - { - using ripple::detail::MultiApiJson; - - 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{}; - - MultiApiJson<1, 3> subject{}; - static_assert(sizeof(subject) == sizeof(subject.val)); - static_assert(subject.size == subject.val.size()); - static_assert( - std::is_same_v>); - - BEAST_EXPECT(subject.val.size() == 3); - BEAST_EXPECT( - (subject.val == - std::array{jsonNull, jsonNull, jsonNull})); - - subject.val[0] = obj1; - subject.val[1] = obj2; - - { - testcase("forApiVersions, forAllApiVersions"); - - // 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); - - MultiApiJson<1, 3> 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; - BEAST_EXPECT(index == s1.index(i)); - BEAST_EXPECT(s1.valid(i)); - s1.val[index] = makeJson("value", primes[i]); - productAllVersions *= primes[i]; - } - BEAST_EXPECT(!s1.valid(0)); - BEAST_EXPECT(!s1.valid(RPC::apiMaximumValidVersion + 1)); - BEAST_EXPECT( - !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(), - [this]( - Json::Value const& json, - unsigned int version, - int* result) { - BEAST_EXPECT( - version >= RPC::apiMinimumSupportedVersion && - version <= RPC::apiMinimumSupportedVersion + 1); - if (BEAST_EXPECT(json.isMember("value"))) - { - *result *= json["value"].asInt(); - } - }, - &result); - BEAST_EXPECT( - result == - primes[RPC::apiMinimumSupportedVersion] * - primes[RPC::apiMinimumSupportedVersion + 1]); - - // Check all the values with mutable data - forAllApiVersions( - s1.visit(), [&s1, this](Json::Value& json, auto version) { - BEAST_EXPECT(s1.val[s1.index(version)] == json); - if (BEAST_EXPECT(json.isMember("value"))) - { - BEAST_EXPECT(json["value"].asInt() == primes[version]); - } - }); - - result = 1; - forAllApiVersions( - std::as_const(s1).visit(), - [this]( - Json::Value const& json, - unsigned int version, - int* result) { - BEAST_EXPECT( - version >= RPC::apiMinimumSupportedVersion && - version <= RPC::apiMaximumValidVersion); - if (BEAST_EXPECT(json.isMember("value"))) - { - *result *= json["value"].asInt(); - } - }, - &result); - - BEAST_EXPECT(result == productAllVersions); - - // Several overloads we want to fail - static_assert([](auto&& v) { - return !requires { - forAllApiVersions( - std::forward(v).visit(), // - [](Json::Value&, auto) {}); // missing const - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return !requires { - forAllApiVersions( - std::forward(v).visit(), // - [](Json::Value&) {}); // missing const - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return !requires { - forAllApiVersions( - std::forward(v).visit(), // - []() {}); // missing parameters - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return !requires { - forAllApiVersions( - std::forward(v).visit(), // - [](auto) {}, - 1); // missing parameters - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return !requires { - forAllApiVersions( - std::forward(v).visit(), // - [](auto, auto) {}, - 1); // missing parameters - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return !requires { - forAllApiVersions( - std::forward(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(v).visit(), // - [](auto) {}); - }; - }(s1)); - static_assert([](auto&& v) { - return requires { - forAllApiVersions( - std::forward(v).visit(), // - [](Json::Value const&) {}); - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return requires { - forAllApiVersions( - std::forward(v).visit(), // - [](auto...) {}); - }; - }(s1)); - static_assert([](auto&& v) { - return requires { - forAllApiVersions( - std::forward(v).visit(), // - [](Json::Value const&, auto...) {}); - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return requires { - forAllApiVersions( - std::forward(v).visit(), // - [](Json::Value&, auto, auto, auto...) {}, - 0, - ""); - }; - }(s1)); - static_assert([](auto&& v) { - return requires { - forAllApiVersions( - std::forward(v).visit(), // - []( - Json::Value const&, - std::integral_constant, - int, - char const*) {}, - 0, - ""); - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return requires { - forAllApiVersions( - std::forward(v).visit(), // - [](auto...) {}); - }; - }(std::move(s1))); - static_assert([](auto&& v) { - return requires { - forAllApiVersions( - std::forward(v).visit(), // - [](auto...) {}); - }; - }(std::move(std::as_const(s1)))); - } - - { - testcase("default copy construction / assignment"); - - MultiApiJson<1, 3> x{subject}; - - BEAST_EXPECT(x.val.size() == subject.val.size()); - BEAST_EXPECT(x.val[0] == subject.val[0]); - BEAST_EXPECT(x.val[1] == subject.val[1]); - BEAST_EXPECT(x.val[2] == subject.val[2]); - BEAST_EXPECT(x.val == subject.val); - BEAST_EXPECT(&x.val[0] != &subject.val[0]); - BEAST_EXPECT(&x.val[1] != &subject.val[1]); - BEAST_EXPECT(&x.val[2] != &subject.val[2]); - - MultiApiJson<1, 3> y; - BEAST_EXPECT((y.val == std::array{})); - y = subject; - BEAST_EXPECT(y.val == subject.val); - BEAST_EXPECT(&y.val[0] != &subject.val[0]); - BEAST_EXPECT(&y.val[1] != &subject.val[1]); - BEAST_EXPECT(&y.val[2] != &subject.val[2]); - - y = std::move(x); - BEAST_EXPECT(y.val == subject.val); - BEAST_EXPECT(&y.val[0] != &subject.val[0]); - BEAST_EXPECT(&y.val[1] != &subject.val[1]); - BEAST_EXPECT(&y.val[2] != &subject.val[2]); - } - - { - testcase("set"); - - auto x = MultiApiJson<1, 2>{Json::objectValue}; - x.set("name1", 42); - BEAST_EXPECT(x.val[0].isMember("name1")); - BEAST_EXPECT(x.val[1].isMember("name1")); - BEAST_EXPECT(x.val[0]["name1"].isInt()); - BEAST_EXPECT(x.val[1]["name1"].isInt()); - BEAST_EXPECT(x.val[0]["name1"].asInt() == 42); - BEAST_EXPECT(x.val[1]["name1"].asInt() == 42); - - x.set("name2", "bar"); - BEAST_EXPECT(x.val[0].isMember("name2")); - BEAST_EXPECT(x.val[1].isMember("name2")); - BEAST_EXPECT(x.val[0]["name2"].isString()); - BEAST_EXPECT(x.val[1]["name2"].isString()); - BEAST_EXPECT(x.val[0]["name2"].asString() == "bar"); - BEAST_EXPECT(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)); - } - - { - testcase("isMember"); - - // Well defined behaviour even if we have different types of members - BEAST_EXPECT(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); - BEAST_EXPECT(s1.isMember("One") == decltype(s1)::all); - BEAST_EXPECT(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); - BEAST_EXPECT(s2.isMember("One") == decltype(s2)::some); - BEAST_EXPECT(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); - BEAST_EXPECT(s3.isMember("One") == decltype(s3)::some); - BEAST_EXPECT(s3.isMember("Two") == decltype(s3)::none); - } - } - - { - testcase("visitor"); - - MultiApiJson<1, 3> s1{}; - s1.val[0] = makeJson("value", 2); - s1.val[1] = makeJson("value", 3); - s1.val[2] = makeJson("value", 5); - - BEAST_EXPECT(not s1.valid(0)); - BEAST_EXPECT(s1.index(0) == 0); - - BEAST_EXPECT(s1.valid(1)); - BEAST_EXPECT(s1.index(1) == 0); - - BEAST_EXPECT(not s1.valid(4)); - - // Test different overloads - static_assert([](auto&& v) { - return requires { - v.visitor( - v, - std::integral_constant{}, - [](Json::Value&, std::integral_constant) { - }); - }; - }(s1)); - BEAST_EXPECT( - s1.visitor( - s1, - std::integral_constant{}, - Overload{ - [](Json::Value& v, - std::integral_constant) { - 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{}, - [](Json::Value&) {}); - }; - }(s1)); - BEAST_EXPECT( - s1.visitor( - s1, - std::integral_constant{}, - 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{}, - [](Json::Value const&, - std::integral_constant) {}); - }; - }(std::as_const(s1))); - BEAST_EXPECT( - s1.visitor( - std::as_const(s1), - std::integral_constant{}, - Overload{ - [](Json::Value const& v, - std::integral_constant) { - 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{}, - [](Json::Value const&) {}); - }; - }(std::as_const(s1))); - BEAST_EXPECT( - s1.visitor( - std::as_const(s1), - std::integral_constant{}, - Overload{ - [](Json::Value const& v) { return v["value"].asInt(); }, - [](Json::Value&) { return 0; }, - [](auto...) { return 0; }}) == 3); - - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](Json::Value&, unsigned) {}); - }; - }(s1)); - BEAST_EXPECT( - s1.visitor( - s1, // - 3u, - Overload{ - [](Json::Value& v, unsigned) { - return v["value"].asInt(); - }, - [](Json::Value const&, unsigned) { return 0; }, - [](auto, auto) { return 0; }}) == 5); - - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](Json::Value&) {}); }; - }(s1)); - BEAST_EXPECT( - s1.visitor( - s1, // - 3, - Overload{ - [](Json::Value& v) { return v["value"].asInt(); }, - [](Json::Value const&) { return 0; }, - [](auto...) { return 0; }}) == 5); - - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](Json::Value const&, unsigned) {}); - }; - }(std::as_const(s1))); - BEAST_EXPECT( - s1.visitor( - std::as_const(s1), // - 2u, - Overload{ - [](Json::Value const& v, unsigned) { - return v["value"].asInt(); - }, - [](Json::Value const&, auto) { return 0; }, - [](auto, auto) { return 0; }}) == 3); - - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](Json::Value const&) {}); }; - }(std::as_const(s1))); - BEAST_EXPECT( - s1.visitor( - std::as_const(s1), // - 2, - Overload{ - [](Json::Value const& v) { return v["value"].asInt(); }, - [](Json::Value&) { return 0; }, - [](auto...) { return 0; }}) == 3); - - // Test type conversions - BEAST_EXPECT( - s1.visitor( - s1, - std::integral_constant{}, // to unsigned - [](Json::Value& v, unsigned) { - return v["value"].asInt(); - }) == 2); - BEAST_EXPECT( - s1.visitor( - std::as_const(s1), - std::integral_constant{}, // to unsigned - [](Json::Value const& v, unsigned) { - return v["value"].asInt(); - }) == 3); - BEAST_EXPECT( - s1.visitor( - s1, // to const - std::integral_constant{}, - [](Json::Value const& v, auto) { - return v["value"].asInt(); - }) == 5); - BEAST_EXPECT( - s1.visitor( - s1, // to const - std::integral_constant{}, - [](Json::Value const& v) { return v["value"].asInt(); }) == - 5); - BEAST_EXPECT( - s1.visitor( - s1, - 3, // to long - [](Json::Value& v, long) { return v["value"].asInt(); }) == - 5); - BEAST_EXPECT( - s1.visitor( - std::as_const(s1), - 1, // to long - [](Json::Value const& v, long) { - return v["value"].asInt(); - }) == 2); - BEAST_EXPECT( - s1.visitor( - s1, // to const - 2, - [](Json::Value const& v, auto) { - return v["value"].asInt(); - }) == 3); - BEAST_EXPECT( - s1.visitor( - s1, // type deduction - 2, - [](auto& v, auto) { return v["value"].asInt(); }) == 3); - BEAST_EXPECT( - s1.visitor( - s1, // to const, type deduction - 2, - [](auto const& v, auto) { return v["value"].asInt(); }) == - 3); - BEAST_EXPECT( - s1.visitor( - s1, // type deduction - 2, - [](auto& v) { return v["value"].asInt(); }) == 3); - BEAST_EXPECT( - s1.visitor( - s1, // to const, type deduction - 2, - [](auto const& v) { return v["value"].asInt(); }) == 3); - - // Test passing of additional arguments - BEAST_EXPECT( - s1.visitor( - s1, - std::integral_constant{}, - [](Json::Value& v, auto ver, auto a1, auto a2) { - return ver * a1 * a2 * v["value"].asInt(); - }, - 5, - 7) == 2 * 5 * 7 * 3); - BEAST_EXPECT( - s1.visitor( - s1, - std::integral_constant{}, - [](Json::Value& v, auto ver, auto... args) { - return ver * (1 * ... * args) * v["value"].asInt(); - }, - 5, - 7) == 2 * 5 * 7 * 3); - - // Several overloads we want to fail - static_assert([](auto&& v) { - return !requires { - v.visitor( - v, - 1, // - [](Json::Value&, auto) {}); // missing const - }; - }(std::as_const(s1))); - - static_assert([](auto&& v) { - return !requires { - v.visitor( - std::move(v), // cannot bind rvalue - 1, - [](Json::Value&, auto) {}); - }; - }(s1)); - - static_assert([](auto&& v) { - return !requires { - v.visitor( - v, - 1, // - []() {}); // missing parameter - }; - }(s1)); - - static_assert([](auto&& v) { - return !requires { - v.visitor( - v, - 1, // - [](Json::Value&, int, int) {}); // too many parameters - }; - }(s1)); - - // Want these to be unambiguous - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](auto) {}); }; - }(s1)); - - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](Json::Value&) {}); }; - }(s1)); - - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](Json::Value&, auto...) {}); - }; - }(s1)); - - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](Json::Value const&) {}); }; - }(s1)); - - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](Json::Value const&, auto...) {}); - }; - }(s1)); - - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](auto...) {}); }; - }(s1)); - - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](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)); - } - - { - testcase("visit"); - - MultiApiJson<1, 3> 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{}, - [](Json::Value&, std::integral_constant) { - }); - }; - }(s1)); - BEAST_EXPECT( - s1.visit( - std::integral_constant{}, - Overload{ - [](Json::Value& v, - std::integral_constant) { - 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{}, - [](Json::Value&, std::integral_constant) { - }); - }; - }(s1)); - BEAST_EXPECT( - s1.visit()( - std::integral_constant{}, - Overload{ - [](Json::Value& v, - std::integral_constant) { - 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{}, - [](Json::Value&) {}); - }; - }(s1)); - BEAST_EXPECT( - s1.visit( - std::integral_constant{}, - 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{}, - [](Json::Value&) {}); - }; - }(s1)); - BEAST_EXPECT( - s1.visit()( - std::integral_constant{}, - 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{}, - [](Json::Value const&, - std::integral_constant) {}); - }; - }(std::as_const(s1))); - BEAST_EXPECT( - std::as_const(s1).visit( - std::integral_constant{}, - Overload{ - [](Json::Value const& v, - std::integral_constant) { - 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{}, - [](Json::Value const&, - std::integral_constant) {}); - }; - }(std::as_const(s1))); - BEAST_EXPECT( - std::as_const(s1).visit()( - std::integral_constant{}, - Overload{ - [](Json::Value const& v, - std::integral_constant) { - 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{}, - [](Json::Value const&) {}); - }; - }(std::as_const(s1))); - BEAST_EXPECT( - std::as_const(s1).visit( - std::integral_constant{}, - 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{}, - [](Json::Value const&) {}); - }; - }(std::as_const(s1))); - BEAST_EXPECT( - std::as_const(s1).visit()( - std::integral_constant{}, - 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(1, [](Json::Value&, unsigned) {}); }; - }(s1)); - BEAST_EXPECT( - s1.visit( - 3u, - Overload{ - [](Json::Value& v, unsigned) { - return v["value"].asInt(); - }, - [](Json::Value const&, unsigned) { return 0; }, - [](Json::Value&, auto) { return 0; }, - [](auto, auto) { return 0; }}) == 5); - static_assert([](auto&& v) { - return requires { - v.visit()(1, [](Json::Value&, unsigned) {}); - }; - }(s1)); - BEAST_EXPECT( - s1.visit()( - 3u, - Overload{ - [](Json::Value& v, unsigned) { - return v["value"].asInt(); - }, - [](Json::Value const&, unsigned) { return 0; }, - [](Json::Value&, auto) { return 0; }, - [](auto, auto) { return 0; }}) == 5); - - static_assert([](auto&& v) { - return requires { v.visit(1, [](Json::Value&) {}); }; - }(s1)); - BEAST_EXPECT( - s1.visit( - 3, - Overload{ - [](Json::Value& v) { return v["value"].asInt(); }, - [](Json::Value const&) { return 0; }, - [](auto...) { return 0; }}) == 5); - static_assert([](auto&& v) { - return requires { v.visit()(1, [](Json::Value&) {}); }; - }(s1)); - BEAST_EXPECT( - s1.visit()( - 3, - Overload{ - [](Json::Value& v) { return v["value"].asInt(); }, - [](Json::Value const&) { return 0; }, - [](auto...) { return 0; }}) == 5); - - static_assert([](auto&& v) { - return requires { - v.visit(1, [](Json::Value const&, unsigned) {}); - }; - }(std::as_const(s1))); - BEAST_EXPECT( - std::as_const(s1).visit( - 2u, - Overload{ - [](Json::Value const& v, unsigned) { - return v["value"].asInt(); - }, - [](Json::Value const&, auto) { return 0; }, - [](Json::Value&, unsigned) { return 0; }, - [](auto, auto) { return 0; }}) == 3); - static_assert([](auto&& v) { - return requires { - v.visit()(1, [](Json::Value const&, unsigned) {}); - }; - }(std::as_const(s1))); - BEAST_EXPECT( - std::as_const(s1).visit()( - 2u, - Overload{ - [](Json::Value const& v, unsigned) { - return v["value"].asInt(); - }, - [](Json::Value const&, auto) { return 0; }, - [](Json::Value&, unsigned) { return 0; }, - [](auto, auto) { return 0; }}) == 3); - - static_assert([](auto&& v) { - return requires { v.visit(1, [](Json::Value const&) {}); }; - }(std::as_const(s1))); - BEAST_EXPECT( - std::as_const(s1).visit( - 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()(1, [](Json::Value const&) {}); }; - }(std::as_const(s1))); - BEAST_EXPECT( - std::as_const(s1).visit()( - 2, - Overload{ - [](Json::Value const& v) { return v["value"].asInt(); }, - [](Json::Value&) { return 0; }, - [](auto...) { return 0; }}) == 3); - - // Rvalue MultivarJson visitor only binds to regular reference - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit(1, [](Json::Value&&) {}); - }; - }(std::move(s1))); - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit( - 1, [](Json::Value const&&) {}); - }; - }(std::move(s1))); - static_assert([](auto&& v) { - return requires { - std::forward(v).visit(1, [](Json::Value&) {}); - }; - }(std::move(s1))); - static_assert([](auto&& v) { - return requires { - std::forward(v).visit( - 1, [](Json::Value const&) {}); - }; - }(std::move(s1))); - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()( - 1, [](Json::Value&&) {}); - }; - }(std::move(s1))); - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()( - 1, [](Json::Value const&&) {}); - }; - }(std::move(s1))); - static_assert([](auto&& v) { - return requires { - std::forward(v).visit()( - 1, [](Json::Value&) {}); - }; - }(std::move(s1))); - static_assert([](auto&& v) { - return requires { - std::forward(v).visit()( - 1, [](Json::Value const&) {}); - }; - }(std::move(s1))); - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit( - 1, [](Json::Value const&&) {}); - }; - }(std::move(std::as_const(s1)))); - static_assert([](auto&& v) { - return requires { - std::forward(v).visit( - 1, [](Json::Value const&) {}); - }; - }(std::move(std::as_const(s1)))); - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()( - 1, [](Json::Value const&&) {}); - }; - }(std::move(std::as_const(s1)))); - static_assert([](auto&& v) { - return requires { - std::forward(v).visit()( - 1, [](Json::Value const&) {}); - }; - }(std::move(std::as_const(s1)))); - - // Missing const - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit( - 1, [](Json::Value&, auto) {}); - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()( - 1, [](Json::Value&, auto) {}); - }; - }(std::as_const(s1))); - - // Missing parameter - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit(1, []() {}); - }; - }(s1)); - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()(1, []() {}); - }; - }(s1)); - - // Sanity checks - static_assert([](auto&& v) { - return requires { - std::forward(v).visit(1, [](auto...) {}); - }; - }(std::as_const(s1))); - static_assert([](auto&& v) { - return requires { - std::forward(v).visit()(1, [](auto...) {}); - }; - }(std::as_const(s1))); - } - } -}; - -BEAST_DEFINE_TESTSUITE(MultiApiJson, protocol, ripple); - -} // namespace test -} // namespace ripple diff --git a/src/test/protocol/PublicKey_test.cpp b/src/test/protocol/PublicKey_test.cpp deleted file mode 100644 index 0f5aef261a..0000000000 --- a/src/test/protocol/PublicKey_test.cpp +++ /dev/null @@ -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 -#include -#include - -#include - -namespace ripple { - -class PublicKey_test : public beast::unit_test::suite -{ -public: - using blob = std::vector; - - template - 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 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(TokenType::NodePublic, "")); - BEAST_EXPECT(!parseBase58(TokenType::NodePublic, " ")); - BEAST_EXPECT( - !parseBase58(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 r; - - while (!s.empty()) - { - s.erase(r(s) % s.size(), 1); - BEAST_EXPECT(!parseBase58(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(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(TokenType::NodePublic, s)); - } - } - - // Strings with incorrect prefix - { - auto s = good; - - for (auto c : std::string("apsrJqtv7")) - { - s[0] = c; - BEAST_EXPECT(!parseBase58(TokenType::NodePublic, s)); - } - } - - // Try some random secret keys - std::vector 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(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(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( - 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( - 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 diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index 68c6fa6cb3..e9bb1d7b2d 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -12,3 +12,7 @@ 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) + +# Protocol unit tests +xrpl_add_test(protocol) +target_link_libraries(xrpl.test.protocol PRIVATE xrpl.imports.test) diff --git a/src/tests/libxrpl/protocol/ApiVersion.cpp b/src/tests/libxrpl/protocol/ApiVersion.cpp new file mode 100644 index 0000000000..1c2bb3e203 --- /dev/null +++ b/src/tests/libxrpl/protocol/ApiVersion.cpp @@ -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 + +#include + +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(); diff --git a/src/tests/libxrpl/protocol/BuildInfo.cpp b/src/tests/libxrpl/protocol/BuildInfo.cpp new file mode 100644 index 0000000000..a078955e3b --- /dev/null +++ b/src/tests/libxrpl/protocol/BuildInfo.cpp @@ -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 + +#include + +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(); diff --git a/src/tests/libxrpl/protocol/Hooks.cpp b/src/tests/libxrpl/protocol/Hooks.cpp new file mode 100644 index 0000000000..f907dd403e --- /dev/null +++ b/src/tests/libxrpl/protocol/Hooks.cpp @@ -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 + +#include + +#include + +#include +#include + +using namespace ripple; + +TEST_SUITE_BEGIN("Hooks"); + +TEST_CASE("Test Hooks fields") +{ + using namespace test::jtx; + + std::vector> 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 v{1, 2, 3}; + dummy.setFieldVL(f, v); + CHECK(dummy.getFieldVL(f) == v); + CHECK(dummy.isFieldPresent(f)); + break; + } + + case STI_ACCOUNT: { + AccountID id = *parseBase58( + "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(); diff --git a/src/test/protocol/InnerObjectFormats_test.cpp b/src/tests/libxrpl/protocol/InnerObjectFormats.cpp similarity index 75% rename from src/test/protocol/InnerObjectFormats_test.cpp rename to src/tests/libxrpl/protocol/InnerObjectFormats.cpp index f4d9722392..889413ad90 100644 --- a/src/test/protocol/InnerObjectFormats_test.cpp +++ b/src/tests/libxrpl/protocol/InnerObjectFormats.cpp @@ -17,15 +17,14 @@ */ //============================================================================== -#include - #include -#include -#include // Json::Reader -#include // RPC::containsError -#include // STParsedJSONObject +#include +#include +#include -namespace ripple { +#include + +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( - "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( + "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(); diff --git a/src/tests/libxrpl/protocol/Issue.cpp b/src/tests/libxrpl/protocol/Issue.cpp new file mode 100644 index 0000000000..ed9d0a8875 --- /dev/null +++ b/src/tests/libxrpl/protocol/Issue.cpp @@ -0,0 +1,964 @@ +//------------------------------------------------------------------------------ +/* + 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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#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 + 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 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 + 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 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 + 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 (!CHECK(c.size() == 1)) + return; + c.insert(a2); + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Issue(c1, i2)) == 0)) + return; + if (!CHECK(c.erase(Issue(c1, i1)) == 1)) + return; + if (!CHECK(c.erase(Issue(c2, i2)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + + { + Set c; + + c.insert(a1); + if (!CHECK(c.size() == 1)) + return; + c.insert(a2); + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Issue(c1, i2)) == 0)) + return; + if (!CHECK(c.erase(Issue(c1, i1)) == 1)) + return; + if (!CHECK(c.erase(Issue(c2, i2)) == 1)) + return; + if (!CHECK(c.empty())) + return; + +#if STL_SET_HAS_EMPLACE + c.emplace(c1, i1); + if (!CHECK(c.size() == 1)) + return; + c.emplace(c2, i2); + if (!CHECK(c.size() == 2)) + return; +#endif + } + } + + template + 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 (!CHECK(c.size() == 1)) + return; + c.insert(std::make_pair(a2, 2)); + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Issue(c1, i2)) == 0)) + return; + if (!CHECK(c.erase(Issue(c1, i1)) == 1)) + return; + if (!CHECK(c.erase(Issue(c2, i2)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + + { + Map c; + + c.insert(std::make_pair(a1, 1)); + if (!CHECK(c.size() == 1)) + return; + c.insert(std::make_pair(a2, 2)); + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Issue(c1, i2)) == 0)) + return; + if (!CHECK(c.erase(Issue(c1, i1)) == 1)) + return; + if (!CHECK(c.erase(Issue(c2, i2)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + } + + template + 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 (!CHECK(c.size() == 1)) + return; + c.insert(std::make_pair(a2, domain1)); + if (!CHECK(c.size() == 2)) + return; + c.insert(std::make_pair(a2, domain2)); + if (!CHECK(c.size() == 3)) + return; + + if (!CHECK(c.erase(std::make_pair(Issue(c1, i2), domain1)) == 0)) + return; + if (!CHECK(c.erase(std::make_pair(a1, domain1)) == 1)) + return; + if (!CHECK(c.erase(std::make_pair(a2, domain1)) == 1)) + return; + if (!CHECK(c.erase(std::make_pair(a2, domain2)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + + template + 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 (!CHECK(c.size() == 1)) + return; + c.insert(std::make_pair(std::make_pair(a2, domain1), 2)); + if (!CHECK(c.size() == 2)) + return; + c.insert(std::make_pair(std::make_pair(a2, domain2), 2)); + if (!CHECK(c.size() == 3)) + return; + + if (!CHECK(c.erase(std::make_pair(Issue(c1, i2), domain1)) == 0)) + return; + if (!CHECK(c.erase(std::make_pair(a1, domain1)) == 1)) + return; + if (!CHECK(c.erase(std::make_pair(a2, domain1)) == 1)) + return; + if (!CHECK(c.erase(std::make_pair(a2, domain2)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + + + //-------------------------------------------------------------------------- + + // Comparison, hash tests for Book + template + 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 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 + 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 (!CHECK(c.size() == 1)) + return; + c.insert(b2); + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Book(a1, a1, std::nullopt)) == 0)) + return; + if (!CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + + { + Set c; + + c.insert(b1); + if (!CHECK(c.size() == 1)) + return; + c.insert(b2); + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Book(a1, a1, std::nullopt)) == 0)) + return; + if (!CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1)) + return; + if (!CHECK(c.empty())) + return; + +#if STL_SET_HAS_EMPLACE + c.emplace(a1, a2); + if (!CHECK(c.size() == 1)) + return; + c.emplace(a2, a1); + if (!CHECK(c.size() == 2)) + return; +#endif + } + + { + Set c; + + c.insert(b1_d1); + if (!CHECK(c.size() == 1)) + return; + c.insert(b2_d1); + if (!CHECK(c.size() == 2)) + return; + c.insert(b1_d2); + if (!CHECK(c.size() == 3)) + return; + c.insert(b2_d2); + if (!CHECK(c.size() == 4)) + return; + + // Try removing non-existent elements + if (!CHECK(c.erase(Book(a2, a2, domain1)) == 0)) + return; + + if (!CHECK(c.erase(Book(a1, a2, domain1)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, domain1)) == 1)) + return; + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Book(a1, a2, domain2)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, domain2)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + + { + Set c; + + c.insert(b1); + c.insert(b2); + c.insert(b1_d1); + c.insert(b2_d1); + if (!CHECK(c.size() == 4)) + return; + + if (!CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1)) + return; + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Book(a1, a2, domain1)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, domain1)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + } + + template + 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 value_type; + + { + Map c; + + // c.insert (value_type (b1, 1)); + c.insert(std::make_pair(b1, 1)); + if (!CHECK(c.size() == 1)) + return; + // c.insert (value_type (b2, 2)); + c.insert(std::make_pair(b2, 1)); + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Book(a1, a1, std::nullopt)) == 0)) + return; + if (!CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + + { + Map c; + + // c.insert (value_type (b1, 1)); + c.insert(std::make_pair(b1, 1)); + if (!CHECK(c.size() == 1)) + return; + // c.insert (value_type (b2, 2)); + c.insert(std::make_pair(b2, 1)); + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Book(a1, a1, std::nullopt)) == 0)) + return; + if (!CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + + { + Map c; + + c.insert(std::make_pair(b1_d1, 10)); + if (!CHECK(c.size() == 1)) + return; + c.insert(std::make_pair(b2_d1, 20)); + if (!CHECK(c.size() == 2)) + return; + c.insert(std::make_pair(b1_d2, 30)); + if (!CHECK(c.size() == 3)) + return; + c.insert(std::make_pair(b2_d2, 40)); + if (!CHECK(c.size() == 4)) + return; + + // Try removing non-existent elements + if (!CHECK(c.erase(Book(a2, a2, domain1)) == 0)) + return; + + if (!CHECK(c.erase(Book(a1, a2, domain1)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, domain1)) == 1)) + return; + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Book(a1, a2, domain2)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, domain2)) == 1)) + return; + if (!CHECK(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 (!CHECK(c.size() == 4)) + return; + + // Try removing non-existent elements + if (!CHECK(c.erase(Book(a1, a1, domain1)) == 0)) + return; + if (!CHECK(c.erase(Book(a2, a2, domain2)) == 0)) + return; + + if (!CHECK(c.erase(Book(a1, a2, std::nullopt)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, std::nullopt)) == 1)) + return; + if (!CHECK(c.size() == 2)) + return; + + if (!CHECK(c.erase(Book(a1, a2, domain1)) == 1)) + return; + if (!CHECK(c.erase(Book(a2, a1, domain1)) == 1)) + return; + if (!CHECK(c.empty())) + return; + } + } + + + //-------------------------------------------------------------------------- + + // End of helper functions. +} + + +} // namespace ripple + +TEST_SUITE_BEGIN("Issue"); + +TEST_CASE("Unsigned types") +{ + testUnsigned(); + testUnsigned(); +} + +TEST_CASE("Issue") +{ + testIssue(); +} + +TEST_CASE("Issue sets") +{ + INFO("std::set "); + testIssueSet>(); + + INFO("std::set "); + testIssueSet>(); + +#if RIPPLE_ASSETS_ENABLE_STD_HASH + INFO("std::unordered_set "); + testIssueSet>(); + + INFO("std::unordered_set "); + testIssueSet>(); +#endif + + INFO("hash_set "); + testIssueSet>(); + + INFO("hash_set "); + testIssueSet>(); +} + +TEST_CASE("Issue maps") +{ + INFO("std::map "); + testIssueMap>(); + + INFO("std::map "); + testIssueMap>(); + +#if RIPPLE_ASSETS_ENABLE_STD_HASH + INFO("std::unordered_map "); + testIssueMap>(); + + INFO("std::unordered_map "); + testIssueMap>(); + + INFO("hash_map "); + testIssueMap>(); + + INFO("hash_map "); + testIssueMap>(); +#endif +} + +TEST_CASE("Book") +{ + testBook(); +} + +TEST_CASE("Book sets") +{ + INFO("std::set "); + testBookSet>(); + + INFO("std::set "); + testBookSet>(); + +#if RIPPLE_ASSETS_ENABLE_STD_HASH + INFO("std::unordered_set "); + testBookSet>(); + + INFO("std::unordered_set "); + testBookSet>(); +#endif + + INFO("hash_set "); + testBookSet>(); + + INFO("hash_set "); + testBookSet>(); +} + +TEST_CASE("Book maps") +{ + INFO("std::map "); + testBookMap>(); + + INFO("std::map "); + testBookMap>(); + +#if RIPPLE_ASSETS_ENABLE_STD_HASH + INFO("std::unordered_map "); + testBookMap>(); + + INFO("std::unordered_map "); + testBookMap>(); + + INFO("hash_map "); + testBookMap>(); + + INFO("hash_map "); + testBookMap>(); +#endif +} + +TEST_CASE("Issue domain sets") +{ + INFO("std::set >"); + testIssueDomainSet>>(); + + INFO("std::set >"); + testIssueDomainSet>>(); + + INFO("hash_set >"); + testIssueDomainSet>>(); + + INFO("hash_set >"); + testIssueDomainSet>>(); +} + +TEST_CASE("Issue domain maps") +{ + INFO("std::map , int>"); + testIssueDomainMap, int>>(); + + INFO("std::map , int>"); + testIssueDomainMap, int>>(); + +#if RIPPLE_ASSETS_ENABLE_STD_HASH + INFO("hash_map , int>"); + testIssueDomainMap, int>>(); + + INFO("hash_map , int>"); + testIssueDomainMap, int>>(); + + INFO("hardened_hash_map , int>"); + testIssueDomainMap, int>>(); + + INFO("hardened_hash_map , int>"); + testIssueDomainMap, int>>(); +#endif +} + +TEST_SUITE_END(); + + diff --git a/src/tests/libxrpl/protocol/Memo.cpp b/src/tests/libxrpl/protocol/Memo.cpp new file mode 100644 index 0000000000..91878b13ac --- /dev/null +++ b/src/tests/libxrpl/protocol/Memo.cpp @@ -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 +#include +#include + +#include + +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 +#include + +#include +#include +#include +#include +#include + +namespace ripple { +namespace test { + +namespace { + +// This needs to be in a namespace because of deduction guide +template +struct Overload : Ts... +{ + using Ts::operator()...; +}; +template +Overload(Ts...) -> Overload; + +} // 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>); + + CHECK(subject.val.size() == 3); + CHECK(subject.val == std::array{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(v).visit(), // + [](Json::Value&, auto) {}); // missing const + }; + }(std::as_const(s1))); + static_assert([](auto&& v) { + return !requires { + forAllApiVersions( + std::forward(v).visit(), // + [](Json::Value&) {}); // missing const + }; + }(std::as_const(s1))); + static_assert([](auto&& v) { + return !requires { + forAllApiVersions( + std::forward(v).visit(), // + []() {}); // missing parameters + }; + }(std::as_const(s1))); + static_assert([](auto&& v) { + return !requires { + forAllApiVersions( + std::forward(v).visit(), // + [](auto) {}, + 1); // missing parameters + }; + }(std::as_const(s1))); + static_assert([](auto&& v) { + return !requires { + forAllApiVersions( + std::forward(v).visit(), // + [](auto, auto) {}, + 1); // missing parameters + }; + }(std::as_const(s1))); + static_assert([](auto&& v) { + return !requires { + forAllApiVersions( + std::forward(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(v).visit(), // + [](auto) {}); + }; + }(s1)); + static_assert([](auto&& v) { + return requires { + forAllApiVersions( + std::forward(v).visit(), // + [](Json::Value const&) {}); + }; + }(std::as_const(s1))); + static_assert([](auto&& v) { + return requires { + forAllApiVersions( + std::forward(v).visit(), // + [](auto...) {}); + }; + }(s1)); + static_assert([](auto&& v) { + return requires { + forAllApiVersions( + std::forward(v).visit(), // + [](Json::Value const&, auto...) {}); + }; + }(std::as_const(s1))); + static_assert([](auto&& v) { + return requires { + forAllApiVersions( + std::forward(v).visit(), // + [](Json::Value&, auto, auto, auto...) {}, + 0, + ""); + }; + }(s1)); + static_assert([](auto&& v) { + return requires { + forAllApiVersions( + std::forward(v).visit(), // + []( + Json::Value const&, + std::integral_constant, + int, + char const*) {}, + 0, + ""); + }; + }(std::as_const(s1))); + static_assert([](auto&& v) { + return requires { + forAllApiVersions( + std::forward(v).visit(), // + [](auto...) {}); + }; + }(std::move(s1))); + static_assert([](auto&& v) { + return requires { + forAllApiVersions( + std::forward(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{})); + 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{}, + [](Json::Value&, std::integral_constant) {}); + }; + }(s1)); + CHECK( + s1.visitor( + s1, + std::integral_constant{}, + Overload{ + [](Json::Value& v, + std::integral_constant) { + 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{}, + [](Json::Value&) {}); + }; + }(s1)); + CHECK( + s1.visitor( + s1, + std::integral_constant{}, + 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{}, + [](Json::Value const&, + std::integral_constant) {}); + }; + }(std::as_const(s1))); + CHECK( + s1.visitor( + std::as_const(s1), + std::integral_constant{}, + Overload{ + [](Json::Value const& v, + std::integral_constant) { + 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{}, + [](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{}, + [](Json::Value&, std::integral_constant) {}); + }; + }(s1)); + CHECK( + s1.visit( + std::integral_constant{}, + Overload{ + [](Json::Value& v, + std::integral_constant) { + 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{}, + [](Json::Value&, std::integral_constant) {}); + }; + }(s1)); + CHECK( + s1.visit()(std::integral_constant{}, + Overload{[](Json::Value& v, + std::integral_constant) { + 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{}, + [](Json::Value&) {}); + }; + }(s1)); + CHECK( + s1.visit( + std::integral_constant{}, + 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{}, [](Json::Value&) {}); + }; + }(s1)); + CHECK( + s1.visit()(std::integral_constant{}, + 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{}, + [](Json::Value const&, + std::integral_constant) {}); + }; + }(std::as_const(s1))); + CHECK( + std::as_const(s1).visit( + std::integral_constant{}, + Overload{ + [](Json::Value const& v, + std::integral_constant) { + 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{}, + [](Json::Value const&, + std::integral_constant) {}); + }; + }(std::as_const(s1))); + CHECK( + std::as_const(s1).visit()(std::integral_constant{}, + Overload{[](Json::Value const& v, + std::integral_constant) { + 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{}, [](Json::Value const&) {}); + }; + }(std::as_const(s1))); + CHECK( + std::as_const(s1).visit( + std::integral_constant{}, + 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{}, + [](Json::Value const&) {}); + }; + }(std::as_const(s1))); + CHECK( + std::as_const(s1).visit()(std::integral_constant{}, + 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(); diff --git a/src/tests/libxrpl/protocol/PublicKey.cpp b/src/tests/libxrpl/protocol/PublicKey.cpp new file mode 100644 index 0000000000..647458540f --- /dev/null +++ b/src/tests/libxrpl/protocol/PublicKey.cpp @@ -0,0 +1,503 @@ +//------------------------------------------------------------------------------ +/* + 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 +#include +#include + +#include + +namespace ripple { + +namespace { + +using blob = std::vector; + +template +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 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( + TokenType::NodePublic, + "n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9"); + CHECK(pk2); + + CHECK(pk1 == *pk2); + } + + // Try converting short, long and malformed data for secp256k1 keys + CHECK(!parseBase58(TokenType::NodePublic, "")); + CHECK(!parseBase58(TokenType::NodePublic, " ")); + CHECK(!parseBase58(TokenType::NodePublic, "!ty89234gh45")); + + auto good = toBase58( + TokenType::NodePublic, derivePublicKey(KeyType::secp256k1, randomSecretKey())); + + { + auto s = good; + std::hash r; + while (!s.empty()) + { + s.erase(r(s) % s.size(), 1); + CHECK(!parseBase58(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(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(TokenType::NodePublic, s)); + } + } + + { + auto s = good; + for (auto c : std::string("apsrJqtv7")) + { + s[0] = c; + CHECK(!parseBase58(TokenType::NodePublic, s)); + } + } + + std::vector 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(TokenType::NodePublic, si); + CHECK(ski && (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(TokenType::NodePublic, sj); + CHECK(skj && (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( + 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 r; + while (!s.empty()) + { + s.erase(r(s) % s.size(), 1); + CHECK(!parseBase58(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(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(TokenType::NodePublic, s)); + } + } + + { + auto s = good; + for (auto c : std::string("apsrJqtv7")) + { + s[0] = c; + CHECK(!parseBase58(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(TokenType::NodePublic, si); + CHECK(ski && (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(TokenType::NodePublic, sj); + CHECK(skj && (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 + diff --git a/src/tests/libxrpl/protocol/main.cpp b/src/tests/libxrpl/protocol/main.cpp new file mode 100644 index 0000000000..0a3f254ea8 --- /dev/null +++ b/src/tests/libxrpl/protocol/main.cpp @@ -0,0 +1,2 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include