diff --git a/src/test/app/LedgerReplay_test.cpp b/src/test/app/LedgerReplay_test.cpp index 8bf1a8f668..229cad21c9 100644 --- a/src/test/app/LedgerReplay_test.cpp +++ b/src/test/app/LedgerReplay_test.cpp @@ -491,8 +491,7 @@ struct LedgerServer for (int i = 0; i < newTxes; ++i) { updateIdx(); - env.apply( - pay(accounts[fromIdx], + env(pay(accounts[fromIdx], accounts[toIdx], jtx::drops(ledgerMaster.getClosedLedger()->fees().base) + jtx::XRP(param.txAmount)), jtx::seq(jtx::autofill), diff --git a/src/test/jtx/Env.h b/src/test/jtx/Env.h index ef6240d48a..7d7dcd2cb8 100644 --- a/src/test/jtx/Env.h +++ b/src/test/jtx/Env.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,27 @@ namespace xrpl { namespace test { namespace jtx { +/** Wrapper that captures std::source_location when implicitly constructed. + This solves the problem of combining std::source_location with variadic + templates. The std::source_location default argument is evaluated at the + call site when the wrapper is constructed via implicit conversion. + + This is a template struct that holds the value directly, allowing implicit + conversion without template argument deduction issues via CTAD. +*/ +template +struct WithSourceLocation +{ + T value; + std::source_location loc; + + // Non-explicit constructor allows implicit conversion. + // The default argument for loc is evaluated at the call site. + WithSourceLocation(T v, std::source_location l = std::source_location::current()) : value(std::move(v)), loc(l) + { + } +}; + /** Designate accounts as no-ripple in Env::fund */ template std::array @@ -522,35 +544,57 @@ public: This calls postconditions. */ virtual void - submit(JTx const& jt); + submit(JTx const& jt, std::source_location const& loc = std::source_location::current()); /** Use the submit RPC command with a provided JTx object. This calls postconditions. */ void - sign_and_submit(JTx const& jt, Json::Value params = Json::nullValue); + sign_and_submit( + JTx const& jt, + Json::Value params = Json::nullValue, + std::source_location const& loc = std::source_location::current()); /** Check expected postconditions of JTx submission. */ void - postconditions(JTx const& jt, ParsedResult const& parsed, Json::Value const& jr = Json::Value()); + postconditions( + JTx const& jt, + ParsedResult const& parsed, + Json::Value const& jr = Json::Value(), + std::source_location const& loc = std::source_location::current()); /** Apply funclets and submit. */ /** @{ */ - template + template Env& - apply(JsonValue&& jv, FN const&... fN) + apply(WithSourceLocation jv, FN const&... fN) { - submit(jt(std::forward(jv), fN...)); + submit(jt(std::move(jv.value), fN...), jv.loc); return *this; } - template + template Env& - operator()(JsonValue&& jv, FN const&... fN) + apply(WithSourceLocation jv, FN const&... fN) { - return apply(std::forward(jv), fN...); + submit(jt(std::move(jv.value), fN...), jv.loc); + return *this; + } + + template + Env& + operator()(WithSourceLocation jv, FN const&... fN) + { + return apply(std::move(jv), fN...); + } + + template + Env& + operator()(WithSourceLocation jv, FN const&... fN) + { + return apply(std::move(jv), fN...); } /** @} */ diff --git a/src/test/jtx/Env_ss.h b/src/test/jtx/Env_ss.h index 78146a04a4..9c178a1c13 100644 --- a/src/test/jtx/Env_ss.h +++ b/src/test/jtx/Env_ss.h @@ -23,19 +23,20 @@ private: SignSubmitRunner& operator=(SignSubmitRunner&&) = delete; - SignSubmitRunner(Env& env, JTx&& jt) : env_(env), jt_(jt) + SignSubmitRunner(Env& env, JTx&& jt, std::source_location loc) : env_(env), jt_(jt), loc_(loc) { } void operator()(Json::Value const& params = Json::nullValue) { - env_.sign_and_submit(jt_, params); + env_.sign_and_submit(jt_, params, loc_); } private: Env& env_; JTx const jt_; + std::source_location const loc_; }; public: @@ -47,12 +48,20 @@ public: { } - template + template SignSubmitRunner - operator()(JsonValue&& jv, FN const&... fN) + operator()(WithSourceLocation jv, FN const&... fN) { - auto jtx = env_.jt(std::forward(jv), fN...); - return SignSubmitRunner(env_, std::move(jtx)); + auto jtx = env_.jt(std::move(jv.value), fN...); + return SignSubmitRunner(env_, std::move(jtx), jv.loc); + } + + template + SignSubmitRunner + operator()(WithSourceLocation jv, FN const&... fN) + { + auto jtx = env_.jt(std::move(jv.value), fN...); + return SignSubmitRunner(env_, std::move(jtx), jv.loc); } }; diff --git a/src/test/jtx/impl/Env.cpp b/src/test/jtx/impl/Env.cpp index 9971da05c4..d8bcec84ee 100644 --- a/src/test/jtx/impl/Env.cpp +++ b/src/test/jtx/impl/Env.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace xrpl { namespace test { @@ -330,7 +331,7 @@ Env::parseResult(Json::Value const& jr) } void -Env::submit(JTx const& jt) +Env::submit(JTx const& jt, std::source_location const& loc) { ParsedResult parsedResult; auto const jr = [&]() { @@ -356,11 +357,11 @@ Env::submit(JTx const& jt) return Json::Value(); } }(); - return postconditions(jt, parsedResult, jr); + return postconditions(jt, parsedResult, jr, loc); } void -Env::sign_and_submit(JTx const& jt, Json::Value params) +Env::sign_and_submit(JTx const& jt, Json::Value params, std::source_location const& loc) { auto const account = lookup(jt.jv[jss::Account].asString()); auto const& passphrase = account.name(); @@ -393,25 +394,26 @@ Env::sign_and_submit(JTx const& jt, Json::Value params) test.expect(parsedResult.ter, "ter uninitialized!"); ter_ = parsedResult.ter.value_or(telENV_RPC_FAILED); - return postconditions(jt, parsedResult, jr); + return postconditions(jt, parsedResult, jr, loc); } void -Env::postconditions(JTx const& jt, ParsedResult const& parsed, Json::Value const& jr) +Env::postconditions(JTx const& jt, ParsedResult const& parsed, Json::Value const& jr, std::source_location const& loc) { auto const line = jt.testLine ? " (" + to_string(*jt.testLine) + ")" : ""; - bool bad = !test.expect(parsed.ter, "apply: No ter result!" + line); + auto const locStr = std::string("(") + loc.file_name() + ":" + to_string(loc.line()) + ")"; + bool bad = !test.expect(parsed.ter, "apply " + locStr + ": No ter result!" + line); bad = (jt.ter && parsed.ter && !test.expect( *parsed.ter == *jt.ter, - "apply: Got " + transToken(*parsed.ter) + " (" + transHuman(*parsed.ter) + "); Expected " + + "apply " + locStr + ": Got " + transToken(*parsed.ter) + " (" + transHuman(*parsed.ter) + "); Expected " + transToken(*jt.ter) + " (" + transHuman(*jt.ter) + ")" + line)); using namespace std::string_literals; bad = (jt.rpcCode && !test.expect( parsed.rpcCode == jt.rpcCode->first && parsed.rpcMessage == jt.rpcCode->second, - "apply: Got RPC result "s + + "apply " + locStr + ": Got RPC result "s + (parsed.rpcCode ? RPC::get_error_info(*parsed.rpcCode).token.c_str() : "NO RESULT") + " (" + parsed.rpcMessage + "); Expected " + RPC::get_error_info(jt.rpcCode->first).token.c_str() + " (" + jt.rpcCode->second + ")" + line)) || @@ -419,13 +421,14 @@ Env::postconditions(JTx const& jt, ParsedResult const& parsed, Json::Value const // If we have an rpcCode (just checked), then the rpcException check is // optional - the 'error' field may not be defined, but if it is, it must // match rpcError. - bad = (jt.rpcException && - !test.expect( - (jt.rpcCode && parsed.rpcError.empty()) || - (parsed.rpcError == jt.rpcException->first && - (!jt.rpcException->second || parsed.rpcException == *jt.rpcException->second)), - "apply: Got RPC result "s + parsed.rpcError + " (" + parsed.rpcException + "); Expected " + - jt.rpcException->first + " (" + jt.rpcException->second.value_or("n/a") + ")" + line)) || + bad = + (jt.rpcException && + !test.expect( + (jt.rpcCode && parsed.rpcError.empty()) || + (parsed.rpcError == jt.rpcException->first && + (!jt.rpcException->second || parsed.rpcException == *jt.rpcException->second)), + "apply " + locStr + ": Got RPC result "s + parsed.rpcError + " (" + parsed.rpcException + "); Expected " + + jt.rpcException->first + " (" + jt.rpcException->second.value_or("n/a") + ")" + line)) || bad; if (bad) { diff --git a/src/test/rpc/Subscribe_test.cpp b/src/test/rpc/Subscribe_test.cpp index 4f83f81da5..cce45fb4ef 100644 --- a/src/test/rpc/Subscribe_test.cpp +++ b/src/test/rpc/Subscribe_test.cpp @@ -835,8 +835,7 @@ public: { auto& from = (i % 2 == 0) ? a : b; auto& to = (i % 2 == 0) ? b : a; - env.apply( - pay(from, to, jtx::XRP(numXRP)), + env(pay(from, to, jtx::XRP(numXRP)), jtx::seq(jtx::autofill), jtx::fee(jtx::autofill), jtx::sig(jtx::autofill));