2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-15 13:12:21 +00:00

Added binary deserialization error tests

This commit is contained in:
ruben
2020-05-04 20:21:28 +01:00
parent ee095a6af0
commit aadd8213ad
6 changed files with 165 additions and 1 deletions

View File

@@ -7,9 +7,14 @@ Sanitize
Refactor binary deserialization constants
Change text row to use parameterized tests
Refactor deserialize_binary_value to have similar implementation to the text one
Better resilience of deserialization
Make float inf and nan output NULL?
Lift range check on dates, datetimes, times
Make invalid dates and datetimes output NULL
Integ tests for zero and invalid dates
Complete DATETIME and TIME error tests
See if we have any trouble with user input in binary serialization: make assertions
Test with an unknown protocol type
Test zero dates
Random input tests
Better docs
Wandbox
@@ -27,6 +32,7 @@ Handshake
SSL certificate & common name validation
sha256_password
Usability
Operator<< and == for value and ADL
Should make_error_code be public?
Incomplete query reads: how does this affect further queries?
Metadata in rows: being able to index by name

View File

@@ -8,6 +8,8 @@
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_SERIALIZATION_HPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_SERIALIZATION_HPP
#include <cmath>
namespace boost {
namespace mysql {
namespace detail {
@@ -268,6 +270,8 @@ boost::mysql::detail::serialization_traits<
std::memcpy(&output, ctx.first(), sizeof(T));
#endif
ctx.advance(sizeof(T));
if (std::isnan(output) || std::isinf(output))
return errc::protocol_value_error;
return errc::ok;
}

View File

@@ -41,7 +41,13 @@ inline errc deserialize_binary_date(
// TODO: how does this handle zero dates?
::date::year_month_day ymd (::date::year(year.value), ::date::month(month.value), ::date::day(day.value));
if (!ymd.ok())
return errc::protocol_value_error;
output = date(ymd);
if (output < min_date || output > max_date)
return errc::protocol_value_error;
return errc::ok;
}

View File

@@ -36,6 +36,7 @@ add_executable(
unit/detail/protocol/text_deserialization_error.cpp
unit/detail/protocol/text_deserialization_row.cpp
unit/detail/protocol/binary_deserialization_value.cpp
unit/detail/protocol/binary_deserialization_error.cpp
unit/detail/protocol/binary_deserialization_row.cpp
unit/detail/protocol/null_bitmap_traits.cpp
unit/metadata.cpp

View File

@@ -0,0 +1,146 @@
//
// Copyright (c) 2019-2020 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test deserialize_binary_value(), only error cases
#include <gtest/gtest.h>
#include "boost/mysql/detail/protocol/binary_deserialization.hpp"
#include "test_common.hpp"
using namespace boost::mysql::detail;
using namespace boost::mysql::test;
using namespace testing;
using boost::mysql::value;
using boost::mysql::error_code;
using boost::mysql::errc;
namespace
{
struct err_binary_value_testcase : named_param
{
std::string name;
bytestring from;
protocol_field_type type;
std::uint16_t flags;
errc expected_err;
err_binary_value_testcase(std::string&& name, bytestring&& from, protocol_field_type type,
std::uint16_t flags=0, errc expected_err=errc::protocol_value_error) :
name(std::move(name)),
from(std::move(from)),
type(type),
flags(flags),
expected_err(expected_err)
{
}
err_binary_value_testcase(std::string&& name, bytestring&& from, protocol_field_type type,
errc expected_err) :
name(std::move(name)),
from(std::move(from)),
type(type),
flags(0),
expected_err(expected_err)
{
}
};
struct DeserializeBinaryValueErrorTest : TestWithParam<err_binary_value_testcase>
{
};
TEST_P(DeserializeBinaryValueErrorTest, Error_ReturnsExpectedErrc)
{
column_definition_packet coldef;
coldef.type = GetParam().type;
coldef.flags.value = GetParam().flags;
boost::mysql::field_metadata meta (coldef);
value actual_value;
const auto& buff = GetParam().from;
deserialization_context ctx (buff.data(), buff.data() + buff.size(), capabilities());
auto err = deserialize_binary_value(ctx, meta, actual_value);
auto expected = GetParam().expected_err;
EXPECT_EQ(expected, err)
<< "expected: " << error_to_string(expected) << ", actual: " << error_to_string(err);
}
std::vector<err_binary_value_testcase> make_int_cases(
protocol_field_type type,
unsigned num_bytes
)
{
return {
{ "signed_not_enough_space", bytestring(num_bytes, 0x0a),
type, errc::incomplete_message },
{ "unsigned_not_enough_space", bytestring(num_bytes, 0x0a),
type, column_flags::unsigned_, errc::incomplete_message }
};
}
INSTANTIATE_TEST_SUITE_P(TINY, DeserializeBinaryValueErrorTest, ValuesIn(
make_int_cases(protocol_field_type::tiny, 0)
), test_name_generator);
INSTANTIATE_TEST_SUITE_P(SMALLINT, DeserializeBinaryValueErrorTest, ValuesIn(
make_int_cases(protocol_field_type::short_, 1)
), test_name_generator);
INSTANTIATE_TEST_SUITE_P(MEDIUMINT, DeserializeBinaryValueErrorTest, ValuesIn(
make_int_cases(protocol_field_type::int24, 3)
), test_name_generator);
INSTANTIATE_TEST_SUITE_P(INT, DeserializeBinaryValueErrorTest, ValuesIn(
make_int_cases(protocol_field_type::long_, 3)
), test_name_generator);
INSTANTIATE_TEST_SUITE_P(BIGINT, DeserializeBinaryValueErrorTest, ValuesIn(
make_int_cases(protocol_field_type::longlong, 7)
), test_name_generator);
INSTANTIATE_TEST_SUITE_P(FLOAT, DeserializeBinaryValueErrorTest, Values(
err_binary_value_testcase("not_enough_space", {0x01, 0x02, 0x03},
protocol_field_type::float_, errc::incomplete_message),
err_binary_value_testcase("inf", {0x00, 0x00, 0x80, 0x7f},
protocol_field_type::float_),
err_binary_value_testcase("minus_inf", {0x00, 0x00, 0x80, 0xff},
protocol_field_type::float_),
err_binary_value_testcase("nan", {0xff, 0xff, 0xff, 0x7f},
protocol_field_type::float_),
err_binary_value_testcase("minus_nan", {0xff, 0xff, 0xff, 0xff},
protocol_field_type::float_)
), test_name_generator);
INSTANTIATE_TEST_SUITE_P(DOUBLE, DeserializeBinaryValueErrorTest, Values(
err_binary_value_testcase("not_enough_space", {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07},
protocol_field_type::double_, errc::incomplete_message),
err_binary_value_testcase("inf", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f},
protocol_field_type::double_),
err_binary_value_testcase("minus_inf", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff},
protocol_field_type::double_),
err_binary_value_testcase("nan", {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},
protocol_field_type::double_),
err_binary_value_testcase("minus_nan", {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
protocol_field_type::double_)
), test_name_generator);
INSTANTIATE_TEST_SUITE_P(DATE, DeserializeBinaryValueErrorTest, Values(
err_binary_value_testcase("empty", {}, protocol_field_type::date, errc::incomplete_message),
err_binary_value_testcase("incomplete_year", {0x04, 0xff},
protocol_field_type::date, errc::incomplete_message),
err_binary_value_testcase("year_gt_max", {0x04, 0x10, 0x27, 0x03, 0x1c}, // year 10000
protocol_field_type::date),
err_binary_value_testcase("year_lt_min", {0x04, 0x63, 0x00, 0x03, 0x1c}, // year 99
protocol_field_type::date)
));
INSTANTIATE_TEST_SUITE_P(YEAR, DeserializeBinaryValueErrorTest, ValuesIn(
make_int_cases(protocol_field_type::year, 1)
), test_name_generator);
} // anon namespace

View File

@@ -64,6 +64,7 @@ TEST_P(DeserializeBinaryValueTest, CorrectFormat_SetsOutputValueReturnsTrue)
auto err = deserialize_binary_value(ctx, meta, actual_value);
EXPECT_EQ(err, errc::ok);
EXPECT_EQ(actual_value, GetParam().expected);
EXPECT_EQ(ctx.first(), buffer.data() + buffer.size()); // all bytes consumed
}
INSTANTIATE_TEST_SUITE_P(StringTypes, DeserializeBinaryValueTest, Values(