mirror of
https://github.com/boostorg/redis.git
synced 2026-01-19 04:42:09 +00:00
Fixes the adapter of empty nested responses.
See https://github.com/boostorg/redis/issues/210.
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -102,8 +102,12 @@ private:
|
||||
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;
|
||||
|
||||
@@ -117,36 +121,35 @@ public:
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user