Skip to content

Commit

Permalink
rpc, tests: Tests for retrieving RPC parameters by name
Browse files Browse the repository at this point in the history
  • Loading branch information
achow101 committed May 30, 2023
1 parent acaf097 commit 35c5ffb
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 8 deletions.
6 changes: 2 additions & 4 deletions src/rpc/request.cpp
Expand Up @@ -196,15 +196,13 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
const UniValue& JSONRPCRequest::JSONRPCParameters::operator[](const std::string& key) const
{
const auto it = named.find(key);
Assert(it != named.end());
if (it == named.end()) return NullUniValue;
return *it->second;
}

const UniValue& JSONRPCRequest::JSONRPCParameters::operator[](size_t pos) const
{
if (pos >= positional.size()) {
return NullUniValue;
}
if (pos >= positional.size()) return NullUniValue;
const UniValue* item = positional.at(pos);
return item ? *item : NullUniValue;
}
Expand Down
7 changes: 3 additions & 4 deletions src/rpc/request.h
Expand Up @@ -34,8 +34,7 @@ class JSONRPCRequest
public:
/** The parameters as received */
UniValue received;
/** Parameter name to parameter. All parameters will be present,
* those not provided at all (neither named nor positional) will be stored as NullUniValue */
/** Parameter name to parameter. Only provided parameters will be present. */
std::unordered_map<std::string, const UniValue*> named;
/** Parameter position to parameter.
* Parameters not provided at all (neither named nor positional) will be stored as nullptr,
Expand All @@ -46,9 +45,9 @@ class JSONRPCRequest
/** Process the received parameters into named and positional mappings */
void ProcessParameters(const std::vector<std::string>& argNames);

/** Retrieve a parameter by its name */
/** Retrieve a parameter by its name. Unknown parameters are returned as NullUniValue. */
const UniValue& operator[](const std::string& key) const;
/** Retrieve a parameter by its position */
/** Retrieve a parameter by its position. Out of bound parameters are returned as NullUniValue */
const UniValue& operator[](size_t pos) const;

/** The number of parameters received */
Expand Down
46 changes: 46 additions & 0 deletions src/test/rpc_tests.cpp
Expand Up @@ -88,6 +88,7 @@ BOOST_AUTO_TEST_CASE(rpc_namedparams)

// Make sure named arguments are transformed into positional arguments in correct places separated by nulls
BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg2": 2, "arg4": 4})"), arg_names).write(), "[null,2,null,4]");
BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg2": 2, "arg4": 4, "arg5": null})"), arg_names).write(), "[null,2,null,4,null]");

// Make sure named argument specified multiple times raises an exception
BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"arg2": 2, "arg2": 4})"), arg_names), UniValue,
Expand Down Expand Up @@ -541,4 +542,49 @@ BOOST_AUTO_TEST_CASE(help_example)
BOOST_CHECK_NE(HelpExampleRpcNamed("foo", {{"arg", true}}), HelpExampleRpcNamed("foo", {{"arg", "true"}}));
}

static void TestParamsByName(const UniValue& params)
{
const std::vector<std::string> arg_names{"arg0", "arg1", "arg2", "arg3", "arg4", "arg5"};
CRPCTable table;
CRPCCommand command{"category", "method",
[&](const JSONRPCRequest& request, UniValue&, bool) -> bool
{
for (size_t i = 0; i < request.params.size() * 2; ++i) {
std::string arg_name = strprintf("arg%u", i);
if (i < arg_names.size()) {
// Known parameters should be the same for both positional and named
BOOST_CHECK_EQUAL(request.params[arg_name].getType(), request.params[i].getType());
BOOST_CHECK_EQUAL(request.params[arg_name].getValStr(), request.params[i].getValStr());
} else {
// Unknown positionals should still be accessible
auto arg = request.params[i];
if (i > request.params.size()) {
// Out of bound positionals are always NullUniValue
BOOST_CHECK(arg.isNull());
}
// Unknown named are always NullUniValue
BOOST_CHECK(request.params[arg_name].isNull());
}
}
return true;
},
arg_names,
/*unique_id=*/0
};
table.appendCommand("method", &command);
JSONRPCRequest request;
request.strMethod = "method";
request.params.received = params;
if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
table.execute(request);
}

BOOST_AUTO_TEST_CASE(rpc_params_by_name)
{
TestParamsByName(JSON(R"({"arg2": 2, "arg4": 4})"));
TestParamsByName(JSON(R"({"arg2": 2, "arg4": 4, "arg5": null})"));
TestParamsByName(JSON(R"([1, 2, 3, 4, 5, 6, 7, 8])"));
TestParamsByName(JSON(R"({"args": [1, 2, 3], "arg5": 5})"));
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 35c5ffb

Please sign in to comment.