Skip to content

Commit

Permalink
Merge pull request #146 from bitshares/optional-api-fix
Browse files Browse the repository at this point in the history
Fix optional API arguments
  • Loading branch information
abitmore authored Aug 13, 2019
2 parents 82af8b5 + 17c4639 commit f7a1e53
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 8 deletions.
22 changes: 16 additions & 6 deletions include/fc/rpc/api_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,18 @@ namespace fc {
}

template<typename R, typename Arg0, typename ... Args>
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0,
variants::const_iterator e, uint32_t max_depth )
{
bool optional_args = all_optionals<std::decay_t<Arg0>, std::decay_t<Args>...>::value;
FC_ASSERT( a0 != e || optional_args );
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
auto arg = (a0 == e)? std::decay_t<Arg0>() : a0->as<std::decay_t<Arg0>>(max_depth - 1);
return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, arg ), a0+1, e, max_depth - 1 );
if (a0==e)
return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, std::decay_t<Arg0>() ), a0,
e, max_depth - 1 );
auto arg = a0->as<std::decay_t<Arg0>>(max_depth - 1);
return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, std::move(arg) ), a0+1, e,
max_depth - 1 );
}

template<typename R, typename ... Args>
Expand Down Expand Up @@ -180,13 +185,18 @@ namespace fc {
}

template<typename R, typename Arg0, typename ... Args>
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0,
variants::const_iterator e, uint32_t max_depth )
{
bool optional_args = detail::all_optionals<std::decay_t<Arg0>, std::decay_t<Args>...>::value;
FC_ASSERT( a0 != e || optional_args, "too few arguments passed to method" );
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
auto arg = (a0 == e)? std::decay_t<Arg0>() : a0->as<std::decay_t<Arg0>>(max_depth - 1);
return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, arg ), a0+1, e, max_depth - 1 );
if (a0==e)
return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, std::decay_t<Arg0>() ), a0,
e, max_depth - 1 );
auto arg = a0->as<std::decay_t<Arg0>>(max_depth - 1);
return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, std::move(arg) ), a0+1, e,
max_depth - 1 );
}

struct api_visitor
Expand Down
44 changes: 42 additions & 2 deletions tests/api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ class optionals_api
const fc::optional<std::string>& third ) {
return fc::json::to_string(fc::variants{first, {second, 2}, {third, 2}});
}
std::string bar( fc::optional<std::string> first, fc::optional<std::string> second,
fc::optional<std::string> third ) {
return fc::json::to_string(fc::variants{{first,2}, {second, 2}, {third, 2}});
}
};
FC_API( optionals_api, (foo) );
FC_API( optionals_api, (foo)(bar) );

using namespace fc;

Expand Down Expand Up @@ -106,6 +110,12 @@ BOOST_AUTO_TEST_CASE(optionals_test) {
BOOST_CHECK_EQUAL(oapi->foo("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
BOOST_CHECK_EQUAL(oapi->foo("a", {}, "c"), "[\"a\",null,\"c\"]");

BOOST_CHECK_EQUAL(oapi->bar(), "[null,null,null]");
BOOST_CHECK_EQUAL(oapi->bar("a"), "[\"a\",null,null]");
BOOST_CHECK_EQUAL(oapi->bar("a", "b"), "[\"a\",\"b\",null]");
BOOST_CHECK_EQUAL(oapi->bar("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
BOOST_CHECK_EQUAL(oapi->bar("a", {}, "c"), "[\"a\",null,\"c\"]");

auto server = std::make_shared<fc::http::websocket_server>();
server->on_connection([&]( const websocket_connection_ptr& c ){
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
Expand All @@ -119,7 +129,6 @@ BOOST_AUTO_TEST_CASE(optionals_test) {

auto client = std::make_shared<fc::http::websocket_client>();
auto con = client->connect( "ws://localhost:" + std::to_string(listen_port) );
server->stop_listening();
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
auto remote_optionals = apic->get_remote_api<optionals_api>();

Expand All @@ -128,6 +137,37 @@ BOOST_AUTO_TEST_CASE(optionals_test) {
BOOST_CHECK_EQUAL(remote_optionals->foo("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
BOOST_CHECK_EQUAL(remote_optionals->foo("a", {}, "c"), "[\"a\",null,\"c\"]");

BOOST_CHECK_EQUAL(remote_optionals->bar(), "[null,null,null]");
BOOST_CHECK_EQUAL(remote_optionals->bar("a"), "[\"a\",null,null]");
BOOST_CHECK_EQUAL(remote_optionals->bar("a", "b"), "[\"a\",\"b\",null]");
BOOST_CHECK_EQUAL(remote_optionals->bar("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
BOOST_CHECK_EQUAL(remote_optionals->bar("a", {}, "c"), "[\"a\",null,\"c\"]");

auto client2 = std::make_shared<fc::http::websocket_client>();
auto con2 = client2->connect( "ws://localhost:" + std::to_string(listen_port) );
string response;
con2->on_message_handler([&](const std::string& s){
response = s;
});

con2->send_message( "{\"id\":1,\"method\":\"call\",\"params\":[0,\"bar\",[\"a\",\"b\",\"c\"]]}" );
fc::usleep(fc::milliseconds(50));
BOOST_CHECK_EQUAL( response, "{\"id\":1,\"result\":\"[\\\"a\\\",\\\"b\\\",\\\"c\\\"]\"}" );

con2->send_message( "{\"id\":2,\"method\":\"call\",\"params\":[0,\"bar\",[\"a\",\"b\"]]}" );
fc::usleep(fc::milliseconds(50));
BOOST_CHECK_EQUAL( response, "{\"id\":2,\"result\":\"[\\\"a\\\",\\\"b\\\",null]\"}" );

con2->send_message( "{\"id\":3,\"method\":\"call\",\"params\":[0,\"bar\",[\"a\"]]}" );
fc::usleep(fc::milliseconds(50));
BOOST_CHECK_EQUAL( response, "{\"id\":3,\"result\":\"[\\\"a\\\",null,null]\"}" );

con2->send_message( "{\"id\":4,\"method\":\"call\",\"params\":[0,\"bar\",[]]}" );
fc::usleep(fc::milliseconds(50));
BOOST_CHECK_EQUAL( response, "{\"id\":4,\"result\":\"[null,null,null]\"}" );

server->stop_listening();

client->synchronous_close();
server->close();
fc::usleep(fc::milliseconds(50));
Expand Down

0 comments on commit f7a1e53

Please sign in to comment.