From 9effcc3924bb90911cc6f01b218e50d5db43c675 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Tue, 31 Jan 2023 02:03:50 -0500 Subject: [PATCH] add testfile and cmake --- Builds/CMake/RippledCore.cmake | 1 + src/test/app/URIToken_test.cpp | 254 +++++++++++++++++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 src/test/app/URIToken_test.cpp diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index 41c8b48fc..b44c0334f 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -731,6 +731,7 @@ if (tests) src/test/app/Transaction_ordering_test.cpp src/test/app/TrustAndBalance_test.cpp src/test/app/TxQ_test.cpp + src/test/app/URIToken_test.cpp src/test/app/ValidatorKeys_test.cpp src/test/app/ValidatorList_test.cpp src/test/app/ValidatorSite_test.cpp diff --git a/src/test/app/URIToken_test.cpp b/src/test/app/URIToken_test.cpp new file mode 100644 index 000000000..923a5e10d --- /dev/null +++ b/src/test/app/URIToken_test.cpp @@ -0,0 +1,254 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include +// #include +#include +#include +#include + +#include + +namespace ripple { +namespace test { +struct URIToken_test : public beast::unit_test::suite +{ + static uint256 + tokenid( + jtx::Account const& account, + std::string const& uri) + { + auto const k = keylet::uritoken(account, Blob(uri.begin(), uri.end())); + return k.key; + } + + static bool + inOwnerDir(ReadView const& view, jtx::Account const& acct, std::shared_ptr const& token) + { + ripple::Dir const ownerDir(view, keylet::ownerDir(acct.id())); + return std::find(ownerDir.begin(), ownerDir.end(), token) != ownerDir.end(); + } + + static std::size_t + ownerDirCount(ReadView const& view, jtx::Account const& acct) + { + ripple::Dir const ownerDir(view, keylet::ownerDir(acct.id())); + return std::distance(ownerDir.begin(), ownerDir.end()); + }; + + static Json::Value + mint( + jtx::Account const& account, + std::string const& uri) + { + using namespace jtx; + Json::Value jv; + jv[jss::TransactionType] = jss::URIToken; + jv[jss::Flags] = tfBurnable; + jv[jss::Account] = account.human(); + jv[sfURI.jsonName] = strHex(uri); + // jv[sfDigest.jsonName] = digest; + return jv; + } + + static Json::Value + burn( + jtx::Account const& account, + std::string const& id) + { + using namespace jtx; + Json::Value jv; + jv[jss::TransactionType] = jss::URIToken; + jv[jss::Flags] = tfBurn; + jv[jss::Account] = account.human(); + jv[sfURITokenID.jsonName] = id; + return jv; + } + + static Json::Value + buy( + jtx::Account const& account, + std::string const& id, + STAmount const& amount) + { + using namespace jtx; + Json::Value jv; + jv[jss::TransactionType] = jss::URIToken; + jv[jss::Account] = account.human(); + jv[jss::Amount] = amount.getJson(JsonOptions::none); + jv[sfURITokenID.jsonName] = id; + return jv; + } + + static Json::Value + sell( + jtx::Account const& account, + std::string const& id, + STAmount const& amount) + { + using namespace jtx; + Json::Value jv; + jv[jss::TransactionType] = jss::URIToken; + jv[jss::Account] = account.human(); + jv[jss::Amount] = amount.getJson(JsonOptions::none); + jv[sfURITokenID.jsonName] = id; + return jv; + } + + static Json::Value + clear( + jtx::Account const& account, + std::string const& id) + { + using namespace jtx; + Json::Value jv; + jv[jss::TransactionType] = jss::URIToken; + jv[jss::Account] = account.human(); + jv[sfURITokenID.jsonName] = id; + return jv; + } + + void + testEnabled(FeatureBitset features) + { + testcase("enabled"); + using namespace jtx; + using namespace std::literals::chrono_literals; + + // setup env + auto const alice = Account("alice"); + auto const bob = Account("bob"); + auto USD = alice["USD"]; + + { + // If the URIToken amendment is not enabled, you should not be able + // to mint, burn, buy, sell or clear uri tokens. + Env env{*this, features - featureURIToken}; + + env.fund(XRP(1000), alice, bob); + + std::string const uri(maxTokenURILength, '?'); + std::string const id{strHex(tokenid(alice, uri))}; + + // MINT + env(mint(alice, uri), ter(temDISABLED)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + + // SELL + env(sell(alice, id, XRP(10)), txflags(tfSell), ter(temDISABLED)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + + // BUY + env(buy(bob, id, XRP(10)), ter(temDISABLED)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + + // SELL + env(sell(bob, id, XRP(10)), txflags(tfSell), ter(temDISABLED)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + + // CLEAR + env(clear(bob, id), ter(temDISABLED)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + + // BURN + env(burn(bob, id), ter(temDISABLED)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + } + { + // If the URIToken amendment is enabled, you should be able + // to mint, burn, buy, sell and clear uri tokens. + Env env{*this, features}; + + env.fund(XRP(1000), alice, bob); + + std::string const uri(maxTokenURILength, '?'); + std::string const id{strHex(tokenid(alice, uri))}; + + // MINT + env(mint(alice, uri)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + + // SELL + env(sell(alice, id, XRP(10)), txflags(tfSell)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + + // BUY + env(buy(bob, id, XRP(10))); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1); + + // SELL + env(sell(bob, id, XRP(10)), txflags(tfSell)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1); + + // CLEAR + env(clear(bob, id)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1); + + // BURN + env(burn(bob, id)); + env.close(); + BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + } + } + + void + testWithFeats(FeatureBitset features) + { + testEnabled(features); + } + +public: + void + run() override + { + using namespace test::jtx; + auto const sa = supported_amendments(); + testWithFeats(sa); + } +}; + +BEAST_DEFINE_TESTSUITE(URIToken, app, ripple); +} // namespace test +} // namespace ripple