Don't include unit test sources in code coverage (RIPD-1132):

Most files containing unit test code are moved to
src/test. JTx and the test client code are not yet moved.
This commit is contained in:
Brad Chase
2016-09-02 15:25:05 -04:00
committed by Vinnie Falco
parent 8687f64429
commit 8f97889176
165 changed files with 2090 additions and 1693 deletions

View File

@@ -0,0 +1,107 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/protocol/BuildInfo.h>
#include <ripple/beast/core/SemanticVersion.h>
#include <ripple/beast/unit_test.h>
namespace ripple {
class BuildInfo_test : public beast::unit_test::suite
{
public:
ProtocolVersion
from_version (std::uint16_t major, std::uint16_t minor)
{
return ProtocolVersion (major, minor);
}
void testValues ()
{
testcase ("comparison");
BEAST_EXPECT(from_version (1,2) == from_version (1,2));
BEAST_EXPECT(from_version (3,4) >= from_version (3,4));
BEAST_EXPECT(from_version (5,6) <= from_version (5,6));
BEAST_EXPECT(from_version (7,8) > from_version (6,7));
BEAST_EXPECT(from_version (7,8) < from_version (8,9));
BEAST_EXPECT(from_version (65535,0) < from_version (65535,65535));
BEAST_EXPECT(from_version (65535,65535) >= from_version (65535,65535));
}
void testStringVersion ()
{
testcase ("string version");
for (std::uint16_t major = 0; major < 8; major++)
{
for (std::uint16_t minor = 0; minor < 8; minor++)
{
BEAST_EXPECT(to_string (from_version (major, minor)) ==
std::to_string (major) + "." + std::to_string (minor));
}
}
}
void testVersionPacking ()
{
testcase ("version packing");
BEAST_EXPECT(to_packed (from_version (0, 0)) == 0);
BEAST_EXPECT(to_packed (from_version (0, 1)) == 1);
BEAST_EXPECT(to_packed (from_version (0, 255)) == 255);
BEAST_EXPECT(to_packed (from_version (0, 65535)) == 65535);
BEAST_EXPECT(to_packed (from_version (1, 0)) == 65536);
BEAST_EXPECT(to_packed (from_version (1, 1)) == 65537);
BEAST_EXPECT(to_packed (from_version (1, 255)) == 65791);
BEAST_EXPECT(to_packed (from_version (1, 65535)) == 131071);
BEAST_EXPECT(to_packed (from_version (255, 0)) == 16711680);
BEAST_EXPECT(to_packed (from_version (255, 1)) == 16711681);
BEAST_EXPECT(to_packed (from_version (255, 255)) == 16711935);
BEAST_EXPECT(to_packed (from_version (255, 65535)) == 16777215);
BEAST_EXPECT(to_packed (from_version (65535, 0)) == 4294901760);
BEAST_EXPECT(to_packed (from_version (65535, 1)) == 4294901761);
BEAST_EXPECT(to_packed (from_version (65535, 255)) == 4294902015);
BEAST_EXPECT(to_packed (from_version (65535, 65535)) == 4294967295);
}
void run ()
{
testValues ();
testStringVersion ();
testVersionPacking ();
auto const current_protocol = BuildInfo::getCurrentProtocol ();
auto const minimum_protocol = BuildInfo::getMinimumProtocol ();
BEAST_EXPECT(current_protocol >= minimum_protocol);
log <<
" Ripple Version: " << BuildInfo::getVersionString() << '\n' <<
" Protocol Version: " << to_string (current_protocol) << std::endl;
}
};
BEAST_DEFINE_TESTSUITE(BuildInfo,ripple_data,ripple);
} // ripple

View File

@@ -0,0 +1,263 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/protocol/IOUAmount.h>
#include <ripple/beast/unit_test.h>
namespace ripple {
class IOUAmount_test : public beast::unit_test::suite
{
public:
void testZero ()
{
testcase ("zero");
IOUAmount const z (0, 0);
BEAST_EXPECT(z.mantissa () == 0);
BEAST_EXPECT(z.exponent () == -100);
BEAST_EXPECT(!z);
BEAST_EXPECT(z.signum () == 0);
BEAST_EXPECT(z == zero);
BEAST_EXPECT((z + z) == z);
BEAST_EXPECT((z - z) == z);
BEAST_EXPECT(z == -z);
IOUAmount const zz (zero);
BEAST_EXPECT(z == zz);
}
void testSigNum ()
{
testcase ("signum");
IOUAmount const neg (-1, 0);
BEAST_EXPECT(neg.signum () < 0);
IOUAmount const zer (0, 0);
BEAST_EXPECT(zer.signum () == 0);
IOUAmount const pos (1, 0);
BEAST_EXPECT(pos.signum () > 0);
}
void testBeastZero ()
{
testcase ("beast::Zero Comparisons");
{
IOUAmount z (zero);
BEAST_EXPECT(z == zero);
BEAST_EXPECT(z >= zero);
BEAST_EXPECT(z <= zero);
unexpected (z != zero);
unexpected (z > zero);
unexpected (z < zero);
}
{
IOUAmount const neg (-2, 0);
BEAST_EXPECT(neg < zero);
BEAST_EXPECT(neg <= zero);
BEAST_EXPECT(neg != zero);
unexpected (neg == zero);
}
{
IOUAmount const pos (2, 0);
BEAST_EXPECT(pos > zero);
BEAST_EXPECT(pos >= zero);
BEAST_EXPECT(pos != zero);
unexpected (pos == zero);
}
}
void testComparisons ()
{
testcase ("IOU Comparisons");
IOUAmount const n (-2, 0);
IOUAmount const z (0, 0);
IOUAmount const p (2, 0);
BEAST_EXPECT(z == z);
BEAST_EXPECT(z >= z);
BEAST_EXPECT(z <= z);
BEAST_EXPECT(z == -z);
unexpected (z > z);
unexpected (z < z);
unexpected (z != z);
unexpected (z != -z);
BEAST_EXPECT(n < z);
BEAST_EXPECT(n <= z);
BEAST_EXPECT(n != z);
unexpected (n > z);
unexpected (n >= z);
unexpected (n == z);
BEAST_EXPECT(p > z);
BEAST_EXPECT(p >= z);
BEAST_EXPECT(p != z);
unexpected (p < z);
unexpected (p <= z);
unexpected (p == z);
BEAST_EXPECT(n < p);
BEAST_EXPECT(n <= p);
BEAST_EXPECT(n != p);
unexpected (n > p);
unexpected (n >= p);
unexpected (n == p);
BEAST_EXPECT(p > n);
BEAST_EXPECT(p >= n);
BEAST_EXPECT(p != n);
unexpected (p < n);
unexpected (p <= n);
unexpected (p == n);
BEAST_EXPECT(p > -p);
BEAST_EXPECT(p >= -p);
BEAST_EXPECT(p != -p);
BEAST_EXPECT(n < -n);
BEAST_EXPECT(n <= -n);
BEAST_EXPECT(n != -n);
}
void testToString()
{
testcase("IOU strings");
BEAST_EXPECT(to_string(IOUAmount (-2, 0)) == "-2");
BEAST_EXPECT(to_string(IOUAmount (0, 0)) == "0");
BEAST_EXPECT(to_string(IOUAmount (2, 0)) == "2");
BEAST_EXPECT(to_string(IOUAmount (25, -3)) == "0.025");
BEAST_EXPECT(to_string(IOUAmount (-25, -3)) == "-0.025");
BEAST_EXPECT(to_string(IOUAmount (25, 1)) == "250");
BEAST_EXPECT(to_string(IOUAmount (-25, 1)) == "-250");
BEAST_EXPECT(to_string(IOUAmount (2, 20)) == "2000000000000000e5");
BEAST_EXPECT(to_string(IOUAmount (-2, -20)) == "-2000000000000000e-35");
}
void testMulRatio()
{
testcase ("mulRatio");
/* The range for the mantissa when normalized */
constexpr std::int64_t minMantissa = 1000000000000000ull;
constexpr std::int64_t maxMantissa = 9999999999999999ull;
// log(2,maxMantissa) ~ 53.15
/* The range for the exponent when normalized */
constexpr int minExponent = -96;
constexpr int maxExponent = 80;
constexpr auto maxUInt = std::numeric_limits<std::uint32_t>::max ();
{
// multiply by a number that would overflow the mantissa, then
// divide by the same number, and check we didn't lose any value
IOUAmount bigMan (maxMantissa, 0);
BEAST_EXPECT(bigMan == mulRatio (bigMan, maxUInt, maxUInt, true));
// rounding mode shouldn't matter as the result is exact
BEAST_EXPECT(bigMan == mulRatio (bigMan, maxUInt, maxUInt, false));
}
{
// Similar test as above, but for negative values
IOUAmount bigMan (-maxMantissa, 0);
BEAST_EXPECT(bigMan == mulRatio (bigMan, maxUInt, maxUInt, true));
// rounding mode shouldn't matter as the result is exact
BEAST_EXPECT(bigMan == mulRatio (bigMan, maxUInt, maxUInt, false));
}
{
// small amounts
IOUAmount tiny (minMantissa, minExponent);
// Round up should give the smallest allowable number
BEAST_EXPECT(tiny == mulRatio (tiny, 1, maxUInt, true));
BEAST_EXPECT(tiny == mulRatio (tiny, maxUInt - 1, maxUInt, true));
// rounding down should be zero
BEAST_EXPECT(beast::zero == mulRatio (tiny, 1, maxUInt, false));
BEAST_EXPECT(beast::zero == mulRatio (tiny, maxUInt - 1, maxUInt, false));
// tiny negative numbers
IOUAmount tinyNeg (-minMantissa, minExponent);
// Round up should give zero
BEAST_EXPECT(zero == mulRatio (tinyNeg, 1, maxUInt, true));
BEAST_EXPECT(zero == mulRatio (tinyNeg, maxUInt - 1, maxUInt, true));
// rounding down should be tiny
BEAST_EXPECT(tinyNeg == mulRatio (tinyNeg, 1, maxUInt, false));
BEAST_EXPECT(tinyNeg == mulRatio (tinyNeg, maxUInt - 1, maxUInt, false));
}
{
// rounding
{
IOUAmount one (1, 0);
auto const rup = mulRatio (one, maxUInt - 1, maxUInt, true);
auto const rdown = mulRatio (one, maxUInt - 1, maxUInt, false);
BEAST_EXPECT(rup.mantissa () - rdown.mantissa () == 1);
}
{
IOUAmount big (maxMantissa, maxExponent);
auto const rup = mulRatio (big, maxUInt - 1, maxUInt, true);
auto const rdown = mulRatio (big, maxUInt - 1, maxUInt, false);
BEAST_EXPECT(rup.mantissa () - rdown.mantissa () == 1);
}
{
IOUAmount negOne (-1, 0);
auto const rup = mulRatio (negOne, maxUInt - 1, maxUInt, true);
auto const rdown = mulRatio (negOne, maxUInt - 1, maxUInt, false);
BEAST_EXPECT(rup.mantissa () - rdown.mantissa () == 1);
}
}
{
// division by zero
IOUAmount one (1, 0);
except ([&] {mulRatio (one, 1, 0, true);});
}
{
// overflow
IOUAmount big (maxMantissa, maxExponent);
except ([&] {mulRatio (big, 2, 0, true);});
}
}
//--------------------------------------------------------------------------
void run ()
{
testZero ();
testSigNum ();
testBeastZero ();
testComparisons ();
testToString ();
testMulRatio ();
}
};
BEAST_DEFINE_TESTSUITE(IOUAmount,protocol,ripple);
} // ripple

View File

@@ -0,0 +1,205 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/basics/contract.h>
#include <ripple/protocol/InnerObjectFormats.h>
#include <ripple/protocol/ErrorCodes.h> // RPC::containsError
#include <ripple/json/json_reader.h> // Json::Reader
#include <ripple/protocol/STParsedJSON.h> // STParsedJSONObject
#include <ripple/beast/unit_test.h>
namespace ripple {
namespace InnerObjectFormatsUnitTestDetail
{
struct TestJSONTxt
{
std::string const txt;
bool const expectFail;
};
static TestJSONTxt const testArray[] =
{
// Valid SignerEntry
{R"({
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
"SignerEntries" :
[
{
"SignerEntry" :
{
"Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"SignerWeight" : 4
}
},
{
"SignerEntry" :
{
"Account" : "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
"SignerWeight" : 3
}
}
],
"SignerQuorum" : 7,
"TransactionType" : "SignerListSet"
})", false
},
// SignerEntry missing Account
{R"({
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
"SignerEntries" :
[
{
"SignerEntry" :
{
"Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"SignerWeight" : 4
}
},
{
"SignerEntry" :
{
"SignerWeight" : 3
}
}
],
"SignerQuorum" : 7,
"TransactionType" : "SignerListSet"
})", true
},
// SignerEntry missing SignerWeight
{R"({
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
"SignerEntries" :
[
{
"SignerEntry" :
{
"Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"SignerWeight" : 4
}
},
{
"SignerEntry" :
{
"Account" : "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
}
}
],
"SignerQuorum" : 7,
"TransactionType" : "SignerListSet"
})", true
},
// SignerEntry with unexpected Amount
{R"({
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
"SignerEntries" :
[
{
"SignerEntry" :
{
"Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"SignerWeight" : 4
}
},
{
"SignerEntry" :
{
"Amount" : "1000000",
"Account" : "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
"SignerWeight" : 3
}
}
],
"SignerQuorum" : 7,
"TransactionType" : "SignerListSet"
})", true
},
// SignerEntry with no Account and unexpected Amount
{R"({
"Account" : "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
"SignerEntries" :
[
{
"SignerEntry" :
{
"Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"SignerWeight" : 4
}
},
{
"SignerEntry" :
{
"Amount" : "10000000",
"SignerWeight" : 3
}
}
],
"SignerQuorum" : 7,
"TransactionType" : "SignerListSet"
})", true
},
};
} // namespace InnerObjectFormatsUnitTestDetail
class InnerObjectFormatsParsedJSON_test : public beast::unit_test::suite
{
public:
void run()
{
using namespace InnerObjectFormatsUnitTestDetail;
for (auto const& test : testArray)
{
Json::Value req;
Json::Reader ().parse (test.txt, req);
if (RPC::contains_error (req))
{
Throw<std::runtime_error> (
"Internal InnerObjectFormatsParsedJSON error. Bad JSON.");
}
STParsedJSONObject parsed ("request", req);
bool const noObj = parsed.object == boost::none;
if ( noObj == test.expectFail )
{
pass ();
}
else
{
std::string errStr ("Unexpected STParsedJSON result on:\n");
errStr += test.txt;
fail (errStr);
}
}
}
};
BEAST_DEFINE_TESTSUITE(InnerObjectFormatsParsedJSON,ripple_app,ripple);
} // ripple

View File

