From 45b6c7c66f9f832d3a1d532c3eb2d8857fa7b6a4 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Fri, 23 Jan 2026 15:52:42 -0500 Subject: [PATCH] add file/line to Env --- src/test/jtx/Env.h | 55 ++++++++++++++++++++++++++++++++------- src/test/jtx/impl/Env.cpp | 18 +++++++------ 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/test/jtx/Env.h b/src/test/jtx/Env.h index 1c07ac2d00d..071e1291a41 100644 --- a/src/test/jtx/Env.h +++ b/src/test/jtx/Env.h @@ -32,17 +32,46 @@ #include #include +#include #include #include #include #include #include +#include #include namespace xrpl { namespace test { namespace jtx { +class Env; // Forward declaration + +/** Wrapper that captures source_location when implicitly constructed. + This solves the problem of combining std::source_location with variadic + templates. The source_location default argument is evaluated at the + call site when the wrapper is constructed via implicit conversion. + + This is a non-template struct that uses std::variant to hold either + Json::Value or JTx, allowing implicit conversion without template + argument deduction issues. +*/ +struct WithSourceLoc +{ + std::variant value; + std::source_location loc; + + // Non-explicit constructors allow implicit conversion. + // The default argument for loc is evaluated at the call site. + WithSourceLoc(Json::Value v, std::source_location l = std::source_location::current()) : value(std::move(v)), loc(l) + { + } + + WithSourceLoc(JTx 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 @@ -523,35 +552,43 @@ class Env 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(WithSourceLoc jv, FN const&... fN) { - submit(jt(std::forward(jv), fN...)); + std::visit([&](auto&& v) { submit(jt(std::move(v), fN...), jv.loc); }, std::move(jv.value)); return *this; } - template + template Env& - operator()(JsonValue&& jv, FN const&... fN) + operator()(WithSourceLoc jv, FN const&... fN) { - return apply(std::forward(jv), fN...); + std::visit([&](auto&& v) { submit(jt(std::move(v), fN...), jv.loc); }, std::move(jv.value)); + return *this; } /** @} */ diff --git a/src/test/jtx/impl/Env.cpp b/src/test/jtx/impl/Env.cpp index 9971da05c4e..ae4aeec491b 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) + ")" : ""; + auto const file = std::string("(") + loc.file_name() + ":" + to_string(loc.line()) + ")"; bool bad = !test.expect(parsed.ter, "apply: 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 " + file + ": 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 " + file + ": 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)) || @@ -424,7 +426,7 @@ Env::postconditions(JTx const& jt, ParsedResult const& parsed, Json::Value const (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 " + + "apply " + file + ": Got RPC result "s + parsed.rpcError + " (" + parsed.rpcException + "); Expected " + jt.rpcException->first + " (" + jt.rpcException->second.value_or("n/a") + ")" + line)) || bad; if (bad)