2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-16 13:32:15 +00:00
Files
mysql/test/unit/detail/protocol/binary_deserialization_error.cpp
ruben f5a17cdf7e Now text protocol supports invalid dates
Changed text protocol to support invalid dates and datetimes
Added tests
Now months greater than 12, days greater than 31, years greater than
9999 are always rejected
2020-05-11 13:21:29 +01:00

260 lines
12 KiB
C++

//
// 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);
// Based on correct, regular date {0x04, 0xda, 0x07, 0x03, 0x1c}
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, 0xda},
protocol_field_type::date, errc::incomplete_message),
err_binary_value_testcase("no_month_day", {0x04, 0xda, 0x07},
protocol_field_type::date, errc::incomplete_message),
err_binary_value_testcase("no_day", {0x04, 0xda, 0x07, 0x03},
protocol_field_type::date, errc::incomplete_message),
err_binary_value_testcase("invalid_year", {0x04, 0x10, 0x27, 0x03, 0x1c}, // year 10000
protocol_field_type::date),
err_binary_value_testcase("invalid_year_max", {0x04, 0xff, 0xff, 0x03, 0x1c},
protocol_field_type::date),
err_binary_value_testcase("invalid_month", {0x04, 0xda, 0x07, 13, 0x1c},
protocol_field_type::date),
err_binary_value_testcase("invalid_month_max", {0x04, 0xda, 0x07, 0xff, 0x1c},
protocol_field_type::date),
err_binary_value_testcase("invalid_day", {0x04, 0xda, 0x07, 0x03, 32},
protocol_field_type::date),
err_binary_value_testcase("invalid_day_max", {0x04, 0xda, 0x07, 0x03, 0xff},
protocol_field_type::date),
err_binary_value_testcase("protocol_max", {0xff, 0xff, 0xff, 0xff, 0xff},
protocol_field_type::date)
));
// Based on correct datetime {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}
std::vector<err_binary_value_testcase> make_datetime_cases(
protocol_field_type type
)
{
return {
{ "empty", {}, type, errc::incomplete_message },
{ "incomplete_date", {0x04, 0xda, 0x07, 0x01}, type, errc::incomplete_message },
{ "no_hours_mins_secs", {0x07, 0xda, 0x07, 0x01, 0x01}, type, errc::incomplete_message },
{ "no_mins_secs", {0x07, 0xda, 0x07, 0x01, 0x01, 0x17}, type, errc::incomplete_message },
{ "no_secs", {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01}, type, errc::incomplete_message },
{ "incomplete_micros", {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e},
type, errc::incomplete_message },
{ "invalid_year_d", {0x04, 0x10, 0x27, 0x01, 0x01}, type }, // year 10000
{ "invalid_year_hms", {0x07, 0x10, 0x27, 0x01, 0x01, 0x17, 0x01, 0x3b}, type },
{ "invalid_year_hmsu", {0x0b, 0x10, 0x27, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_year_max_hmsu", {0x0b, 0xff, 0xff, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_hour_hms", {0x07, 0xda, 0x07, 0x01, 0x01, 24, 0x01, 0x3b}, type },
{ "invalid_hour_hmsu", {0x0b, 0xda, 0x07, 0x01, 0x01, 24, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_hour_max_hmsu", {0x0b, 0xda, 0x07, 0x01, 0x01, 0xff, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_min_hms", {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 60, 0x3b}, type },
{ "invalid_min_hmsu", {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 60, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_min_max_hmsu", {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0xff, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_sec_hms", {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 60}, type },
{ "invalid_sec_hmsu", {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 60, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_sec_max_hmsu", {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0xff, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_micro_hmsu", {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x40, 0x42, 0xf4, 0x00}, type }, // 1M
{ "invalid_micro_max_hmsu", {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0xff, 0xff, 0xff, 0xff}, type },
{ "invalid_hour_invalid_date", {0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_min_invalid_date", {0x0b, 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_sec_invalid_date", {0x0b, 0x00, 0x00, 0x00, 0x00, 0x17, 0x01, 0xff, 0x56, 0xc3, 0x0e, 0x00}, type },
{ "invalid_micro_invalid_date", {0x0b, 0x00, 0x00, 0x00, 0x00, 0x17, 0x01, 0x3b, 0xff, 0xff, 0xff, 0xff}, type },
{ "protocol_max", {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, type }
};
}
INSTANTIATE_TEST_SUITE_P(DATETIME, DeserializeBinaryValueErrorTest, ValuesIn(
make_datetime_cases(protocol_field_type::datetime)
), test_name_generator);
INSTANTIATE_TEST_SUITE_P(TIMESTAMP, DeserializeBinaryValueErrorTest, ValuesIn(
make_datetime_cases(protocol_field_type::timestamp)
), test_name_generator);
std::vector<err_binary_value_testcase> make_time_cases()
{
constexpr auto type = protocol_field_type::time;
std::vector<err_binary_value_testcase> res {
{ "empty", {},
type, errc::incomplete_message },
{ "no_sign_days_hours_mins_secs", {0x08},
type, errc::incomplete_message },
{ "no_days_hours_mins_secs", {0x08, 0x01},
type, errc::incomplete_message },
{ "no_hours_mins_secs", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00},
type, errc::incomplete_message },
{ "no_mins_secs", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16},
type, errc::incomplete_message },
{ "no_secs", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b},
type, errc::incomplete_message },
{ "no_micros", {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a},
type, errc::incomplete_message },
};
std::pair<const char*, std::vector<std::uint8_t>> out_of_range_cases [] {
{ "invalid_days", {0x08, 0x00, 35, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a} },
{ "invalid_days_max", {0x08, 0x00, 0xff, 0xff, 0xff, 0xff, 0x16, 0x3b, 0x3a} },
{ "invalid_hours", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 24, 0x3b, 0x3a} },
{ "invalid_hours_max", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0xff, 0x3b, 0x3a} },
{ "invalid_mins", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 60, 0x3a} },
{ "invalid_mins_max", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0xff, 0x3a} },
{ "invalid_secs", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 60} },
{ "invalid_secs_max", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0xff} },
{ "invalid_micros", {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x40, 0x42, 0xf4, 0x00} },
{ "invalid_micros_max", {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0xff, 0xff, 0xff, 0xff} },
};
for (auto& c: out_of_range_cases)
{
// Positive
c.second[1] = 0x00;
res.emplace_back(c.first + std::string("_positive"), bytestring(c.second), type);
// Negative
c.second[1] = 0x01;
res.emplace_back(c.first + std::string("_negative"), std::move(c.second), type);
}
return res;
}
// 0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a
// 0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00
INSTANTIATE_TEST_SUITE_P(TIME, DeserializeBinaryValueErrorTest, ValuesIn(
make_time_cases()
), test_name_generator);
INSTANTIATE_TEST_SUITE_P(YEAR, DeserializeBinaryValueErrorTest, ValuesIn(
make_int_cases(protocol_field_type::year, 1)
), test_name_generator);
} // anon namespace