@@ -0,0 +1,494 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/basics/UnorderedContainers.h>
#include <ripple/protocol/Book.h>
#include <ripple/protocol/Issue.h>
#include <ripple/beast/unit_test.h>
#include <map>
#include <set>
#include <typeinfo>
#include <unordered_set>
#if BEAST_MSVC
# define STL_SET_HAS_EMPLACE 1
#else
# define STL_SET_HAS_EMPLACE 0
#endif
#ifndef RIPPLE_ASSETS_ENABLE_STD_HASH
# if BEAST_MAC || BEAST_IOS
# define RIPPLE_ASSETS_ENABLE_STD_HASH 0
# else
# define RIPPLE_ASSETS_ENABLE_STD_HASH 1
# endif
#endif
namespace ripple {
class Issue_test : public beast::unit_test::suite
{
public:
// Comparison, hash tests for uint60 (via base_uint)
template <typename Unsigned>
void testUnsigned ()
{
Unsigned const u1 (1);
Unsigned const u2 (2);
Unsigned const u3 (3);
BEAST_EXPECT(u1 != u2);
BEAST_EXPECT(u1 < u2);
BEAST_EXPECT(u1 <= u2);
BEAST_EXPECT(u2 <= u2);
BEAST_EXPECT(u2 == u2);
BEAST_EXPECT(u2 >= u2);
BEAST_EXPECT(u3 >= u2);
BEAST_EXPECT(u3 > u2);
std::hash <Unsigned> hash;
BEAST_EXPECT(hash (u1) == hash (u1));
BEAST_EXPECT(hash (u2) == hash (u2));
BEAST_EXPECT(hash (u3) == hash (u3));
BEAST_EXPECT(hash (u1) != hash (u2));
BEAST_EXPECT(hash (u1) != hash (u3));
BEAST_EXPECT(hash (u2) != hash (u3));
}
//--------------------------------------------------------------------------
// Comparison, hash tests for Issue
template <class Issue>
void testIssue ()
{
Currency const c1 (1); AccountID const i1 (1);
Currency const c2 (2); AccountID const i2 (2);
Currency const c3 (3); AccountID const i3 (3);
BEAST_EXPECT(Issue (c1, i1) != Issue (c2, i1));
BEAST_EXPECT(Issue (c1, i1) < Issue (c2, i1));
BEAST_EXPECT(Issue (c1, i1) <= Issue (c2, i1));
BEAST_EXPECT(Issue (c2, i1) <= Issue (c2, i1));
BEAST_EXPECT(Issue (c2, i1) == Issue (c2, i1));
BEAST_EXPECT(Issue (c2, i1) >= Issue (c2, i1));
BEAST_EXPECT(Issue (c3, i1) >= Issue (c2, i1));
BEAST_EXPECT(Issue (c3, i1) > Issue (c2, i1));
BEAST_EXPECT(Issue (c1, i1) != Issue (c1, i2));
BEAST_EXPECT(Issue (c1, i1) < Issue (c1, i2));
BEAST_EXPECT(Issue (c1, i1) <= Issue (c1, i2));
BEAST_EXPECT(Issue (c1, i2) <= Issue (c1, i2));
BEAST_EXPECT(Issue (c1, i2) == Issue (c1, i2));
BEAST_EXPECT(Issue (c1, i2) >= Issue (c1, i2));
BEAST_EXPECT(Issue (c1, i3) >= Issue (c1, i2));
BEAST_EXPECT(Issue (c1, i3) > Issue (c1, i2));
std::hash <Issue> hash;
BEAST_EXPECT(hash (Issue (c1, i1)) == hash (Issue (c1, i1)));
BEAST_EXPECT(hash (Issue (c1, i2)) == hash (Issue (c1, i2)));
BEAST_EXPECT(hash (Issue (c1, i3)) == hash (Issue (c1, i3)));
BEAST_EXPECT(hash (Issue (c2, i1)) == hash (Issue (c2, i1)));
BEAST_EXPECT(hash (Issue (c2, i2)) == hash (Issue (c2, i2)));
BEAST_EXPECT(hash (Issue (c2, i3)) == hash (Issue (c2, i3)));
BEAST_EXPECT(hash (Issue (c3, i1)) == hash (Issue (c3, i1)));
BEAST_EXPECT(hash (Issue (c3, i2)) == hash (Issue (c3, i2)));
BEAST_EXPECT(hash (Issue (c3, i3)) == hash (Issue (c3, i3)));
BEAST_EXPECT(hash (Issue (c1, i1)) != hash (Issue (c1, i2)));
BEAST_EXPECT(hash (Issue (c1, i1)) != hash (Issue (c1, i3)));
BEAST_EXPECT(hash (Issue (c1, i1)) != hash (Issue (c2, i1)));
BEAST_EXPECT(hash (Issue (c1, i1)) != hash (Issue (c2, i2)));
BEAST_EXPECT(hash (Issue (c1, i1)) != hash (Issue (c2, i3)));
BEAST_EXPECT(hash (Issue (c1, i1)) != hash (Issue (c3, i1)));
BEAST_EXPECT(hash (Issue (c1, i1)) != hash (Issue (c3, i2)));
BEAST_EXPECT(hash (Issue (c1, i1)) != hash (Issue (c3, i3)));
}
template <class Set>
void testIssueSet ()
{
Currency const c1 (1);
AccountID const i1 (1);
Currency const c2 (2);
AccountID const i2 (2);
Issue const a1 (c1, i1);
Issue const a2 (c2, i2);
{
Set c;
c.insert (a1);
if (! BEAST_EXPECT(c.size () == 1)) return;
c.insert (a2);
if (! BEAST_EXPECT(c.size () == 2)) return;
if (! BEAST_EXPECT(c.erase (Issue (c1, i2)) == 0)) return;
if (! BEAST_EXPECT(c.erase (Issue (c1, i1)) == 1)) return;
if (! BEAST_EXPECT(c.erase (Issue (c2, i2)) == 1)) return;
if (! BEAST_EXPECT(c.empty ())) return;
}
{
Set c;
c.insert (a1);
if (! BEAST_EXPECT(c.size () == 1)) return;
c.insert (a2);
if (! BEAST_EXPECT(c.size () == 2)) return;
if (! BEAST_EXPECT(c.erase (Issue (c1, i2)) == 0)) return;
if (! BEAST_EXPECT(c.erase (Issue (c1, i1)) == 1)) return;
if (! BEAST_EXPECT(c.erase (Issue (c2, i2)) == 1)) return;
if (! BEAST_EXPECT(c.empty ())) return;
#if STL_SET_HAS_EMPLACE
c.emplace (c1, i1);
if (! BEAST_EXPECT(c.size() == 1)) return;
c.emplace (c2, i2);
if (! BEAST_EXPECT(c.size() == 2)) return;
#endif
}
}
template <class Map>
void testIssueMap ()
{
Currency const c1 (1);
AccountID const i1 (1);
Currency const c2 (2);
AccountID const i2 (2);
Issue const a1 (c1, i1);
Issue const a2 (c2, i2);
{
Map c;
c.insert (std::make_pair (a1, 1));
if (! BEAST_EXPECT(c.size () == 1)) return;
c.insert (std::make_pair (a2, 2));
if (! BEAST_EXPECT(c.size () == 2)) return;
if (! BEAST_EXPECT(c.erase (Issue (c1, i2)) == 0)) return;
if (! BEAST_EXPECT(c.erase (Issue (c1, i1)) == 1)) return;
if (! BEAST_EXPECT(c.erase (Issue (c2, i2)) == 1)) return;
if (! BEAST_EXPECT(c.empty ())) return;
}
{
Map c;
c.insert (std::make_pair (a1, 1));
if (! BEAST_EXPECT(c.size () == 1)) return;
c.insert (std::make_pair (a2, 2));
if (! BEAST_EXPECT(c.size () == 2)) return;
if (! BEAST_EXPECT(c.erase (Issue (c1, i2)) == 0)) return;
if (! BEAST_EXPECT(c.erase (Issue (c1, i1)) == 1)) return;
if (! BEAST_EXPECT(c.erase (Issue (c2, i2)) == 1)) return;
if (! BEAST_EXPECT(c.empty ())) return;
}
}
void testIssueSets ()
{
testcase ("std::set <Issue>");
testIssueSet <std::set <Issue>> ();
testcase ("std::set <Issue>");
testIssueSet <std::set <Issue>> ();
#if RIPPLE_ASSETS_ENABLE_STD_HASH
testcase ("std::unordered_set <Issue>");
testIssueSet <std::unordered_set <Issue>> ();
testcase ("std::unordered_set <Issue>");
testIssueSet <std::unordered_set <Issue>> ();
#endif
testcase ("hash_set <Issue>");
testIssueSet <hash_set <Issue>> ();
testcase ("hash_set <Issue>");
testIssueSet <hash_set <Issue>> ();
}
void testIssueMaps ()
{
testcase ("std::map <Issue, int>");
testIssueMap <std::map <Issue, int>> ();
testcase ("std::map <Issue, int>");
testIssueMap <std::map <Issue, int>> ();
#if RIPPLE_ASSETS_ENABLE_STD_HASH
testcase ("std::unordered_map <Issue, int>");
testIssueMap <std::unordered_map <Issue, int>> ();
testcase ("std::unordered_map <Issue, int>");
testIssueMap <std::unordered_map <Issue, int>> ();
testcase ("hash_map <Issue, int>");
testIssueMap <hash_map <Issue, int>> ();
testcase ("hash_map <Issue, int>");
testIssueMap <hash_map <Issue, int>> ();
#endif
}
//--------------------------------------------------------------------------
// Comparison, hash tests for Book
template <class Book>
void testBook ()
{
Currency const c1 (1); AccountID const i1 (1);
Currency const c2 (2); AccountID const i2 (2);
Currency const c3 (3); AccountID const i3 (3);
Issue a1 (c1, i1);
Issue a2 (c1, i2);
Issue a3 (c2, i2);
Issue a4 (c3, i2);
BEAST_EXPECT(Book (a1, a2) != Book (a2, a3));
BEAST_EXPECT(Book (a1, a2) < Book (a2, a3));
BEAST_EXPECT(Book (a1, a2) <= Book (a2, a3));
BEAST_EXPECT(Book (a2, a3) <= Book (a2, a3));
BEAST_EXPECT(Book (a2, a3) == Book (a2, a3));
BEAST_EXPECT(Book (a2, a3) >= Book (a2, a3));
BEAST_EXPECT(Book (a3, a4) >= Book (a2, a3));
BEAST_EXPECT(Book (a3, a4) > Book (a2, a3));
std::hash <Book> hash;
// log << std::hex << hash (Book (a1, a2));
// log << std::hex << hash (Book (a1, a2));
//
// log << std::hex << hash (Book (a1, a3));
// log << std::hex << hash (Book (a1, a3));
//
// log << std::hex << hash (Book (a1, a4));
// log << std::hex << hash (Book (a1, a4));
//
// log << std::hex << hash (Book (a2, a3));
// log << std::hex << hash (Book (a2, a3));
//
// log << std::hex << hash (Book (a2, a4));
// log << std::hex << hash (Book (a2, a4));
//
// log << std::hex << hash (Book (a3, a4));
// log << std::hex << hash (Book (a3, a4));
BEAST_EXPECT(hash (Book (a1, a2)) == hash (Book (a1, a2)));
BEAST_EXPECT(hash (Book (a1, a3)) == hash (Book (a1, a3)));
BEAST_EXPECT(hash (Book (a1, a4)) == hash (Book (a1, a4)));
BEAST_EXPECT(hash (Book (a2, a3)) == hash (Book (a2, a3)));
BEAST_EXPECT(hash (Book (a2, a4)) == hash (Book (a2, a4)));
BEAST_EXPECT(hash (Book (a3, a4)) == hash (Book (a3, a4)));
BEAST_EXPECT(hash (Book (a1, a2)) != hash (Book (a1, a3)));
BEAST_EXPECT(hash (Book (a1, a2)) != hash (Book (a1, a4)));
BEAST_EXPECT(hash (Book (a1, a2)) != hash (Book (a2, a3)));
BEAST_EXPECT(hash (Book (a1, a2)) != hash (Book (a2, a4)));
BEAST_EXPECT(hash (Book (a1, a2)) != hash (Book (a3, a4)));
}
//--------------------------------------------------------------------------
template <class Set>
void testBookSet ()
{
Currency const c1 (1);
AccountID const i1 (1);
Currency const c2 (2);
AccountID const i2 (2);
Issue const a1 (c1, i1);
Issue const a2 (c2, i2);
Book const b1 (a1, a2);
Book const b2 (a2, a1);
{
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)) == 0)) return;
if (! BEAST_EXPECT(c.erase (Book (a1, a2)) == 1)) return;
if (! BEAST_EXPECT(c.erase (Book (a2, a1)) == 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)) == 0)) return;
if (! BEAST_EXPECT(c.erase (Book (a1, a2)) == 1)) return;
if (! BEAST_EXPECT(c.erase (Book (a2, a1)) == 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
}
}
template <class Map>
void testBookMap ()
{
Currency const c1 (1);
AccountID const i1 (1);
Currency const c2 (2);
AccountID const i2 (2);
Issue const a1 (c1, i1);
Issue const a2 (c2, i2);
Book const b1 (a1, a2);
Book const b2 (a2, a1);
//typename Map::value_type value_type;
//std::pair <Book const, int> value_type;
{
Map c;
//c.insert (value_type (b1, 1));
c.insert (std::make_pair (b1, 1));
if (! BEAST_EXPECT(c.size () == 1)) return;
//c.insert (value_type (b2, 2));
c.insert (std::make_pair (b2, 1));
if (! BEAST_EXPECT(c.size () == 2)) return;
if (! BEAST_EXPECT(c.erase (Book (a1, a1)) == 0)) return;
if (! BEAST_EXPECT(c.erase (Book (a1, a2)) == 1)) return;
if (! BEAST_EXPECT(c.erase (Book (a2, a1)) == 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)) == 0)) return;
if (! BEAST_EXPECT(c.erase (Book (a1, a2)) == 1)) return;
if (! BEAST_EXPECT(c.erase (Book (a2, a1)) == 1)) return;
if (! BEAST_EXPECT(c.empty ())) return;
}
}
void testBookSets ()
{
testcase ("std::set <Book>");
testBookSet <std::set <Book>> ();
testcase ("std::set <Book>");
testBookSet <std::set <Book>> ();
#if RIPPLE_ASSETS_ENABLE_STD_HASH
testcase ("std::unordered_set <Book>");
testBookSet <std::unordered_set <Book>> ();
testcase ("std::unordered_set <Book>");
testBookSet <std::unordered_set <Book>> ();
#endif
testcase ("hash_set <Book>");
testBookSet <hash_set <Book>> ();
testcase ("hash_set <Book>");
testBookSet <hash_set <Book>> ();
}
void testBookMaps ()
{
testcase ("std::map <Book, int>");
testBookMap <std::map <Book, int>> ();
testcase ("std::map <Book, int>");
testBookMap <std::map <Book, int>> ();
#if RIPPLE_ASSETS_ENABLE_STD_HASH
testcase ("std::unordered_map <Book, int>");
testBookMap <std::unordered_map <Book, int>> ();
testcase ("std::unordered_map <Book, int>");
testBookMap <std::unordered_map <Book, int>> ();
testcase ("hash_map <Book, int>");
testBookMap <hash_map <Book, int>> ();
testcase ("hash_map <Book, int>");
testBookMap <hash_map <Book, int>> ();
#endif
}
//--------------------------------------------------------------------------
void run()
{
testcase ("Currency");
testUnsigned <Currency> ();
testcase ("AccountID");
testUnsigned <AccountID> ();
// ---
testcase ("Issue");
testIssue <Issue> ();
testcase ("Issue");
testIssue <Issue> ();
testIssueSets ();
testIssueMaps ();
// ---
testcase ("Book");
testBook <Book> ();
testcase ("Book");
testBook <Book> ();
testBookSets ();
testBookMaps ();
}
};
BEAST_DEFINE_TESTSUITE(Issue,protocol,ripple);
}

