Skip to content

Commit

Permalink
Fixes the adapter of empty nested responses.
Browse files Browse the repository at this point in the history
See #210.
  • Loading branch information
mzimbres committed Oct 5, 2024
1 parent 9039c3c commit 0acca49
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 15 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,9 @@ https://lists.boost.org/Archives/boost/2023/01/253944.php.
also changed to return EOF to the user when that error is received
from the server. That is a breaking change.

* ([Issue 210](https://github.com/boostorg/redis/issues/210))
Fixes the adapter of empty nested reposponses.

### Boost 1.85

* ([Issue 170](https://github.com/boostorg/redis/issues/170))
Expand Down
33 changes: 18 additions & 15 deletions include/boost/redis/adapter/detail/result_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,12 @@ class static_aggregate_adapter<result<Tuple>> {
std::variant>,
std::tuple_size<Tuple>::value>;

// Tuple element we are currently on.
std::size_t i_ = 0;

// Nested aggregate element counter.
std::size_t aggregate_size_ = 0;

adapters_array_type adapters_;
result<Tuple>* res_ = nullptr;

Expand All @@ -117,36 +121,35 @@ class static_aggregate_adapter<result<Tuple>> {
}

template <class String>
void count(resp3::basic_node<String> const& nd)
void count(resp3::basic_node<String> const& elem)
{
if (nd.depth == 1) {
if (is_aggregate(nd.data_type))
aggregate_size_ = element_multiplicity(nd.data_type) * nd.aggregate_size;
else
++i_;

return;
if (elem.depth == 1 && is_aggregate(elem.data_type)) {
aggregate_size_ = element_multiplicity(elem.data_type) * elem.aggregate_size;
}

if (--aggregate_size_ == 0)
++i_;
if (aggregate_size_ == 0) {
i_ += 1;
} else {
aggregate_size_ -= 1;
}
}

template <class String>
void operator()(resp3::basic_node<String> const& nd, system::error_code& ec)
void operator()(resp3::basic_node<String> const& elem, system::error_code& ec)
{
using std::visit;

if (nd.depth == 0) {
auto const real_aggr_size = nd.aggregate_size * element_multiplicity(nd.data_type);
if (elem.depth == 0) {
auto const multiplicity = element_multiplicity(elem.data_type);
auto const real_aggr_size = elem.aggregate_size * multiplicity;
if (real_aggr_size != std::tuple_size<Tuple>::value)
ec = redis::error::incompatible_size;

return;
}

visit([&](auto& arg){arg(nd, ec);}, adapters_[i_]);
count(nd);
visit([&](auto& arg){arg(elem, ec);}, adapters_[i_]);
count(elem);
}
};

Expand Down
112 changes: 112 additions & 0 deletions test/test_low_level_sync_sans_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
using boost::redis::request;
using boost::redis::config;
using boost::redis::detail::push_hello;
using boost::redis::response;
using boost::redis::adapter::adapt2;
using boost::redis::adapter::result;
using boost::redis::resp3::detail::deserialize;
using boost::redis::ignore_t;

BOOST_AUTO_TEST_CASE(low_level_sync_sans_io)
{
Expand Down Expand Up @@ -88,3 +90,113 @@ BOOST_AUTO_TEST_CASE(config_to_hello_cmd_auth)
std::string_view const expected = "*5\r\n$5\r\nHELLO\r\n$1\r\n3\r\n$4\r\nAUTH\r\n$3\r\nfoo\r\n$3\r\nbar\r\n";
BOOST_CHECK_EQUAL(req.payload(), expected);
}

BOOST_AUTO_TEST_CASE(issue_210_empty_set)
{
try {
result<
std::tuple<
result<int>,
result<std::vector<std::string>>,
result<std::string>,
result<int>
>
> resp;

char const* wire = "*4\r\n:1\r\n~0\r\n$25\r\nthis_should_not_be_in_set\r\n:2\r\n";

deserialize(wire, adapt2(resp));

BOOST_CHECK_EQUAL(std::get<0>(resp.value()).value(), 1);
BOOST_CHECK(std::get<1>(resp.value()).value().empty());
BOOST_CHECK_EQUAL(std::get<2>(resp.value()).value(), "this_should_not_be_in_set");
BOOST_CHECK_EQUAL(std::get<3>(resp.value()).value(), 2);

} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE);
}
}

BOOST_AUTO_TEST_CASE(issue_210_non_empty_set_size_one)
{
try {
result<
std::tuple<
result<int>,
result<std::vector<std::string>>,
result<std::string>,
result<int>
>
> resp;

char const* wire = "*4\r\n:1\r\n~1\r\n$3\r\nfoo\r\n$25\r\nthis_should_not_be_in_set\r\n:2\r\n";

deserialize(wire, adapt2(resp));

BOOST_CHECK_EQUAL(std::get<0>(resp.value()).value(), 1);
BOOST_CHECK_EQUAL(std::get<1>(resp.value()).value().size(), 1);
BOOST_CHECK_EQUAL(std::get<1>(resp.value()).value().at(0), std::string{"foo"});
BOOST_CHECK_EQUAL(std::get<2>(resp.value()).value(), "this_should_not_be_in_set");
BOOST_CHECK_EQUAL(std::get<3>(resp.value()).value(), 2);

} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE);
}
}

BOOST_AUTO_TEST_CASE(issue_210_non_empty_set_size_two)
{
try {
result<
std::tuple<
result<int>,
result<std::vector<std::string>>,
result<std::string>,
result<int>
>
> resp;

char const* wire = "*4\r\n:1\r\n~2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$25\r\nthis_should_not_be_in_set\r\n:2\r\n";

deserialize(wire, adapt2(resp));

BOOST_CHECK_EQUAL(std::get<0>(resp.value()).value(), 1);
BOOST_CHECK_EQUAL(std::get<1>(resp.value()).value().at(0), std::string{"foo"});
BOOST_CHECK_EQUAL(std::get<1>(resp.value()).value().at(1), std::string{"bar"});
BOOST_CHECK_EQUAL(std::get<2>(resp.value()).value(), "this_should_not_be_in_set");

} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE);
}
}

BOOST_AUTO_TEST_CASE(issue_210_no_nested)
{
try {
result<
std::tuple<
result<int>,
result<std::string>,
result<std::string>,
result<std::string>
>
> resp;

char const* wire = "*4\r\n:1\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$25\r\nthis_should_not_be_in_set\r\n";

deserialize(wire, adapt2(resp));

BOOST_CHECK_EQUAL(std::get<0>(resp.value()).value(), 1);
BOOST_CHECK_EQUAL(std::get<1>(resp.value()).value(), std::string{"foo"});
BOOST_CHECK_EQUAL(std::get<2>(resp.value()).value(), std::string{"bar"});
BOOST_CHECK_EQUAL(std::get<3>(resp.value()).value(), "this_should_not_be_in_set");

} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE);
}
}

0 comments on commit 0acca49

Please sign in to comment.