View File

@@ -0,0 +1,395 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/beast/unit_test.h>
#include <vector>
namespace ripple {
class PublicKey_test : public beast::unit_test::suite
{
public:
using blob = std::vector<std::uint8_t>;
template <class FwdIter, class Container>
static
void
hex_to_binary (FwdIter first, FwdIter last, Container& out)
{
struct Table
{
int val[256];
Table ()
{
std::fill (val, val+256, 0);
for (int i = 0; i < 10; ++i)
val ['0'+i] = i;
for (int i = 0; i < 6; ++i)
{
val ['A'+i] = 10 + i;
val ['a'+i] = 10 + i;
}
}
int operator[] (int i)
{
return val[i];
}
};
static Table lut;
out.reserve (std::distance (first, last) / 2);
while (first != last)
{
auto const hi (lut[(*first++)]);
auto const lo (lut[(*first++)]);
out.push_back ((hi*16)+lo);
}
}
blob
sig (std::string const& hex)
{
blob b;
hex_to_binary (hex.begin (), hex.end (), b);
return b;
}
bool
check (boost::optional<ECDSACanonicality> answer,
std::string const& s)
{
return ecdsaCanonicality(makeSlice(sig(s))) ==
answer;
}
void testCanonical()
{
testcase ("Canonical");
// Fully canonical
BEAST_EXPECT(check(ECDSACanonicality::fullyCanonical,
"3045"
"022100FF478110D1D4294471EC76E0157540C2181F47DEBD25D7F9E7DDCCCD47EEE905"
"0220078F07CDAE6C240855D084AD91D1479609533C147C93B0AEF19BC9724D003F28"));
BEAST_EXPECT(check(ECDSACanonicality::fullyCanonical,
"3045"
"0221009218248292F1762D8A51BE80F8A7F2CD288D810CE781D5955700DA1684DF1D2D"
"022041A1EE1746BFD72C9760CC93A7AAA8047D52C8833A03A20EAAE92EA19717B454"));
BEAST_EXPECT(check(ECDSACanonicality::fullyCanonical,
"3044"
"02206A9E43775F73B6D1EC420E4DDD222A80D4C6DF5D1BEECC431A91B63C928B7581"
"022023E9CC2D61DDA6F73EAA6BCB12688BEB0F434769276B3127E4044ED895C9D96B"));
BEAST_EXPECT(check(ECDSACanonicality::fullyCanonical,
"3044"
"022056E720007221F3CD4EFBB6352741D8E5A0968D48D8D032C2FBC4F6304AD1D04E"
"02201F39EB392C20D7801C3E8D81D487E742FA84A1665E923225BD6323847C71879F"));
BEAST_EXPECT(check(ECDSACanonicality::fullyCanonical,
"3045"
"022100FDFD5AD05518CEA0017A2DCB5C4DF61E7C73B6D3A38E7AE93210A1564E8C2F12"
"0220214FF061CCC123C81D0BB9D0EDEA04CD40D96BF1425D311DA62A7096BB18EA18"));
// Canonical but not fully canonical
BEAST_EXPECT(check(ECDSACanonicality::canonical,
"3046"
"022100F477B3FA6F31C7CB3A0D1AD94A231FDD24B8D78862EE334CEA7CD08F6CBC0A1B"
"022100928E6BCF1ED2684679730C5414AEC48FD62282B090041C41453C1D064AF597A1"));
BEAST_EXPECT(check(ECDSACanonicality::canonical,
"3045"
"022063E7C7CA93CB2400E413A342C027D00665F8BAB9C22EF0A7B8AE3AAF092230B6"
"0221008F2E8BB7D09521ABBC277717B14B93170AE6465C5A1B36561099319C4BEB254C"));
BEAST_EXPECT(check(ECDSACanonicality::canonical,
"3046"
"02210099DCA1188663DDEA506A06A7B20C2B7D8C26AFF41DECE69D6C5F7C967D32625F"
"022100897658A6B1F9EEE5D140D7A332DA0BD73BB98974EA53F6201B01C1B594F286EA"));
BEAST_EXPECT(check(ECDSACanonicality::canonical,
"3045"
"02200855DE366E4E323AA2CE2A25674401A7D11F72EC432770D07F7B57DF7387AEC0"
"022100DA4C6ADDEA14888858DE2AC5B91ED9050D6972BB388DEF582628CEE32869AE35"));
// valid
BEAST_EXPECT(check(ECDSACanonicality::fullyCanonical,
"3006"
"020101"
"020102"));
BEAST_EXPECT(check(ECDSACanonicality::fullyCanonical,
"3044"
"02203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c"
"022030b61dd36543125d56b9f9f3a1f53189e5af33cdda8d77a5209aec03978fa001"));
BEAST_EXPECT(check(ECDSACanonicality::canonical,
"3045"
"0220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a"
"0221008fffd599910eefe00bc803c688eca1d2ba7f6b180620eaa03488e6585db6ba01"));
BEAST_EXPECT(check(ECDSACanonicality::canonical,
"3046"
"022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a"
"0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba"));
BEAST_EXPECT(check(boost::none,
"3005"
"0201FF"
"0200"));
BEAST_EXPECT(check(boost::none,
"3006"
"020101"
"020202"));
BEAST_EXPECT(check(boost::none,
"3006"
"020701"
"020102"));
BEAST_EXPECT(check(boost::none,
"3006"
"020401"
"020102"));
BEAST_EXPECT(check(boost::none,
"3006"
"020501"
"020102"));
BEAST_EXPECT(check(boost::none,
"3006"
"020201"
"020102"));
BEAST_EXPECT(check(boost::none,
"3006"
"020301"
"020202"));
BEAST_EXPECT(check(boost::none,
"3006"
"020401"
"020202"));
BEAST_EXPECT(check(boost::none,
"3047"
"0221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
BEAST_EXPECT(check(boost::none,
"3144"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
BEAST_EXPECT(check(boost::none,
"3045"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
BEAST_EXPECT(check(boost::none,
"301F"
"01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1"));
BEAST_EXPECT(check(boost::none,
"3045"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed00"));
BEAST_EXPECT(check(boost::none,
"3044"
"01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
BEAST_EXPECT(check(boost::none,
"3024"
"0200"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
BEAST_EXPECT(check(boost::none,
"3044"
"02208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
BEAST_EXPECT(check(boost::none,
"3045"
"0221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
BEAST_EXPECT(check(boost::none,
"3044"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105012"
"02d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
BEAST_EXPECT(check(boost::none,
"3024"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"0200"));
BEAST_EXPECT(check(boost::none,
"3044"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"0220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
BEAST_EXPECT(check(boost::none,
"3045"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"0221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"));
}
void testBase58 (KeyType keyType)
{
// Try converting short, long and malformed data
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, ""));
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, " "));
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, "!ty89234gh45"));
auto const good = toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
derivePublicKey (
keyType,
randomSecretKey()));
// Short (non-empty) strings
{
auto s = good;
// Remove all characters from the string in random order:
std::hash<std::string> r;
while (!s.empty())
{
s.erase (r(s) % s.size(), 1);
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, s));
}
}
// Long strings
for (std::size_t i = 1; i != 16; i++)
{
auto s = good;
s.resize (s.size() + i, s[i % s.size()]);
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, s));
}
// Strings with invalid Base58 characters
for (auto c : std::string ("0IOl"))
{
for (std::size_t i = 0; i != good.size(); ++i)
{
auto s = good;
s[i % s.size()] = c;
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, s));
}
}
// Strings with incorrect prefix
{
auto s = good;
for (auto c : std::string("apsrJqtv7"))
{
s[0] = c;
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, s));
}
}
// Try some random secret keys
std::array <PublicKey, 32> keys;
for (std::size_t i = 0; i != keys.size(); ++i)
keys[i] = derivePublicKey (keyType, randomSecretKey());
for (std::size_t i = 0; i != keys.size(); ++i)
{
auto const si = toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
keys[i]);
BEAST_EXPECT(!si.empty());
auto const ski = parseBase58<PublicKey> (
TOKEN_NODE_PUBLIC, 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::TOKEN_NODE_PUBLIC,
keys[j]);
BEAST_EXPECT((si == sj) == (i == j));
auto const skj = parseBase58<PublicKey> (
TOKEN_NODE_PUBLIC, sj);
BEAST_EXPECT(skj && (keys[j] == *skj));
BEAST_EXPECT((*ski == *skj) == (i == j));
}
}
}
void testBase58 ()
{
testcase ("Base58: secp256k1");
{
auto const pk1 = derivePublicKey (
KeyType::secp256k1,
generateSecretKey (
KeyType::secp256k1,
generateSeed ("masterpassphrase")));
auto const pk2 = parseBase58<PublicKey> (
TOKEN_NODE_PUBLIC,
"n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9");
BEAST_EXPECT(pk2);
BEAST_EXPECT(pk1 == *pk2);
}
testBase58 (KeyType::secp256k1);
testcase ("Base58: ed25519");
{
auto const pk1 = derivePublicKey (
KeyType::ed25519,
generateSecretKey (
KeyType::ed25519,
generateSeed ("masterpassphrase")));
auto const pk2 = parseBase58<PublicKey> (
TOKEN_NODE_PUBLIC,
"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;
pk3 = pk2;
BEAST_EXPECT(pk3 == pk2);
BEAST_EXPECT(pk1 == pk3);
}
void run() override
{
testBase58();
testCanonical();
testMiscOperations();
}
};
BEAST_DEFINE_TESTSUITE(PublicKey,protocol,ripple);
} // ripple

View File

@@ -0,0 +1,328 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/protocol/Quality.h>
#include <ripple/beast/unit_test.h>
#include <type_traits>
namespace ripple {
class Quality_test : public beast::unit_test::suite
{
public:
// Create a raw, non-integral amount from mantissa and exponent
STAmount
static raw (std::uint64_t mantissa, int exponent)
{
return STAmount ({Currency(3), AccountID(3)}, mantissa, exponent);
}
template <class Integer>
static
STAmount
amount (Integer integer,
std::enable_if_t <std::is_signed <Integer>::value>* = 0)
{
static_assert (std::is_integral <Integer>::value, "");
return STAmount (integer, false);
}
template <class Integer>
static
STAmount
amount (Integer integer,
std::enable_if_t <! std::is_signed <Integer>::value>* = 0)
{
static_assert (std::is_integral <Integer>::value, "");
if (integer < 0)
return STAmount (-integer, true);
return STAmount (integer, false);
}
template <class In, class Out>
static
Amounts
amounts (In in, Out out)
{
return Amounts (amount(in), amount(out));
}
template <class In1, class Out1, class Int, class In2, class Out2>
void
ceil_in (Quality const& q,
In1 in, Out1 out, Int limit, In2 in_expected, Out2 out_expected)
{
auto expect_result (amounts (in_expected, out_expected));
auto actual_result (q.ceil_in (
amounts (in, out), amount (limit)));
BEAST_EXPECT(actual_result == expect_result);
}
template <class In1, class Out1, class Int, class In2, class Out2>
void
ceil_out (Quality const& q,
In1 in, Out1 out, Int limit, In2 in_expected, Out2 out_expected)
{
auto const expect_result (amounts (in_expected, out_expected));
auto const actual_result (q.ceil_out (
amounts (in, out), amount (limit)));
BEAST_EXPECT(actual_result == expect_result);
}
void
test_ceil_in ()
{
testcase ("ceil_in");
{
// 1 in, 1 out:
Quality q (Amounts (amount(1), amount(1)));
ceil_in (q,
1, 1, // 1 in, 1 out
1, // limit: 1
1, 1); // 1 in, 1 out
ceil_in (q,
10, 10, // 10 in, 10 out
5, // limit: 5
5, 5); // 5 in, 5 out
ceil_in (q,
5, 5, // 5 in, 5 out
10, // limit: 10
5, 5); // 5 in, 5 out
}
{
// 1 in, 2 out:
Quality q (Amounts (amount(1), amount(2)));
ceil_in (q,
40, 80, // 40 in, 80 out
40, // limit: 40
40, 80); // 40 in, 20 out
ceil_in (q,
40, 80, // 40 in, 80 out
20, // limit: 20
20, 40); // 20 in, 40 out
ceil_in (q,
40, 80, // 40 in, 80 out
60, // limit: 60
40, 80); // 40 in, 80 out
}
{
// 2 in, 1 out:
Quality q (Amounts (amount(2), amount(1)));
ceil_in (q,
40, 20, // 40 in, 20 out
20, // limit: 20
20, 10); // 20 in, 10 out
ceil_in (q,
40, 20, // 40 in, 20 out
40, // limit: 40
40, 20); // 40 in, 20 out
ceil_in (q,
40, 20, // 40 in, 20 out
50, // limit: 40
40, 20); // 40 in, 20 out
}
}
void
test_ceil_out ()
{
testcase ("ceil_out");
{
// 1 in, 1 out:
Quality q (Amounts (amount(1),amount(1)));
ceil_out (q,
1, 1, // 1 in, 1 out
1, // limit 1
1, 1); // 1 in, 1 out
ceil_out (q,
10, 10, // 10 in, 10 out
5, // limit 5
5, 5); // 5 in, 5 out
ceil_out (q,
10, 10, // 10 in, 10 out
20, // limit 20
10, 10); // 10 in, 10 out
}
{
// 1 in, 2 out:
Quality q (Amounts (amount(1),amount(2)));
ceil_out (q,
40, 80, // 40 in, 80 out
40, // limit 40
20, 40); // 20 in, 40 out
ceil_out (q,
40, 80, // 40 in, 80 out
80, // limit 80
40, 80); // 40 in, 80 out
ceil_out (q,
40, 80, // 40 in, 80 out
100, // limit 100
40, 80); // 40 in, 80 out
}
{
// 2 in, 1 out:
Quality q (Amounts (amount(2),amount(1)));
ceil_out (q,
40, 20, // 40 in, 20 out
20, // limit 20
40, 20); // 40 in, 20 out
ceil_out (q,
40, 20, // 40 in, 20 out
40, // limit 40
40, 20); // 40 in, 20 out
ceil_out (q,
40, 20, // 40 in, 20 out
10, // limit 10
20, 10); // 20 in, 10 out
}
}
void
test_raw()
{
testcase ("raw");
{
Quality q (0x5d048191fb9130daull); // 126836389.7680090
Amounts const value (
amount(349469768), // 349.469768 XRP
raw (2755280000000000ull, -15)); // 2.75528
STAmount const limit (
raw (4131113916555555, -16)); // .4131113916555555
Amounts const result (
q.ceil_out (value, limit));
BEAST_EXPECT(result.in != zero);
}
}
void
test_comparisons()
{
testcase ("comparisons");
STAmount const amount1 (noIssue(), 231);
STAmount const amount2 (noIssue(), 462);
STAmount const amount3 (noIssue(), 924);
Quality const q11 (Amounts (amount1, amount1));
Quality const q12 (Amounts (amount1, amount2));
Quality const q13 (Amounts (amount1, amount3));
Quality const q21 (Amounts (amount2, amount1));
Quality const q31 (Amounts (amount3, amount1));
BEAST_EXPECT(q11 == q11);
BEAST_EXPECT(q11 < q12);
BEAST_EXPECT(q12 < q13);
BEAST_EXPECT(q31 < q21);
BEAST_EXPECT(q21 < q11);
BEAST_EXPECT(q31 != q21);
}
void
test_composition ()
{
testcase ("composition");
STAmount const amount1 (noIssue(), 231);
STAmount const amount2 (noIssue(), 462);
STAmount const amount3 (noIssue(), 924);
Quality const q11 (Amounts (amount1, amount1));
Quality const q12 (Amounts (amount1, amount2));
Quality const q13 (Amounts (amount1, amount3));
Quality const q21 (Amounts (amount2, amount1));
Quality const q31 (Amounts (amount3, amount1));
BEAST_EXPECT(
composed_quality (q12, q21) == q11);
Quality const q13_31 (
composed_quality (q13, q31));
Quality const q31_13 (
composed_quality (q31, q13));
BEAST_EXPECT(q13_31 == q31_13);
BEAST_EXPECT(q13_31 == q11);
}
void
test_operations ()
{
testcase ("operations");
Quality const q11 (Amounts (
STAmount (noIssue(), 731),
STAmount (noIssue(), 731)));
Quality qa (q11);
Quality qb (q11);
BEAST_EXPECT(qa == qb);
BEAST_EXPECT(++qa != q11);
BEAST_EXPECT(qa != qb);
BEAST_EXPECT(--qb != q11);
BEAST_EXPECT(qa != qb);
BEAST_EXPECT(qb < qa);
BEAST_EXPECT(qb++ < qa);
BEAST_EXPECT(qb++ < qa);
BEAST_EXPECT(qb++ == qa);
BEAST_EXPECT(qa < qb);
}
void
run()
{
test_comparisons ();
test_composition ();
test_operations ();
test_ceil_in ();
test_ceil_out ();
test_raw ();
}
};
BEAST_DEFINE_TESTSUITE(Quality,protocol,ripple);
}

View File

@@ -0,0 +1,134 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2015 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 <BeastConfig.h>
#include <ripple/protocol/STAccount.h>
#include <ripple/beast/unit_test.h>
namespace ripple {
struct STAccount_test : public beast::unit_test::suite
{
void
testSTAccount()
{
{
// Test default constructor.
STAccount const defaultAcct;
BEAST_EXPECT(defaultAcct.getSType() == STI_ACCOUNT);
BEAST_EXPECT(defaultAcct.getText() == "");
BEAST_EXPECT(defaultAcct.isDefault() == true);
BEAST_EXPECT(defaultAcct.value() == AccountID {});
{
#ifdef NDEBUG // Qualified because the serialization asserts in a debug build.
Serializer s;
defaultAcct.add (s); // Asserts in debug build
BEAST_EXPECT(s.size() == 1);
BEAST_EXPECT(s.getHex() == "00");
SerialIter sit (s.slice ());
STAccount const deserializedDefault (sit, sfAccount);
BEAST_EXPECT(deserializedDefault.isEquivalent (defaultAcct));
#endif // NDEBUG
}
{
// Construct a deserialized default STAccount.
Serializer s;
s.addVL (nullptr, 0);
SerialIter sit (s.slice ());
STAccount const deserializedDefault (sit, sfAccount);
BEAST_EXPECT(deserializedDefault.isEquivalent (defaultAcct));
}
// Test constructor from SField.
STAccount const sfAcct {sfAccount};
BEAST_EXPECT(sfAcct.getSType() == STI_ACCOUNT);
BEAST_EXPECT(sfAcct.getText() == "");
BEAST_EXPECT(sfAcct.isDefault());
BEAST_EXPECT(sfAcct.value() == AccountID {});
BEAST_EXPECT(sfAcct.isEquivalent (defaultAcct));
{
Serializer s;
sfAcct.add (s);
BEAST_EXPECT(s.size() == 1);
BEAST_EXPECT(s.getHex() == "00");
SerialIter sit (s.slice ());
STAccount const deserializedSf (sit, sfAccount);
BEAST_EXPECT(deserializedSf.isEquivalent(sfAcct));
}
// Test constructor from SField and AccountID.
STAccount const zeroAcct {sfAccount, AccountID{}};
BEAST_EXPECT(zeroAcct.getText() == "rrrrrrrrrrrrrrrrrrrrrhoLvTp");
BEAST_EXPECT(! zeroAcct.isDefault());
BEAST_EXPECT(zeroAcct.value() == AccountID {0});
BEAST_EXPECT(! zeroAcct.isEquivalent (defaultAcct));
BEAST_EXPECT(! zeroAcct.isEquivalent (sfAcct));
{
Serializer s;
zeroAcct.add (s);
BEAST_EXPECT(s.size() == 21);
BEAST_EXPECT(s.getHex() ==
"140000000000000000000000000000000000000000");
SerialIter sit (s.slice ());
STAccount const deserializedZero (sit, sfAccount);
BEAST_EXPECT(deserializedZero.isEquivalent (zeroAcct));
}
{
// Construct from a VL that is not exactly 160 bits.
Serializer s;
const std::uint8_t bits128[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
s.addVL (bits128, sizeof (bits128));
SerialIter sit (s.slice ());
try
{
// Constructing an STAccount with a bad size should throw.
STAccount const deserializedBadSize (sit, sfAccount);
}
catch (std::runtime_error const& ex)
{
BEAST_EXPECT(ex.what() == std::string("Invalid STAccount size"));
}
}
// Interestingly, equal values but different types are equivalent!
STAccount const regKey {sfRegularKey, AccountID{}};
BEAST_EXPECT(regKey.isEquivalent (zeroAcct));
// Test assignment.
STAccount assignAcct;
BEAST_EXPECT(assignAcct.isEquivalent (defaultAcct));
BEAST_EXPECT(assignAcct.isDefault());
assignAcct = AccountID{};
BEAST_EXPECT(! assignAcct.isEquivalent (defaultAcct));
BEAST_EXPECT(assignAcct.isEquivalent (zeroAcct));
BEAST_EXPECT(! assignAcct.isDefault());
}
}
void
run() override
{
testSTAccount();
}
};
BEAST_DEFINE_TESTSUITE(STAccount,protocol,ripple);
}

View File

@@ -0,0 +1,625 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/random.h>
#include <ripple/protocol/STAmount.h>
#include <ripple/beast/unit_test.h>
namespace ripple {
class STAmount_test : public beast::unit_test::suite
{
public:
static STAmount serializeAndDeserialize (STAmount const& s)
{
Serializer ser;
s.add (ser);
SerialIter sit (ser.slice());
return STAmount(sit, sfGeneric);
}
//--------------------------------------------------------------------------
STAmount roundSelf (STAmount const& amount)
{
if (amount.native ())
return amount;
std::uint64_t mantissa = amount.mantissa ();
std::uint64_t valueDigits = mantissa % 1000000000;
if (valueDigits == 1)
{
mantissa--;
if (mantissa < STAmount::cMinValue)
return { amount.issue (), mantissa, amount.exponent (),
amount.negative () };
return { amount.issue (), mantissa, amount.exponent (),
amount.native(), amount.negative (), STAmount::unchecked {} };
}
if (valueDigits == 999999999)
{
mantissa++;
if (mantissa > STAmount::cMaxValue)
return { amount.issue (), mantissa, amount.exponent (),
amount.negative () };
return { amount.issue (), mantissa, amount.exponent (),
amount.native(), amount.negative (), STAmount::unchecked {} };
}
return amount;
}
void roundTest (int n, int d, int m)
{
// check STAmount rounding
STAmount num (noIssue(), n);
STAmount den (noIssue(), d);
STAmount mul (noIssue(), m);
STAmount quot = divide (n, d, noIssue());
STAmount res = roundSelf (multiply (quot, mul, noIssue()));
BEAST_EXPECT(! res.native ());
STAmount cmp (noIssue(), (n * m) / d);
BEAST_EXPECT(! cmp.native ());
BEAST_EXPECT(cmp.issue().currency == res.issue().currency);
if (res != cmp)
{
log <<
"(" << num.getText () << "/" << den.getText () <<
") X " << mul.getText () << " = " << res.getText () <<
" not " << cmp.getText ();
fail ("Rounding");
return;
}
}
void mulTest (int a, int b)
{
STAmount aa (noIssue(), a);
STAmount bb (noIssue(), b);
STAmount prod1 (multiply (aa, bb, noIssue()));
BEAST_EXPECT(! prod1.native ());
STAmount prod2 (noIssue(), static_cast<std::uint64_t> (a) * static_cast<std::uint64_t> (b));
if (prod1 != prod2)
{
log <<
"nn(" << aa.getFullText () << " * " << bb.getFullText () <<
") = " << prod1.getFullText () << " not " << prod2.getFullText ();
fail ("Multiplication result is not exact");
}
}
//--------------------------------------------------------------------------
void testSetValue (
std::string const& value, Issue const& issue, bool success = true)
{
try
{
STAmount const amount = amountFromString (issue, value);
BEAST_EXPECT(amount.getText () == value);
}
catch (std::exception const&)
{
BEAST_EXPECT(!success);
}
}
void testSetValue ()
{
{
testcase ("set value (native)");
Issue const xrp (xrpIssue ());
// fractional XRP (i.e. drops)
testSetValue ("1", xrp);
testSetValue ("22", xrp);
testSetValue ("333", xrp);
testSetValue ("4444", xrp);
testSetValue ("55555", xrp);
testSetValue ("666666", xrp);
// 1 XRP up to 100 billion, in powers of 10 (in drops)
testSetValue ("1000000", xrp);
testSetValue ("10000000", xrp);
testSetValue ("100000000", xrp);
testSetValue ("1000000000", xrp);
testSetValue ("10000000000", xrp);
testSetValue ("100000000000", xrp);
testSetValue ("1000000000000", xrp);
testSetValue ("10000000000000", xrp);
testSetValue ("100000000000000", xrp);
testSetValue ("1000000000000000", xrp);
testSetValue ("10000000000000000", xrp);
testSetValue ("100000000000000000", xrp);
// Invalid native values:
testSetValue ("1.1", xrp, false);
testSetValue ("100000000000000001", xrp, false);
testSetValue ("1000000000000000000", xrp, false);
}
{
testcase ("set value (iou)");
Issue const usd (Currency (0x5553440000000000), AccountID (0x4985601));
testSetValue ("1", usd);
testSetValue ("10", usd);
testSetValue ("100", usd);
testSetValue ("1000", usd);
testSetValue ("10000", usd);
testSetValue ("100000", usd);
testSetValue ("1000000", usd);
testSetValue ("10000000", usd);
testSetValue ("100000000", usd);
testSetValue ("1000000000", usd);
testSetValue ("10000000000", usd);
testSetValue ("1234567.1", usd);
testSetValue ("1234567.12", usd);
testSetValue ("1234567.123", usd);
testSetValue ("1234567.1234", usd);
testSetValue ("1234567.12345", usd);
testSetValue ("1234567.123456", usd);
testSetValue ("1234567.1234567", usd);
testSetValue ("1234567.12345678", usd);
testSetValue ("1234567.123456789", usd);
}
}
//--------------------------------------------------------------------------
void testNativeCurrency ()
{
testcase ("native currency");
STAmount zeroSt, one (1), hundred (100);
// VFALCO NOTE Why repeat "STAmount fail" so many times??
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
unexpected (serializeAndDeserialize (one) != one, "STAmount fail");
unexpected (serializeAndDeserialize (hundred) != hundred, "STAmount fail");
unexpected (!zeroSt.native (), "STAmount fail");
unexpected (!hundred.native (), "STAmount fail");
unexpected (zeroSt != zero, "STAmount fail");
unexpected (one == zero, "STAmount fail");
unexpected (hundred == zero, "STAmount fail");
unexpected ((zeroSt < zeroSt), "STAmount fail");
unexpected (! (zeroSt < one), "STAmount fail");
unexpected (! (zeroSt < hundred), "STAmount fail");
unexpected ((one < zeroSt), "STAmount fail");
unexpected ((one < one), "STAmount fail");
unexpected (! (one < hundred), "STAmount fail");
unexpected ((hundred < zeroSt), "STAmount fail");
unexpected ((hundred < one), "STAmount fail");
unexpected ((hundred < hundred), "STAmount fail");
unexpected ((zeroSt > zeroSt), "STAmount fail");
unexpected ((zeroSt > one), "STAmount fail");
unexpected ((zeroSt > hundred), "STAmount fail");
unexpected (! (one > zeroSt), "STAmount fail");
unexpected ((one > one), "STAmount fail");
unexpected ((one > hundred), "STAmount fail");
unexpected (! (hundred > zeroSt), "STAmount fail");
unexpected (! (hundred > one), "STAmount fail");
unexpected ((hundred > hundred), "STAmount fail");
unexpected (! (zeroSt <= zeroSt), "STAmount fail");
unexpected (! (zeroSt <= one), "STAmount fail");
unexpected (! (zeroSt <= hundred), "STAmount fail");
unexpected ((one <= zeroSt), "STAmount fail");
unexpected (! (one <= one), "STAmount fail");
unexpected (! (one <= hundred), "STAmount fail");
unexpected ((hundred <= zeroSt), "STAmount fail");
unexpected ((hundred <= one), "STAmount fail");
unexpected (! (hundred <= hundred), "STAmount fail");
unexpected (! (zeroSt >= zeroSt), "STAmount fail");
unexpected ((zeroSt >= one), "STAmount fail");
unexpected ((zeroSt >= hundred), "STAmount fail");
unexpected (! (one >= zeroSt), "STAmount fail");
unexpected (! (one >= one), "STAmount fail");
unexpected ((one >= hundred), "STAmount fail");
unexpected (! (hundred >= zeroSt), "STAmount fail");
unexpected (! (hundred >= one), "STAmount fail");
unexpected (! (hundred >= hundred), "STAmount fail");
unexpected (! (zeroSt == zeroSt), "STAmount fail");
unexpected ((zeroSt == one), "STAmount fail");
unexpected ((zeroSt == hundred), "STAmount fail");
unexpected ((one == zeroSt), "STAmount fail");
unexpected (! (one == one), "STAmount fail");
unexpected ((one == hundred), "STAmount fail");
unexpected ((hundred == zeroSt), "STAmount fail");
unexpected ((hundred == one), "STAmount fail");
unexpected (! (hundred == hundred), "STAmount fail");
unexpected ((zeroSt != zeroSt), "STAmount fail");
unexpected (! (zeroSt != one), "STAmount fail");
unexpected (! (zeroSt != hundred), "STAmount fail");
unexpected (! (one != zeroSt), "STAmount fail");
unexpected ((one != one), "STAmount fail");
unexpected (! (one != hundred), "STAmount fail");
unexpected (! (hundred != zeroSt), "STAmount fail");
unexpected (! (hundred != one), "STAmount fail");
unexpected ((hundred != hundred), "STAmount fail");
unexpected (STAmount ().getText () != "0", "STAmount fail");
unexpected (STAmount (31).getText () != "31", "STAmount fail");
unexpected (STAmount (310).getText () != "310", "STAmount fail");
unexpected (to_string (Currency ()) != "XRP", "cHC(XRP)");
Currency c;
unexpected (!to_currency (c, "USD"), "create USD currency");
unexpected (to_string (c) != "USD", "check USD currency");
const std::string cur = "015841551A748AD2C1F76FF6ECB0CCCD00000000";
unexpected (!to_currency (c, cur), "create custom currency");
unexpected (to_string (c) != cur, "check custom currency");
unexpected (c != Currency (
from_hex_text<Currency>(cur)), "check custom currency");
}
//--------------------------------------------------------------------------
void testCustomCurrency ()
{
testcase ("custom currency");
STAmount zeroSt (noIssue()), one (noIssue(), 1), hundred (noIssue(), 100);
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
unexpected (serializeAndDeserialize (one) != one, "STAmount fail");
unexpected (serializeAndDeserialize (hundred) != hundred, "STAmount fail");
unexpected (zeroSt.native (), "STAmount fail");
unexpected (hundred.native (), "STAmount fail");
unexpected (zeroSt != zero, "STAmount fail");
unexpected (one == zero, "STAmount fail");
unexpected (hundred == zero, "STAmount fail");
unexpected ((zeroSt < zeroSt), "STAmount fail");
unexpected (! (zeroSt < one), "STAmount fail");
unexpected (! (zeroSt < hundred), "STAmount fail");
unexpected ((one < zeroSt), "STAmount fail");
unexpected ((one < one), "STAmount fail");
unexpected (! (one < hundred), "STAmount fail");
unexpected ((hundred < zeroSt), "STAmount fail");
unexpected ((hundred < one), "STAmount fail");
unexpected ((hundred < hundred), "STAmount fail");
unexpected ((zeroSt > zeroSt), "STAmount fail");
unexpected ((zeroSt > one), "STAmount fail");
unexpected ((zeroSt > hundred), "STAmount fail");
unexpected (! (one > zeroSt), "STAmount fail");
unexpected ((one > one), "STAmount fail");
unexpected ((one > hundred), "STAmount fail");
unexpected (! (hundred > zeroSt), "STAmount fail");
unexpected (! (hundred > one), "STAmount fail");
unexpected ((hundred > hundred), "STAmount fail");
unexpected (! (zeroSt <= zeroSt), "STAmount fail");
unexpected (! (zeroSt <= one), "STAmount fail");
unexpected (! (zeroSt <= hundred), "STAmount fail");
unexpected ((one <= zeroSt), "STAmount fail");
unexpected (! (one <= one), "STAmount fail");
unexpected (! (one <= hundred), "STAmount fail");
unexpected ((hundred <= zeroSt), "STAmount fail");
unexpected ((hundred <= one), "STAmount fail");
unexpected (! (hundred <= hundred), "STAmount fail");
unexpected (! (zeroSt >= zeroSt), "STAmount fail");
unexpected ((zeroSt >= one), "STAmount fail");
unexpected ((zeroSt >= hundred), "STAmount fail");
unexpected (! (one >= zeroSt), "STAmount fail");
unexpected (! (one >= one), "STAmount fail");
unexpected ((one >= hundred), "STAmount fail");
unexpected (! (hundred >= zeroSt), "STAmount fail");
unexpected (! (hundred >= one), "STAmount fail");
unexpected (! (hundred >= hundred), "STAmount fail");
unexpected (! (zeroSt == zeroSt), "STAmount fail");
unexpected ((zeroSt == one), "STAmount fail");
unexpected ((zeroSt == hundred), "STAmount fail");
unexpected ((one == zeroSt), "STAmount fail");
unexpected (! (one == one), "STAmount fail");
unexpected ((one == hundred), "STAmount fail");
unexpected ((hundred == zeroSt), "STAmount fail");
unexpected ((hundred == one), "STAmount fail");
unexpected (! (hundred == hundred), "STAmount fail");
unexpected ((zeroSt != zeroSt), "STAmount fail");
unexpected (! (zeroSt != one), "STAmount fail");
unexpected (! (zeroSt != hundred), "STAmount fail");
unexpected (! (one != zeroSt), "STAmount fail");
unexpected ((one != one), "STAmount fail");
unexpected (! (one != hundred), "STAmount fail");
unexpected (! (hundred != zeroSt), "STAmount fail");
unexpected (! (hundred != one), "STAmount fail");
unexpected ((hundred != hundred), "STAmount fail");
unexpected (STAmount (noIssue()).getText () != "0", "STAmount fail");
unexpected (STAmount (noIssue(), 31).getText () != "31", "STAmount fail");
unexpected (STAmount (noIssue(), 31, 1).getText () != "310", "STAmount fail");
unexpected (STAmount (noIssue(), 31, -1).getText () != "3.1", "STAmount fail");
unexpected (STAmount (noIssue(), 31, -2).getText () != "0.31", "STAmount fail");
unexpected (multiply (STAmount (noIssue(), 20), STAmount (3), noIssue()).getText () != "60",
"STAmount multiply fail 1");
unexpected (multiply (STAmount (noIssue(), 20), STAmount (3), xrpIssue ()).getText () != "60",
"STAmount multiply fail 2");
unexpected (multiply (STAmount (20), STAmount (3), noIssue()).getText () != "60",
"STAmount multiply fail 3");
unexpected (multiply (STAmount (20), STAmount (3), xrpIssue ()).getText () != "60",
"STAmount multiply fail 4");
if (divide (STAmount (noIssue(), 60), STAmount (3), noIssue()).getText () != "20")
{
log << "60/3 = " <<
divide (STAmount (noIssue(), 60),
STAmount (3), noIssue()).getText ();
fail ("STAmount divide fail");
}
else
{
pass ();
}
unexpected (divide (STAmount (noIssue(), 60), STAmount (3), xrpIssue ()).getText () != "20",
"STAmount divide fail");
unexpected (divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), noIssue()).getText () != "20",
"STAmount divide fail");
unexpected (divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), xrpIssue ()).getText () != "20",
"STAmount divide fail");
STAmount a1 (noIssue(), 60), a2 (noIssue(), 10, -1);
unexpected (divide (a2, a1, noIssue()) != amountFromQuality (getRate (a1, a2)),
"STAmount setRate(getRate) fail");
unexpected (divide (a1, a2, noIssue()) != amountFromQuality (getRate (a2, a1)),
"STAmount setRate(getRate) fail");
}
//--------------------------------------------------------------------------
void testArithmetic ()
{
testcase ("arithmetic");
// Test currency multiplication and division operations such as
// convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded
unexpected (getRate (STAmount (1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 1");
unexpected (getRate (STAmount (10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 2");
unexpected (getRate (STAmount (noIssue(), 1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 3");
unexpected (getRate (STAmount (noIssue(), 10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 4");
unexpected (getRate (STAmount (noIssue(), 1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 5");
unexpected (getRate (STAmount (noIssue(), 10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 6");
unexpected (getRate (STAmount (1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 7");
unexpected (getRate (STAmount (10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 8");
roundTest (1, 3, 3);
roundTest (2, 3, 9);
roundTest (1, 7, 21);
roundTest (1, 2, 4);
roundTest (3, 9, 18);
roundTest (7, 11, 44);
for (int i = 0; i <= 100000; ++i)
{
mulTest (
rand_int(10000000),
rand_int(10000000));
}
}
//--------------------------------------------------------------------------
void testUnderflow ()
{
testcase ("underflow");
STAmount bigNative (STAmount::cMaxNative / 2);
STAmount bigValue (noIssue(),
(STAmount::cMinValue + STAmount::cMaxValue) / 2,
STAmount::cMaxOffset - 1);
STAmount smallValue (noIssue(),
(STAmount::cMinValue + STAmount::cMaxValue) / 2,
STAmount::cMinOffset + 1);
STAmount zeroSt (noIssue(), 0);
STAmount smallXsmall = multiply (smallValue, smallValue, noIssue());
BEAST_EXPECT(smallXsmall == zero);
STAmount bigDsmall = divide (smallValue, bigValue, noIssue());
BEAST_EXPECT(bigDsmall == zero);
BEAST_EXPECT(bigDsmall == zero);
bigDsmall = divide (smallValue, bigValue, xrpIssue ());
BEAST_EXPECT(bigDsmall == zero);
bigDsmall = divide (smallValue, bigNative, xrpIssue ());
BEAST_EXPECT(bigDsmall == zero);
// very bad offer
std::uint64_t r = getRate (smallValue, bigValue);
BEAST_EXPECT(r == 0);
// very good offer
r = getRate (bigValue, smallValue);
BEAST_EXPECT(r == 0);
}
//--------------------------------------------------------------------------
void testRounding ()
{
// VFALCO TODO There are no actual tests here, just printed output?
// Change this to actually do something.
#if 0
beginTestCase ("rounding ");
std::uint64_t value = 25000000000000000ull;
int offset = -14;
canonicalizeRound (false, value, offset, true);
STAmount one (noIssue(), 1);
STAmount two (noIssue(), 2);
STAmount three (noIssue(), 3);
STAmount oneThird1 = divRound (one, three, noIssue(), false);
STAmount oneThird2 = divide (one, three, noIssue());
STAmount oneThird3 = divRound (one, three, noIssue(), true);
log << oneThird1;
log << oneThird2;
log << oneThird3;
STAmount twoThird1 = divRound (two, three, noIssue(), false);
STAmount twoThird2 = divide (two, three, noIssue());
STAmount twoThird3 = divRound (two, three, noIssue(), true);
log << twoThird1;
log << twoThird2;
log << twoThird3;
STAmount oneA = mulRound (oneThird1, three, noIssue(), false);
STAmount oneB = multiply (oneThird2, three, noIssue());
STAmount oneC = mulRound (oneThird3, three, noIssue(), true);
log << oneA;
log << oneB;
log << oneC;
STAmount fourThirdsB = twoThird2 + twoThird2;
log << fourThirdsA;
log << fourThirdsB;
log << fourThirdsC;
STAmount dripTest1 = mulRound (twoThird2, two, xrpIssue (), false);
STAmount dripTest2 = multiply (twoThird2, two, xrpIssue ());
STAmount dripTest3 = mulRound (twoThird2, two, xrpIssue (), true);
log << dripTest1;
log << dripTest2;
log << dripTest3;
#endif
}
void
testConvertXRP ()
{
testcase ("STAmount to XRPAmount conversions");
Issue const usd { Currency (0x5553440000000000), AccountID (0x4985601) };
Issue const xrp { xrpIssue () };
for (std::uint64_t drops = 100000000000000000; drops != 1; drops = drops / 10)
{
auto const t = amountFromString (xrp, std::to_string (drops));
auto const s = t.xrp ();
BEAST_EXPECT(s.drops() == drops);
BEAST_EXPECT(t == STAmount (XRPAmount (drops)));
BEAST_EXPECT(s == XRPAmount (drops));
}
try
{
auto const t = amountFromString (usd, "136500");
fail (to_string (t.xrp ()));
}
catch (std::logic_error const&)
{
pass ();
}
catch (std::exception const&)
{
fail ("wrong exception");
}
}
void
testConvertIOU ()
{
testcase ("STAmount to IOUAmount conversions");
Issue const usd { Currency (0x5553440000000000), AccountID (0x4985601) };
Issue const xrp { xrpIssue () };
for (std::uint64_t dollars = 10000000000; dollars != 1; dollars = dollars / 10)
{
auto const t = amountFromString (usd, std::to_string (dollars));
auto const s = t.iou ();
BEAST_EXPECT(t == STAmount (s, usd));
BEAST_EXPECT(s.mantissa () == t.mantissa ());
BEAST_EXPECT(s.exponent () == t.exponent ());
}
try
{
auto const t = amountFromString (xrp, "136500");
fail (to_string (t.iou ()));
}
catch (std::logic_error const&)
{
pass ();
}
catch (std::exception const&)
{
fail ("wrong exception");
}
}
//--------------------------------------------------------------------------
void run ()
{
testSetValue ();
testNativeCurrency ();
testCustomCurrency ();
testArithmetic ();
testUnderflow ();
testRounding ();
testConvertXRP ();
testConvertIOU ();
}
};
BEAST_DEFINE_TESTSUITE(STAmount,ripple_data,ripple);
} // ripple

View File

@@ -0,0 +1,513 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/st.h>
#include <ripple/json/json_reader.h>
#include <ripple/json/to_string.h>
#include <ripple/beast/unit_test.h>
#include <memory>
#include <type_traits>
namespace ripple {
class STObject_test : public beast::unit_test::suite
{
public:
bool parseJSONString (std::string const& json, Json::Value& to)
{
Json::Reader reader;
return reader.parse(json, to) &&
bool (to) &&
to.isObject();
}
void testParseJSONArrayWithInvalidChildrenObjects ()
{
testcase ("parse json array invalid children");
try
{
/*
STArray/STObject constructs don't really map perfectly to json
arrays/objects.
STObject is an associative container, mapping fields to value, but
an STObject may also have a Field as its name, stored outside the
associative structure. The name is important, so to maintain
fidelity, it will take TWO json objects to represent them.
*/
std::string faulty ("{\"Template\":[{"
"\"ModifiedNode\":{\"Sequence\":1}, "
"\"DeletedNode\":{\"Sequence\":1}"
"}]}");
std::unique_ptr<STObject> so;
Json::Value faultyJson;
bool parsedOK (parseJSONString(faulty, faultyJson));
unexpected(!parsedOK, "failed to parse");
STParsedJSONObject parsed ("test", faultyJson);
BEAST_EXPECT(! parsed.object);
}
catch(std::runtime_error& e)
{
std::string what(e.what());
unexpected (what.find("First level children of `Template`") != 0);
}
}
void testParseJSONArray ()
{
testcase ("parse json array");
std::string const json (
"{\"Template\":[{\"ModifiedNode\":{\"Sequence\":1}}]}");
Json::Value jsonObject;
bool parsedOK (parseJSONString(json, jsonObject));
if (parsedOK)
{
STParsedJSONObject parsed ("test", jsonObject);
std::string const& serialized (
to_string (parsed.object->getJson(0)));
BEAST_EXPECT(serialized == json);
}
else
{
fail ("Couldn't parse json: " + json);
}
}
void testSerialization ()
{
testcase ("serialization");
unexpected (sfGeneric.isUseful (), "sfGeneric must not be useful");
SField const& sfTestVL = SField::getField (STI_VL, 255);
SField const& sfTestH256 = SField::getField (STI_HASH256, 255);
SField const& sfTestU32 = SField::getField (STI_UINT32, 255);
SField const& sfTestV256 = SField::getField(STI_VECTOR256, 255);
SField const& sfTestObject = SField::getField (STI_OBJECT, 255);
SOTemplate elements;
elements.push_back (SOElement (sfFlags, SOE_REQUIRED));
elements.push_back (SOElement (sfTestVL, SOE_REQUIRED));
elements.push_back (SOElement (sfTestH256, SOE_OPTIONAL));
elements.push_back (SOElement (sfTestU32, SOE_REQUIRED));
elements.push_back (SOElement (sfTestV256, SOE_OPTIONAL));
STObject object1 (elements, sfTestObject);
STObject object2 (object1);
unexpected (object1.getSerializer () != object2.getSerializer (),
"STObject error 1");
unexpected (object1.isFieldPresent (sfTestH256) ||
!object1.isFieldPresent (sfTestVL), "STObject error");
object1.makeFieldPresent (sfTestH256);
unexpected (!object1.isFieldPresent (sfTestH256), "STObject Error 2");
unexpected (object1.getFieldH256 (sfTestH256) != uint256 (),
"STObject error 3");
if (object1.getSerializer () == object2.getSerializer ())
{
log <<
"O1: " << object1.getJson (0) << '\n' <<
"O2: " << object2.getJson (0) << std::endl;
fail ("STObject error 4");
}
else
{
pass ();
}
object1.makeFieldAbsent (sfTestH256);
unexpected (object1.isFieldPresent (sfTestH256), "STObject error 5");
unexpected (object1.getFlags () != 0, "STObject error 6");
unexpected (object1.getSerializer () != object2.getSerializer (),
"STObject error 7");
STObject copy (object1);
unexpected (object1.isFieldPresent (sfTestH256), "STObject error 8");
unexpected (copy.isFieldPresent (sfTestH256), "STObject error 9");
unexpected (object1.getSerializer () != copy.getSerializer (),
"STObject error 10");
copy.setFieldU32 (sfTestU32, 1);
unexpected (object1.getSerializer () == copy.getSerializer (),
"STObject error 11");
for (int i = 0; i < 1000; i++)
{
Blob j (i, 2);
object1.setFieldVL (sfTestVL, j);
Serializer s;
object1.add (s);
SerialIter it (s.slice());
STObject object3 (elements, it, sfTestObject);
unexpected (object1.getFieldVL (sfTestVL) != j, "STObject error");
unexpected (object3.getFieldVL (sfTestVL) != j, "STObject error");
}
{
std::vector<uint256> uints;
uints.reserve(5);
for (int i = 0; i < uints.capacity(); ++i)
{
uints.emplace_back(i);
}
object1.setFieldV256(sfTestV256, STVector256(uints));
Serializer s;
object1.add(s);
SerialIter it(s.slice());
STObject object3(elements, it, sfTestObject);
auto const& uints1 = object1.getFieldV256(sfTestV256);
auto const& uints3 = object3.getFieldV256(sfTestV256);
BEAST_EXPECT(uints1 == uints3);
}
}
// Exercise field accessors
void
testFields()
{
testcase ("fields");
auto const& sf1 = sfSequence;
auto const& sf2 = sfExpiration;
auto const& sf3 = sfQualityIn;
auto const& sf4 = sfSignature;
auto const& sf5 = sfPublicKey;
// read free object
{
auto const st = [&]()
{
STObject st(sfGeneric);
st.setFieldU32(sf1, 1);
st.setFieldU32(sf2, 2);
return st;
}();
BEAST_EXPECT(st[sf1] == 1);
BEAST_EXPECT(st[sf2] == 2);
except<missing_field_error>([&]()
{ st[sf3]; });
BEAST_EXPECT(*st[~sf1] == 1);
BEAST_EXPECT(*st[~sf2] == 2);
BEAST_EXPECT(st[~sf3] == boost::none);
BEAST_EXPECT(!! st[~sf1]);
BEAST_EXPECT(!! st[~sf2]);
BEAST_EXPECT(! st[~sf3]);
BEAST_EXPECT(st[sf1] != st[sf2]);
BEAST_EXPECT(st[~sf1] != st[~sf2]);
}
// read templated object
auto const sot = [&]()
{
SOTemplate sot;
sot.push_back(SOElement(sf1, SOE_REQUIRED));
sot.push_back(SOElement(sf2, SOE_OPTIONAL));
sot.push_back(SOElement(sf3, SOE_DEFAULT));
sot.push_back(SOElement(sf4, SOE_OPTIONAL));
sot.push_back(SOElement(sf5, SOE_DEFAULT));
return sot;
}();
{
auto const st = [&]()
{
STObject st(sot, sfGeneric);
st.setFieldU32(sf1, 1);
st.setFieldU32(sf2, 2);
return st;
}();
BEAST_EXPECT(st[sf1] == 1);
BEAST_EXPECT(st[sf2] == 2);
BEAST_EXPECT(st[sf3] == 0);
BEAST_EXPECT(*st[~sf1] == 1);
BEAST_EXPECT(*st[~sf2] == 2);
BEAST_EXPECT(*st[~sf3] == 0);
BEAST_EXPECT(!! st[~sf1]);
BEAST_EXPECT(!! st[~sf2]);
BEAST_EXPECT(!! st[~sf3]);
}
// write free object
{
STObject st(sfGeneric);
unexcept([&]() { st[sf1]; });
except([&](){ return st[sf1] == 0; });
BEAST_EXPECT(st[~sf1] == boost::none);
BEAST_EXPECT(st[~sf1] == boost::optional<std::uint32_t>{});
BEAST_EXPECT(st[~sf1] != boost::optional<std::uint32_t>(1));
BEAST_EXPECT(! st[~sf1]);
st[sf1] = 2;
BEAST_EXPECT(st[sf1] == 2);
BEAST_EXPECT(st[~sf1] != boost::none);
BEAST_EXPECT(st[~sf1] == boost::optional<std::uint32_t>(2));
BEAST_EXPECT(!! st[~sf1]);
st[sf1] = 1;
BEAST_EXPECT(st[sf1] == 1);
BEAST_EXPECT(!! st[sf1]);
BEAST_EXPECT(!! st[~sf1]);
st[sf1] = 0;
BEAST_EXPECT(! st[sf1]);
BEAST_EXPECT(!! st[~sf1]);
st[~sf1] = boost::none;
BEAST_EXPECT(! st[~sf1]);
BEAST_EXPECT(st[~sf1] == boost::none);
BEAST_EXPECT(st[~sf1] == boost::optional<std::uint32_t>{});
st[~sf1] = boost::none;
BEAST_EXPECT(! st[~sf1]);
except([&]() { return st[sf1] == 0; });
except([&]() { return *st[~sf1]; });
st[sf1] = 1;
BEAST_EXPECT(st[sf1] == 1);
BEAST_EXPECT(!! st[sf1]);
BEAST_EXPECT(!! st[~sf1]);
st[sf1] = 3;
st[sf2] = st[sf1];
BEAST_EXPECT(st[sf1] == 3);
BEAST_EXPECT(st[sf2] == 3);
BEAST_EXPECT(st[sf2] == st[sf1]);
st[sf1] = 4;
st[sf2] = st[sf1];
BEAST_EXPECT(st[sf1] == 4);
BEAST_EXPECT(st[sf2] == 4);
BEAST_EXPECT(st[sf2] == st[sf1]);
}
// Write templated object
{
STObject st(sot, sfGeneric);
BEAST_EXPECT(!! st[~sf1]);
BEAST_EXPECT(st[~sf1] != boost::none);
BEAST_EXPECT(st[sf1] == 0);
BEAST_EXPECT(*st[~sf1] == 0);
BEAST_EXPECT(! st[~sf2]);
BEAST_EXPECT(st[~sf2] == boost::none);
except([&]() { return st[sf2] == 0; });
BEAST_EXPECT(!! st[~sf3]);
BEAST_EXPECT(st[~sf3] != boost::none);
BEAST_EXPECT(st[sf3] == 0);
except([&]() { st[~sf1] = boost::none; });
st[sf1] = 1;
BEAST_EXPECT(st[sf1] == 1);
BEAST_EXPECT(*st[~sf1] == 1);
BEAST_EXPECT(!! st[~sf1]);
st[sf1] = 0;
BEAST_EXPECT(st[sf1] == 0);
BEAST_EXPECT(*st[~sf1] == 0);
BEAST_EXPECT(!! st[~sf1]);
st[sf2] = 2;
BEAST_EXPECT(st[sf2] == 2);
BEAST_EXPECT(*st[~sf2] == 2);
BEAST_EXPECT(!! st[~sf2]);
st[~sf2] = boost::none;
except([&]() { return *st[~sf2]; });
BEAST_EXPECT(! st[~sf2]);
st[sf3] = 3;
BEAST_EXPECT(st[sf3] == 3);
BEAST_EXPECT(*st[~sf3] == 3);
BEAST_EXPECT(!! st[~sf3]);
st[sf3] = 2;
BEAST_EXPECT(st[sf3] == 2);
BEAST_EXPECT(*st[~sf3] == 2);
BEAST_EXPECT(!! st[~sf3]);
st[sf3] = 0;
BEAST_EXPECT(st[sf3] == 0);
BEAST_EXPECT(*st[~sf3] == 0);
BEAST_EXPECT(!! st[~sf3]);
except([&]() { st[~sf3] = boost::none; });
BEAST_EXPECT(st[sf3] == 0);
BEAST_EXPECT(*st[~sf3] == 0);
BEAST_EXPECT(!! st[~sf3]);
}
// coercion operator to boost::optional
{
STObject st(sfGeneric);
auto const v = ~st[~sf1];
static_assert(std::is_same<
std::decay_t<decltype(v)>,
boost::optional<std::uint32_t>>::value, "");
}
// UDT scalar fields
{
STObject st(sfGeneric);
st[sfAmount] = STAmount{};
st[sfAccount] = AccountID{};
st[sfDigest] = uint256{};
[&](STAmount){}(st[sfAmount]);
[&](AccountID){}(st[sfAccount]);
[&](uint256){}(st[sfDigest]);
}
// STBlob and slice
{
{
STObject st(sfGeneric);
Buffer b(1);
BEAST_EXPECT(! b.empty());
st[sf4] = std::move(b);
BEAST_EXPECT(b.empty());
BEAST_EXPECT(Slice(st[sf4]).size() == 1);
st[~sf4] = boost::none;
BEAST_EXPECT(! ~st[~sf4]);
b = Buffer{2};
st[sf4] = Slice(b);
BEAST_EXPECT(b.size() == 2);
BEAST_EXPECT(Slice(st[sf4]).size() == 2);
st[sf5] = st[sf4];
BEAST_EXPECT(Slice(st[sf4]).size() == 2);
BEAST_EXPECT(Slice(st[sf5]).size() == 2);
}
{
STObject st(sot, sfGeneric);
BEAST_EXPECT(st[sf5] == Slice{});
BEAST_EXPECT(!! st[~sf5]);
BEAST_EXPECT(!! ~st[~sf5]);
Buffer b(1);
st[sf5] = std::move(b);
BEAST_EXPECT(b.empty());
BEAST_EXPECT(Slice(st[sf5]).size() == 1);
st[~sf4] = boost::none;
BEAST_EXPECT(! ~st[~sf4]);
}
}
// UDT blobs
{
STObject st(sfGeneric);
BEAST_EXPECT(! st[~sf5]);
auto const kp = generateKeyPair(
KeyType::secp256k1,
generateSeed("masterpassphrase"));
st[sf5] = kp.first;
BEAST_EXPECT(st[sf5] != PublicKey{});
st[~sf5] = boost::none;
#if 0
pk = st[sf5];
BEAST_EXPECT(pk.size() == 0);
#endif
}
// By reference fields
{
auto const& sf = sfIndexes;
STObject st(sfGeneric);
std::vector<uint256> v;
v.emplace_back(1);
v.emplace_back(2);
st[sf] = v;
st[sf] = std::move(v);
auto const& cst = st;
BEAST_EXPECT(cst[sf].size() == 2);
BEAST_EXPECT(cst[~sf]->size() == 2);
BEAST_EXPECT(cst[sf][0] == 1);
BEAST_EXPECT(cst[sf][1] == 2);
static_assert(std::is_same<decltype(cst[sfIndexes]),
std::vector<uint256> const&>::value, "");
}
// Default by reference field
{
auto const& sf1 = sfIndexes;
auto const& sf2 = sfHashes;
auto const& sf3 = sfAmendments;
auto const sot = [&]()
{
SOTemplate sot;
sot.push_back(SOElement(sf1, SOE_REQUIRED));
sot.push_back(SOElement(sf2, SOE_OPTIONAL));
sot.push_back(SOElement(sf3, SOE_DEFAULT));
return sot;
}();
STObject st(sot, sfGeneric);
auto const& cst(st);
BEAST_EXPECT(cst[sf1].size() == 0);
BEAST_EXPECT(! cst[~sf2]);
BEAST_EXPECT(cst[sf3].size() == 0);
std::vector<uint256> v;
v.emplace_back(1);
st[sf1] = v;
BEAST_EXPECT(cst[sf1].size() == 1);
BEAST_EXPECT(cst[sf1][0] == uint256{1});
st[sf2] = v;
BEAST_EXPECT(cst[sf2].size() == 1);
BEAST_EXPECT(cst[sf2][0] == uint256{1});
st[~sf2] = boost::none;
BEAST_EXPECT(! st[~sf2]);
st[sf3] = v;
BEAST_EXPECT(cst[sf3].size() == 1);
BEAST_EXPECT(cst[sf3][0] == uint256{1});
st[sf3] = std::vector<uint256>{};
BEAST_EXPECT(cst[sf3].size() == 0);
}
}
void
run()
{
testFields();
testSerialization();
testParseJSONArray();
testParseJSONArrayWithInvalidChildrenObjects();
}
};
BEAST_DEFINE_TESTSUITE(STObject,protocol,ripple);
} // ripple

View File

@@ -0,0 +1,196 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/protocol/Sign.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/STParsedJSON.h>
#include <ripple/protocol/types.h>
#include <ripple/json/to_string.h>
#include <ripple/beast/unit_test.h>
namespace ripple {
class STTx_test : public beast::unit_test::suite
{
public:
void run()
{
testcase ("secp256k1 signatures");
testSTTx (KeyType::secp256k1);
testcase ("ed25519 signatures");
testSTTx (KeyType::ed25519);
}
void testSTTx(KeyType keyType)
{
auto const keypair = randomKeyPair (keyType);
STTx j (ttACCOUNT_SET,
[&keypair](auto& obj)
{
obj.setAccountID (sfAccount, calcAccountID(keypair.first));
obj.setFieldVL (sfMessageKey, keypair.first.slice());
obj.setFieldVL (sfSigningPubKey, keypair.first.slice());
});
j.sign (keypair.first, keypair.second);
unexpected (!j.checkSign (true).first, "Transaction fails signature test");
Serializer rawTxn;
j.add (rawTxn);
SerialIter sit (rawTxn.slice());
STTx copy (sit);
if (copy != j)
{
log <<
"j=" << j.getJson (0) << '\n' <<
"copy=" << copy.getJson (0) << std::endl;
fail ("Transaction fails serialize/deserialize test");
}
else
{
pass ();
}
STParsedJSONObject parsed ("test", j.getJson (0));
if (!parsed.object)
fail ("Unable to build object from json");
if (STObject (j) != parsed.object)
{
log <<
"ORIG: " << j.getJson (0) << '\n' <<
"BUILT " << parsed.object->getJson (0) << std::endl;
fail ("Built a different transaction");
}
else
{
pass ();
}
}
};
class InnerObjectFormatsSerializer_test : public beast::unit_test::suite
{
public:
void run()
{
auto const kp1 = randomKeyPair (KeyType::secp256k1);
auto const id1 = calcAccountID(kp1.first);
STTx txn (ttACCOUNT_SET,
[&id1,&kp1](auto& obj)
{
obj.setAccountID (sfAccount, id1);
obj.setFieldVL (sfMessageKey, kp1.first.slice());
// Make empty signature for multi-signing
obj.setFieldVL (sfSigningPubKey, Slice{});
});
// Create fields for a SigningAccount
auto const kp2 = randomKeyPair (KeyType::secp256k1);
auto const id2 = calcAccountID(kp2.first);
// Get the stream of the transaction for use in multi-signing.
Serializer s = buildMultiSigningData (txn, id2);
auto const saMultiSignature = sign (kp2.first, kp2.second, s.slice());
// The InnerObjectFormats say a Signer is supposed to look
// like this:
// Signer {
// Account: "...",
// TxnSignature: "...",
// PublicKey: "...""
// }
// Make one well formed Signer and several mal-formed ones. See
// whether the serializer lets the good one through and catches
// the bad ones.
// This lambda contains the bulk of the test code.
auto testMalformedSigningAccount =
[this, &txn, &id1]
(STObject const& signer, bool expectPass)
{
// Create SigningAccounts array.
STArray signers (sfSigners, 1);
signers.push_back (signer);
// Insert signers into transaction.
STTx tempTxn (txn);
tempTxn.setFieldArray (sfSigners, signers);
Serializer rawTxn;
tempTxn.add (rawTxn);
SerialIter sit (rawTxn.slice());
bool serialized = false;
try
{
STTx copy (sit);
serialized = true;
}
catch (std::exception const&)
{
; // If it threw then serialization failed.
}
BEAST_EXPECT(serialized == expectPass);
};
{
// Test case 1. Make a valid Signer object.
STObject soTest1 (sfSigner);
soTest1.setAccountID (sfAccount, id2);
soTest1.setFieldVL (sfSigningPubKey, kp1.first.slice());
soTest1.setFieldVL (sfTxnSignature, saMultiSignature);
testMalformedSigningAccount (soTest1, true);
}
{
// Test case 2. Omit sfSigningPubKey from SigningAccount.
STObject soTest2 (sfSigner);
soTest2.setAccountID (sfAccount, id2);
soTest2.setFieldVL (sfTxnSignature, saMultiSignature);
testMalformedSigningAccount (soTest2, false);
}
{
// Test case 3. Extra sfAmount in SigningAccount.
STObject soTest3 (sfSigner);
soTest3.setAccountID (sfAccount, id2);
soTest3.setFieldVL (sfSigningPubKey, kp1.first.slice());
soTest3.setFieldVL (sfTxnSignature, saMultiSignature);
soTest3.setFieldAmount (sfAmount, STAmount (10000));
testMalformedSigningAccount (soTest3, false);
}
{
// Test case 4. Right number of fields, but wrong ones.
STObject soTest4 (sfSigner);
soTest4.setFieldVL (sfSigningPubKey, kp1.first.slice());
soTest4.setFieldVL (sfTxnSignature, saMultiSignature);
soTest4.setFieldAmount (sfAmount, STAmount (10000));
testMalformedSigningAccount (soTest4, false);
}
}
};
BEAST_DEFINE_TESTSUITE(STTx,ripple_app,ripple);
BEAST_DEFINE_TESTSUITE(InnerObjectFormatsSerializer,ripple_app,ripple);
} // ripple

View File

@@ -0,0 +1,293 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/crypto/csprng.h>
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/Seed.h>
#include <ripple/beast/unit_test.h>
#include <ripple/beast/utility/rngfill.h>
#include <algorithm>
#include <string>
#include <vector>
namespace ripple {
class SecretKey_test : public beast::unit_test::suite
{
static
bool equal(SecretKey const& lhs, SecretKey const& rhs)
{
return std::equal (
lhs.data(), lhs.data() + lhs.size(),
rhs.data(), rhs.data() + rhs.size());
}
public:
void testDigestSigning()
{
testcase ("secp256k1 digest");
for (std::size_t i = 0; i < 32; i++)
{
auto const keypair = randomKeyPair (KeyType::secp256k1);
BEAST_EXPECT(keypair.first == derivePublicKey (KeyType::secp256k1, keypair.second));
BEAST_EXPECT(*publicKeyType (keypair.first) == KeyType::secp256k1);
for (std::size_t j = 0; j < 32; j++)
{
uint256 digest;
beast::rngfill (
digest.data(),
digest.size(),
crypto_prng());
auto sig = signDigest (
keypair.first, keypair.second, digest);
BEAST_EXPECT(sig.size() != 0);
BEAST_EXPECT(verifyDigest (keypair.first,
digest, sig, true));
// Wrong digest:
BEAST_EXPECT(!verifyDigest (keypair.first,
~digest, sig, true));
// Slightly change the signature:
if (auto ptr = sig.data())
ptr[j % sig.size()]++;
// Wrong signature:
BEAST_EXPECT(!verifyDigest (keypair.first,
digest, sig, true));
// Wrong digest and signature:
BEAST_EXPECT(!verifyDigest (keypair.first,
~digest, sig, true));
}
}
}
void testSigning (KeyType type)
{
for (std::size_t i = 0; i < 32; i++)
{
auto const keypair = randomKeyPair (type);
BEAST_EXPECT(keypair.first == derivePublicKey (type, keypair.second));
BEAST_EXPECT(*publicKeyType (keypair.first) == type);
for (std::size_t j = 0; j < 32; j++)
{
std::vector<std::uint8_t> data (64 + (8 * i) + j);
beast::rngfill (
data.data(),
data.size(),
crypto_prng());
auto sig = sign (
keypair.first, keypair.second,
makeSlice (data));
BEAST_EXPECT(sig.size() != 0);
BEAST_EXPECT(verify(keypair.first,
makeSlice(data), sig, true));
// Construct wrong data:
auto badData = data;
// swaps the smallest and largest elements in buffer
std::iter_swap (
std::min_element (badData.begin(), badData.end()),
std::max_element (badData.begin(), badData.end()));
// Wrong data: should fail
BEAST_EXPECT(!verify (keypair.first,
makeSlice(badData), sig, true));
// Slightly change the signature:
if (auto ptr = sig.data())
ptr[j % sig.size()]++;
// Wrong signature: should fail
BEAST_EXPECT(!verify (keypair.first,
makeSlice(data), sig, true));
// Wrong data and signature: should fail
BEAST_EXPECT(!verify (keypair.first,
makeSlice(badData), sig, true));
}
}
}
void testBase58 ()
{
testcase ("Base58");
// Ensure that parsing some well-known secret keys works
{
auto const sk1 = generateSecretKey (
KeyType::secp256k1,
generateSeed ("masterpassphrase"));
auto const sk2 = parseBase58<SecretKey> (
TOKEN_NODE_PRIVATE,
"pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe");
BEAST_EXPECT(sk2);
BEAST_EXPECT(equal (sk1, *sk2));
}
{
auto const sk1 = generateSecretKey (
KeyType::ed25519,
generateSeed ("masterpassphrase"));
auto const sk2 = parseBase58<SecretKey> (
TOKEN_NODE_PRIVATE,
"paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36");
BEAST_EXPECT(sk2);
BEAST_EXPECT(equal (sk1, *sk2));
}
// Try converting short, long and malformed data
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, ""));
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, " "));
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, "!35gty9mhju8nfjl"));
auto const good = toBase58 (
TokenType::TOKEN_NODE_PRIVATE,
randomSecretKey());
// Short (non-empty) strings
{
auto s = good;
// Remove all characters from the string in random order:
std::hash<std::string> r;
while (!s.empty())
{
s.erase (r(s) % s.size(), 1);
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, 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<SecretKey> (TOKEN_NODE_PRIVATE, 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<SecretKey> (TOKEN_NODE_PRIVATE, s));
}
}
// Strings with incorrect prefix
{
auto s = good;
for (auto c : std::string("ansrJqtv7"))
{
s[0] = c;
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, s));
}
}
// Try some random secret keys
std::array <SecretKey, 32> keys;
for (std::size_t i = 0; i != keys.size(); ++i)
keys[i] = randomSecretKey();
for (std::size_t i = 0; i != keys.size(); ++i)
{
auto const si = toBase58 (
TokenType::TOKEN_NODE_PRIVATE,
keys[i]);
BEAST_EXPECT(!si.empty());
auto const ski = parseBase58<SecretKey> (
TOKEN_NODE_PRIVATE, si);
BEAST_EXPECT(ski && equal(keys[i], *ski));
for (std::size_t j = i; j != keys.size(); ++j)
{
BEAST_EXPECT(equal (keys[i], keys[j]) == (i == j));
auto const sj = toBase58 (
TokenType::TOKEN_NODE_PRIVATE,
keys[j]);
BEAST_EXPECT((si == sj) == (i == j));
auto const skj = parseBase58<SecretKey> (
TOKEN_NODE_PRIVATE, sj);
BEAST_EXPECT(skj && equal(keys[j], *skj));
BEAST_EXPECT(equal (*ski, *skj) == (i == j));
}
}
}
void testMiscOperations ()
{
testcase ("Miscellaneous operations");
auto const sk1 = generateSecretKey (
KeyType::secp256k1,
generateSeed ("masterpassphrase"));
SecretKey sk2 (sk1);
BEAST_EXPECT(equal (sk1, sk2));
SecretKey sk3;
sk3 = sk2;
BEAST_EXPECT(equal (sk3, sk2));
}
void run() override
{
testBase58();
testDigestSigning();
testMiscOperations();
testcase ("secp256k1");
testSigning(KeyType::secp256k1);
testcase ("ed25519");
testSigning(KeyType::ed25519);
}
};
BEAST_DEFINE_TESTSUITE(SecretKey,protocol,ripple);
} // ripple

View File

@@ -0,0 +1,353 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/basics/random.h>
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/Seed.h>
#include <ripple/beast/unit_test.h>
#include <ripple/beast/utility/rngfill.h>
#include <ripple/beast/xor_shift_engine.h>
#include <algorithm>
namespace ripple {
class Seed_test : public beast::unit_test::suite
{
static
bool equal(Seed const& lhs, Seed const& rhs)
{
return std::equal (
lhs.data(), lhs.data() + lhs.size(),
rhs.data(), rhs.data() + rhs.size());
}
public:
void testConstruction ()
{
testcase ("construction");
{
std::uint8_t src[16];
for (std::uint8_t i = 0; i < 64; i++)
{
beast::rngfill (
src,
sizeof(src),
default_prng());
Seed const seed ({ src, sizeof(src) });
BEAST_EXPECT(memcmp (seed.data(), src, sizeof(src)) == 0);
}
}
for (int i = 0; i < 64; i++)
{
uint128 src;
beast::rngfill (
src.data(),
src.size(),
default_prng());
Seed const seed (src);
BEAST_EXPECT(memcmp (seed.data(), src.data(), src.size()) == 0);
}
}
std::string testPassphrase(std::string passphrase)
{
auto const seed1 = generateSeed (passphrase);
auto const seed2 = parseBase58<Seed>(toBase58(seed1));
BEAST_EXPECT(static_cast<bool>(seed2));
BEAST_EXPECT(equal (seed1, *seed2));
return toBase58(seed1);
}
void testPassphrase()
{
testcase ("generation from passphrase");
BEAST_EXPECT(testPassphrase ("masterpassphrase") ==
"snoPBrXtMeMyMHUVTgbuqAfg1SUTb");
BEAST_EXPECT(testPassphrase ("Non-Random Passphrase") ==
"snMKnVku798EnBwUfxeSD8953sLYA");
BEAST_EXPECT(testPassphrase ("cookies excitement hand public") ==
"sspUXGrmjQhq6mgc24jiRuevZiwKT");
}
void testBase58()
{
testcase ("base58 operations");
// Success:
BEAST_EXPECT(parseBase58<Seed>("snoPBrXtMeMyMHUVTgbuqAfg1SUTb"));
BEAST_EXPECT(parseBase58<Seed>("snMKnVku798EnBwUfxeSD8953sLYA"));
BEAST_EXPECT(parseBase58<Seed>("sspUXGrmjQhq6mgc24jiRuevZiwKT"));
// Failure:
BEAST_EXPECT(!parseBase58<Seed>(""));
BEAST_EXPECT(!parseBase58<Seed>("sspUXGrmjQhq6mgc24jiRuevZiwK"));
BEAST_EXPECT(!parseBase58<Seed>("sspUXGrmjQhq6mgc24jiRuevZiwKTT"));
BEAST_EXPECT(!parseBase58<Seed>("sspOXGrmjQhq6mgc24jiRuevZiwKT"));
BEAST_EXPECT(!parseBase58<Seed>("ssp/XGrmjQhq6mgc24jiRuevZiwKT"));
}
void testRandom()
{
testcase ("random generation");
for (int i = 0; i < 32; i++)
{
auto const seed1 = randomSeed ();
auto const seed2 = parseBase58<Seed>(toBase58(seed1));
BEAST_EXPECT(static_cast<bool>(seed2));
BEAST_EXPECT(equal (seed1, *seed2));
}
}
void testKeypairGenerationAndSigning ()
{
std::string const message1 = "http://www.ripple.com";
std::string const message2 = "https://www.ripple.com";
{
testcase ("Node keypair generation & signing (secp256k1)");
auto const secretKey = generateSecretKey (
KeyType::secp256k1, generateSeed ("masterpassphrase"));
auto const publicKey = derivePublicKey (
KeyType::secp256k1, secretKey);
BEAST_EXPECT(toBase58(TokenType::TOKEN_NODE_PUBLIC, publicKey) ==
"n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9");
BEAST_EXPECT(toBase58(TokenType::TOKEN_NODE_PRIVATE, secretKey) ==
"pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe");
BEAST_EXPECT(to_string(calcNodeID(publicKey)) ==
"7E59C17D50F5959C7B158FEC95C8F815BF653DC8");
auto sig = sign (publicKey, secretKey, makeSlice(message1));
BEAST_EXPECT(sig.size() != 0);
BEAST_EXPECT(verify (publicKey, makeSlice(message1), sig));
// Correct public key but wrong message
BEAST_EXPECT(!verify (publicKey, makeSlice(message2), sig));
// Verify with incorrect public key
{
auto const otherPublicKey = derivePublicKey (
KeyType::secp256k1,
generateSecretKey (
KeyType::secp256k1,
generateSeed ("otherpassphrase")));
BEAST_EXPECT(!verify (otherPublicKey, makeSlice(message1), sig));
}
// Correct public key but wrong signature
{
// Slightly change the signature:
if (auto ptr = sig.data())
ptr[sig.size() / 2]++;
BEAST_EXPECT(!verify (publicKey, makeSlice(message1), sig));
}
}
{
testcase ("Node keypair generation & signing (ed25519)");
auto const secretKey = generateSecretKey (
KeyType::ed25519, generateSeed ("masterpassphrase"));
auto const publicKey = derivePublicKey (
KeyType::ed25519, secretKey);
BEAST_EXPECT(toBase58(TokenType::TOKEN_NODE_PUBLIC, publicKey) ==
"nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf");
BEAST_EXPECT(toBase58(TokenType::TOKEN_NODE_PRIVATE, secretKey) ==
"paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36");
BEAST_EXPECT(to_string(calcNodeID(publicKey)) ==
"AA066C988C712815CC37AF71472B7CBBBD4E2A0A");
auto sig = sign (publicKey, secretKey, makeSlice(message1));
BEAST_EXPECT(sig.size() != 0);
BEAST_EXPECT(verify (publicKey, makeSlice(message1), sig));
// Correct public key but wrong message
BEAST_EXPECT(!verify (publicKey, makeSlice(message2), sig));
// Verify with incorrect public key
{
auto const otherPublicKey = derivePublicKey (
KeyType::ed25519,
generateSecretKey (
KeyType::ed25519,
generateSeed ("otherpassphrase")));
BEAST_EXPECT(!verify (otherPublicKey, makeSlice(message1), sig));
}
// Correct public key but wrong signature
{
// Slightly change the signature:
if (auto ptr = sig.data())
ptr[sig.size() / 2]++;
BEAST_EXPECT(!verify (publicKey, makeSlice(message1), sig));
}
}
{
testcase ("Account keypair generation & signing (secp256k1)");
auto const keyPair = generateKeyPair (
KeyType::secp256k1,
generateSeed ("masterpassphrase"));
BEAST_EXPECT(toBase58(calcAccountID(keyPair.first)) ==
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
BEAST_EXPECT(toBase58(TokenType::TOKEN_ACCOUNT_PUBLIC, keyPair.first) ==
"aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw");
BEAST_EXPECT(toBase58(TokenType::TOKEN_ACCOUNT_SECRET, keyPair.second) ==
"p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh");
auto sig = sign (keyPair.first, keyPair.second, makeSlice(message1));
BEAST_EXPECT(sig.size() != 0);
BEAST_EXPECT(verify (keyPair.first, makeSlice(message1), sig));
// Correct public key but wrong message
BEAST_EXPECT(!verify (keyPair.first, makeSlice(message2), sig));
// Verify with incorrect public key
{
auto const otherKeyPair = generateKeyPair (
KeyType::secp256k1,
generateSeed ("otherpassphrase"));
BEAST_EXPECT(!verify (otherKeyPair.first, makeSlice(message1), sig));
}
// Correct public key but wrong signature
{
// Slightly change the signature:
if (auto ptr = sig.data())
ptr[sig.size() / 2]++;
BEAST_EXPECT(!verify (keyPair.first, makeSlice(message1), sig));
}
}
{
testcase ("Account keypair generation & signing (ed25519)");
auto const keyPair = generateKeyPair (
KeyType::ed25519,
generateSeed ("masterpassphrase"));
BEAST_EXPECT(to_string(calcAccountID(keyPair.first)) ==
"rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf");
BEAST_EXPECT(toBase58(TokenType::TOKEN_ACCOUNT_PUBLIC, keyPair.first) ==
"aKGheSBjmCsKJVuLNKRAKpZXT6wpk2FCuEZAXJupXgdAxX5THCqR");
BEAST_EXPECT(toBase58(TokenType::TOKEN_ACCOUNT_SECRET, keyPair.second) ==
"pwDQjwEhbUBmPuEjFpEG75bFhv2obkCB7NxQsfFxM7xGHBMVPu9");
auto sig = sign (keyPair.first, keyPair.second, makeSlice(message1));
BEAST_EXPECT(sig.size() != 0);
BEAST_EXPECT(verify (keyPair.first, makeSlice(message1), sig));
// Correct public key but wrong message
BEAST_EXPECT(!verify (keyPair.first, makeSlice(message2), sig));
// Verify with incorrect public key
{
auto const otherKeyPair = generateKeyPair (
KeyType::ed25519,
generateSeed ("otherpassphrase"));
BEAST_EXPECT(!verify (otherKeyPair.first, makeSlice(message1), sig));
}
// Correct public key but wrong signature
{
// Slightly change the signature:
if (auto ptr = sig.data())
ptr[sig.size() / 2]++;
BEAST_EXPECT(!verify (keyPair.first, makeSlice(message1), sig));
}
}
}
void testSeedParsing ()
{
testcase ("Parsing");
// account IDs and node and account public and private
// keys should not be parseable as seeds.
auto const node1 = randomKeyPair(KeyType::secp256k1);
BEAST_EXPECT(!parseGenericSeed (
toBase58 (TokenType::TOKEN_NODE_PUBLIC, node1.first)));
BEAST_EXPECT(!parseGenericSeed (
toBase58 (TokenType::TOKEN_NODE_PRIVATE, node1.second)));
auto const node2 = randomKeyPair(KeyType::ed25519);
BEAST_EXPECT(!parseGenericSeed (
toBase58 (TokenType::TOKEN_NODE_PUBLIC, node2.first)));
BEAST_EXPECT(!parseGenericSeed (
toBase58 (TokenType::TOKEN_NODE_PRIVATE, node2.second)));
auto const account1 = generateKeyPair(
KeyType::secp256k1, randomSeed ());
BEAST_EXPECT(!parseGenericSeed (
toBase58(calcAccountID(account1.first))));
BEAST_EXPECT(!parseGenericSeed (
toBase58(TokenType::TOKEN_ACCOUNT_PUBLIC, account1.first)));
BEAST_EXPECT(!parseGenericSeed (
toBase58(TokenType::TOKEN_ACCOUNT_SECRET, account1.second)));
auto const account2 = generateKeyPair(
KeyType::ed25519, randomSeed ());
BEAST_EXPECT(!parseGenericSeed (
toBase58(calcAccountID(account2.first))));
BEAST_EXPECT(!parseGenericSeed (
toBase58(TokenType::TOKEN_ACCOUNT_PUBLIC, account2.first)));
BEAST_EXPECT(!parseGenericSeed (
toBase58(TokenType::TOKEN_ACCOUNT_SECRET, account2.second)));
}
void run() override
{
testConstruction();
testPassphrase();
testBase58();
testRandom();
testKeypairGenerationAndSigning();
testSeedParsing ();
}
};
BEAST_DEFINE_TESTSUITE(Seed,protocol,ripple);
} // ripple

View File

@@ -0,0 +1,206 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/protocol/XRPAmount.h>
#include <ripple/beast/unit_test.h>
namespace ripple {
class XRPAmount_test : public beast::unit_test::suite
{
public:
void testSigNum ()
{
testcase ("signum");
for (auto i : { -1, 0, 1})
{
XRPAmount const x(i);
if (i < 0)
BEAST_EXPECT(x.signum () < 0);
else if (i > 0)
BEAST_EXPECT(x.signum () > 0);
else
BEAST_EXPECT(x.signum () == 0);
}
}
void testBeastZero ()
{
testcase ("beast::Zero Comparisons");
for (auto i : { -1, 0, 1})
{
XRPAmount const x (i);
BEAST_EXPECT((i == 0) == (x == zero));
BEAST_EXPECT((i != 0) == (x != zero));
BEAST_EXPECT((i < 0) == (x < zero));
BEAST_EXPECT((i > 0) == (x > zero));
BEAST_EXPECT((i <= 0) == (x <= zero));
BEAST_EXPECT((i >= 0) == (x >= zero));
BEAST_EXPECT((0 == i) == (zero == x));
BEAST_EXPECT((0 != i) == (zero != x));
BEAST_EXPECT((0 < i) == (zero < x));
BEAST_EXPECT((0 > i) == (zero > x));
BEAST_EXPECT((0 <= i) == (zero <= x));
BEAST_EXPECT((0 >= i) == (zero >= x));
}
}
void testComparisons ()
{
testcase ("XRP Comparisons");
for (auto i : { -1, 0, 1})
{
XRPAmount const x (i);
for (auto j : { -1, 0, 1})
{
XRPAmount const y (j);
BEAST_EXPECT((i == j) == (x == y));
BEAST_EXPECT((i != j) == (x != y));
BEAST_EXPECT((i < j) == (x < y));
BEAST_EXPECT((i > j) == (x > y));
BEAST_EXPECT((i <= j) == (x <= y));
BEAST_EXPECT((i >= j) == (x >= y));
}
}
}
void testAddSub ()
{
testcase ("Addition & Subtraction");
for (auto i : { -1, 0, 1})
{
XRPAmount const x (i);
for (auto j : { -1, 0, 1})
{
XRPAmount const y (j);
BEAST_EXPECT(XRPAmount(i + j) == (x + y));
BEAST_EXPECT(XRPAmount(i - j) == (x - y));
BEAST_EXPECT((x + y) == (y + x)); // addition is commutative
}
}
}
void testMulRatio()
{
testcase ("mulRatio");
constexpr auto maxUInt32 = std::numeric_limits<std::uint32_t>::max ();
constexpr auto maxUInt64 = std::numeric_limits<std::uint64_t>::max ();
{
// multiply by a number that would overflow then divide by the same
// number, and check we didn't lose any value
XRPAmount big (maxUInt64);
BEAST_EXPECT(big == mulRatio (big, maxUInt32, maxUInt32, true));
// rounding mode shouldn't matter as the result is exact
BEAST_EXPECT(big == mulRatio (big, maxUInt32, maxUInt32, false));
}
{
// Similar test as above, but for neative values
XRPAmount big (maxUInt64);
BEAST_EXPECT(big == mulRatio (big, maxUInt32, maxUInt32, true));
// rounding mode shouldn't matter as the result is exact
BEAST_EXPECT(big == mulRatio (big, maxUInt32, maxUInt32, false));
}
{
// small amounts
XRPAmount tiny (1);
// Round up should give the smallest allowable number
BEAST_EXPECT(tiny == mulRatio (tiny, 1, maxUInt32, true));
// rounding down should be zero
BEAST_EXPECT(beast::zero == mulRatio (tiny, 1, maxUInt32, false));
BEAST_EXPECT(beast::zero ==
mulRatio (tiny, maxUInt32 - 1, maxUInt32, false));
// tiny negative numbers
XRPAmount tinyNeg (-1);
// Round up should give zero
BEAST_EXPECT(zero == mulRatio (tinyNeg, 1, maxUInt32, true));
BEAST_EXPECT(zero == mulRatio (tinyNeg, maxUInt32 - 1, maxUInt32, true));
// rounding down should be tiny
BEAST_EXPECT(tinyNeg == mulRatio (tinyNeg, maxUInt32 - 1, maxUInt32, false));
}
{
// rounding
{
XRPAmount one (1);
auto const rup = mulRatio (one, maxUInt32 - 1, maxUInt32, true);
auto const rdown = mulRatio (one, maxUInt32 - 1, maxUInt32, false);
BEAST_EXPECT(rup.drops () - rdown.drops () == 1);
}
{
XRPAmount big (maxUInt64);
auto const rup = mulRatio (big, maxUInt32 - 1, maxUInt32, true);
auto const rdown = mulRatio (big, maxUInt32 - 1, maxUInt32, false);
BEAST_EXPECT(rup.drops () - rdown.drops () == 1);
}
{
XRPAmount negOne (-1);
auto const rup = mulRatio (negOne, maxUInt32 - 1, maxUInt32, true);
auto const rdown = mulRatio (negOne, maxUInt32 - 1, maxUInt32, false);
BEAST_EXPECT(rup.drops () - rdown.drops () == 1);
}
}
{
// division by zero
XRPAmount one (1);
except ([&] {mulRatio (one, 1, 0, true);});
}
{
// overflow
XRPAmount big (maxUInt64);
except ([&] {mulRatio (big, 2, 0, true);});
}
}
//--------------------------------------------------------------------------
void run ()
{
testSigNum ();
testBeastZero ();
testComparisons ();
testAddSub ();
testMulRatio ();
}
};
BEAST_DEFINE_TESTSUITE(XRPAmount,protocol,ripple);
} // ripple

View File

@@ -0,0 +1,162 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/protocol/digest.h>
#include <ripple/beast/utility/rngfill.h>
#include <ripple/beast/xor_shift_engine.h>
#include <ripple/beast/unit_test.h>
#include <algorithm>
#include <chrono>
#include <cmath>
#include <numeric>
#include <vector>
namespace ripple {
class digest_test : public beast::unit_test::suite
{
std::vector<uint256> dataset1;
template <class Hasher>
void test (char const* name)
{
using namespace std::chrono;
// Prime the cache
for (int i = 0; i != 4; i++)
{
for (auto const& x : dataset1)
{
Hasher h;
h (x.data (), x.size ());
(void) static_cast<typename Hasher::result_type>(h);
}
}
std::array<nanoseconds, 128> results;
for (auto& result : results)
{
auto const start = high_resolution_clock::now ();
for (auto const& x : dataset1)
{
Hasher h;
h (x.data (), x.size ());
(void) static_cast<typename Hasher::result_type>(h);
}
auto const d = high_resolution_clock::now () - start;
result = d;
}
log << " " << name << ":" << '\n';
auto const sum = std::accumulate(
results.begin(), results.end(),
nanoseconds{0});
{
auto s = duration_cast<seconds>(sum);
auto ms = duration_cast<milliseconds>(sum) - s;
log <<
" Total Time = " << s.count() <<
"." << ms.count() << " seconds" << std::endl;
}
auto const mean = sum / results.size();
{
auto s = duration_cast<seconds>(mean);
auto ms = duration_cast<milliseconds>(mean) - s;
log <<
" Mean Time = " << s.count() <<
"." << ms.count() << " seconds" << std::endl;
}
std::vector<nanoseconds::rep> diff(results.size());
std::transform(
results.begin(), results.end(), diff.begin(),
[&mean](nanoseconds trial)
{
return (trial - mean).count();
});
auto const sq_sum = std::inner_product(
diff.begin(), diff.end(), diff.begin(), 0.0);
{
nanoseconds const stddev {
static_cast<nanoseconds::rep>(
std::sqrt(sq_sum / results.size()))
};
auto s = duration_cast<seconds>(stddev);
auto ms = duration_cast<milliseconds>(stddev) - s;
log <<
" Std Dev = " << s.count() <<
"." << ms.count() << " seconds" << std::endl;
}
}
public:
digest_test ()
{
beast::xor_shift_engine g(19207813);
std::uint8_t buf[32];
for (int i = 0; i < 1000000; i++)
{
beast::rngfill (buf, sizeof(buf), g);
dataset1.push_back (uint256::fromVoid (buf));
}
}
void testSHA512 ()
{
testcase ("SHA512");
test<openssl_ripemd160_hasher> ("OpenSSL");
test<beast::ripemd160_hasher> ("Beast");
pass ();
}
void testSHA256 ()
{
testcase ("SHA256");
test<openssl_sha256_hasher> ("OpenSSL");
test<beast::sha256_hasher> ("Beast");
pass ();
}
void testRIPEMD160 ()
{
testcase ("RIPEMD160");
test<openssl_ripemd160_hasher> ("OpenSSL");
test<beast::ripemd160_hasher> ("Beast");
pass ();
}
void run ()
{
testSHA512 ();
testSHA256 ();
testRIPEMD160 ();
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(digest,ripple_data,ripple);
} // ripple

View File

@@ -0,0 +1,47 @@
//------------------------------------------------------------------------------
/*
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 <BeastConfig.h>
#include <ripple/protocol/types.h>
#include <ripple/beast/unit_test.h>
namespace ripple {
struct types_test : public beast::unit_test::suite
{
void
testAccountID()
{
auto const s =
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
if (BEAST_EXPECT(parseBase58<AccountID>(s)))
BEAST_EXPECT(toBase58(
*parseBase58<AccountID>(s)) == s);
}
void
run() override
{
testAccountID();
}
};
BEAST_DEFINE_TESTSUITE(types,protocol,ripple);
}