mirror of
https://github.com/boostorg/mysql.git
synced 2026-02-15 13:12:21 +00:00
Improved text deserializ error handling
Added more tests for text deserialization Corrected some previous tests Added code to handle some corner cases more gracefully Refactored
This commit is contained in:
9
TODO.txt
9
TODO.txt
@@ -1,5 +1,13 @@
|
||||
Sanitize
|
||||
Test zero dates
|
||||
Refactor text deserialization constants
|
||||
Add text deserialization error tests
|
||||
Refactor binary deserialization constants
|
||||
Add binary deserialization error tests
|
||||
Float: nan, inf, signalling nan
|
||||
See if we have any trouble with user input in binary serialization
|
||||
Test with an unknown protocol type
|
||||
Random input tests
|
||||
Better docs
|
||||
Wandbox
|
||||
Breaking up the tutorial in pieces
|
||||
@@ -38,7 +46,6 @@ Other possible features
|
||||
Status flags accessors in resultset (for OK_Packet)
|
||||
Technical debt
|
||||
Change channel read to make less syscalls
|
||||
Random input tests
|
||||
Test dashboard
|
||||
Sanitizers
|
||||
Integ tests for different default auth plugins
|
||||
|
||||
@@ -17,25 +17,71 @@ namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
// Text protocol deserialization constants
|
||||
namespace textc {
|
||||
|
||||
constexpr unsigned max_decimals = 6u;
|
||||
|
||||
constexpr std::size_t year_sz = 4;
|
||||
constexpr std::size_t month_sz = 2;
|
||||
constexpr std::size_t day_sz = 2;
|
||||
constexpr std::size_t hours_min_sz = 2; // in TIME, it may be longer
|
||||
constexpr std::size_t mins_sz = 2;
|
||||
constexpr std::size_t secs_sz = 2;
|
||||
|
||||
constexpr std::size_t date_sz = year_sz + month_sz + day_sz + 2; // delimiters
|
||||
constexpr std::size_t time_min_sz = hours_min_sz + mins_sz + secs_sz + 2; // delimiters
|
||||
constexpr std::size_t time_max_sz = time_min_sz + max_decimals + 3; // sign, period, hour extra character
|
||||
constexpr std::size_t datetime_min_sz = date_sz + time_min_sz + 1; // delimiter
|
||||
|
||||
constexpr unsigned max_hour = 838;
|
||||
constexpr unsigned max_min = 59;
|
||||
constexpr unsigned max_sec = 59;
|
||||
constexpr unsigned max_micro = 999999;
|
||||
|
||||
} // textc
|
||||
|
||||
inline unsigned sanitize_decimals(unsigned decimals)
|
||||
{
|
||||
return std::min(decimals, textc::max_decimals);
|
||||
}
|
||||
|
||||
// Computes the meaning of the parsed microsecond number, taking into
|
||||
// account decimals (85 with 2 decimals means 850000us)
|
||||
inline unsigned compute_micros(unsigned parsed_micros, unsigned decimals)
|
||||
{
|
||||
return parsed_micros * static_cast<unsigned>(std::pow(10, textc::max_decimals - decimals));
|
||||
}
|
||||
|
||||
inline errc deserialize_text_value_impl(
|
||||
std::string_view from,
|
||||
date& to
|
||||
)
|
||||
{
|
||||
constexpr std::size_t size = 4 + 2 + 2 + 2; // year, month, day, separators
|
||||
if (from.size() != size)
|
||||
// Size check
|
||||
if (from.size() != textc::date_sz)
|
||||
return errc::protocol_value_error;
|
||||
unsigned year, month, day;
|
||||
char buffer [size + 1] {};
|
||||
|
||||
// Copy to a NULL-terminated buffer
|
||||
char buffer [textc::date_sz + 1] {};
|
||||
memcpy(buffer, from.data(), from.size());
|
||||
|
||||
// Parse individual components
|
||||
unsigned year, month, day;
|
||||
int parsed = sscanf(buffer, "%4u-%2u-%2u", &year, &month, &day);
|
||||
if (parsed != 3)
|
||||
return errc::protocol_value_error;
|
||||
|
||||
// Verify date validity
|
||||
::date::year_month_day result (::date::year(year)/::date::month(month)/::date::day(day));
|
||||
if (!result.ok())
|
||||
return errc::protocol_value_error;
|
||||
|
||||
// Range check
|
||||
if (result > max_date || result < min_date)
|
||||
return errc::protocol_value_error;
|
||||
|
||||
// Done
|
||||
to = result;
|
||||
return errc::ok;
|
||||
}
|
||||
@@ -46,28 +92,46 @@ inline errc deserialize_text_value_impl(
|
||||
unsigned decimals
|
||||
)
|
||||
{
|
||||
using namespace textc;
|
||||
|
||||
// Adjust decimals
|
||||
decimals = sanitize_decimals(decimals);
|
||||
|
||||
// size check
|
||||
constexpr std::size_t min_size = 2 + 2 + 2 + 2; // hours, mins, seconds, no micros
|
||||
constexpr std::size_t max_size = min_size + 1 + 1 + 7; // hour extra character, sign and micros
|
||||
decimals = std::min(decimals, 6u);
|
||||
if (from.size() < min_size || from.size() > max_size)
|
||||
std::size_t actual_min_size = time_min_sz + (decimals ? decimals + 1 : 0);
|
||||
std::size_t actual_max_size = actual_min_size + 1 + 1; // hour extra character and sign
|
||||
assert(actual_max_size <= time_max_sz);
|
||||
if (from.size() < actual_min_size || from.size() > actual_max_size)
|
||||
return errc::protocol_value_error;
|
||||
|
||||
// Copy to NULL-terminated buffer
|
||||
char buffer [time_max_sz + 1] {};
|
||||
memcpy(buffer, from.data(), from.size());
|
||||
|
||||
// Sign
|
||||
bool is_negative = from[0] == '-';
|
||||
const char* first = is_negative ? buffer + 1 : buffer;
|
||||
|
||||
// Parse it
|
||||
int hours;
|
||||
unsigned minutes, seconds, micros = 0;
|
||||
char buffer [max_size + 1] {};
|
||||
memcpy(buffer, from.data(), from.size());
|
||||
int parsed = decimals ? sscanf(buffer, "%4d:%2u:%2u.%6u", &hours, &minutes, &seconds, µs) : // sign adds 1 char
|
||||
sscanf(buffer, "%4d:%2u:%2u", &hours, &minutes, &seconds);
|
||||
if ((decimals && parsed != 4) || (!decimals && parsed != 3))
|
||||
return errc::protocol_value_error;
|
||||
micros *= static_cast<unsigned>(std::pow(10, 6 - decimals));
|
||||
hours = std::abs(hours);
|
||||
bool is_negative = from[0] == '-';
|
||||
unsigned hours, minutes, seconds;
|
||||
unsigned micros = 0;
|
||||
char extra_char;
|
||||
if (decimals)
|
||||
{
|
||||
int parsed = sscanf(first, "%3u:%2u:%2u.%6u%c", &hours, &minutes, &seconds, µs, &extra_char);
|
||||
if (parsed != 4)
|
||||
return errc::protocol_value_error;
|
||||
micros = compute_micros(micros, decimals);
|
||||
}
|
||||
else
|
||||
{
|
||||
int parsed = sscanf(first, "%3u:%2u:%2u%c", &hours, &minutes, &seconds, &extra_char);
|
||||
if (parsed != 3)
|
||||
return errc::protocol_value_error;
|
||||
}
|
||||
|
||||
// Range check for minutes and seconds (hours may be greater than 24)
|
||||
if (minutes >= 60 || seconds >= 60)
|
||||
// Range check
|
||||
if (hours > max_hour || minutes > max_min || seconds > max_sec || micros > max_micro)
|
||||
return errc::protocol_value_error;
|
||||
|
||||
// Sum it
|
||||
@@ -78,10 +142,7 @@ inline errc deserialize_text_value_impl(
|
||||
res = -res;
|
||||
}
|
||||
|
||||
// Range check
|
||||
if (res > max_time || res < min_time)
|
||||
return errc::protocol_value_error;
|
||||
|
||||
// Done
|
||||
to = res;
|
||||
return errc::ok;
|
||||
}
|
||||
@@ -92,30 +153,35 @@ inline errc deserialize_text_value_impl(
|
||||
unsigned decimals
|
||||
)
|
||||
{
|
||||
using namespace textc;
|
||||
|
||||
// Sanitize decimals
|
||||
decimals = sanitize_decimals(decimals);
|
||||
|
||||
// Length check
|
||||
constexpr std::size_t min_size = 4 + 5*2 + 5; // year, month, day, hour, minute, seconds, separators
|
||||
decimals = std::min(decimals, 6u);
|
||||
std::size_t expected_size = min_size + (decimals ? decimals + 1 : 0);
|
||||
std::size_t expected_size = datetime_min_sz + (decimals ? decimals + 1 : 0);
|
||||
if (from.size() != expected_size)
|
||||
return errc::protocol_value_error;
|
||||
|
||||
// Date part
|
||||
date dt;
|
||||
auto err = deserialize_text_value_impl(from.substr(0, 10), dt);
|
||||
// Parse date
|
||||
date d;
|
||||
auto err = deserialize_text_value_impl(from.substr(0, date_sz), d);
|
||||
if (err != errc::ok)
|
||||
return err;
|
||||
|
||||
// Time of day part
|
||||
time time_of_day;
|
||||
err = deserialize_text_value_impl(from.substr(11), time_of_day, decimals);
|
||||
err = deserialize_text_value_impl(from.substr(date_sz + 1), time_of_day, decimals);
|
||||
if (err != errc::ok)
|
||||
return err;
|
||||
|
||||
// Range check
|
||||
constexpr auto max_time_of_day = std::chrono::hours(24) - std::chrono::microseconds(1);
|
||||
if (time_of_day < std::chrono::seconds(0) || time_of_day > max_time_of_day)
|
||||
return errc::protocol_value_error;
|
||||
|
||||
// Sum it up
|
||||
to = dt + time_of_day;
|
||||
to = d + time_of_day;
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
@@ -141,30 +207,16 @@ inline errc deserialize_text_value_impl(std::string_view from, std::string_view&
|
||||
template <typename T, typename... Args>
|
||||
errc deserialize_text_value_to_variant(std::string_view from, value& to, Args&&... args)
|
||||
{
|
||||
T value;
|
||||
auto err = deserialize_text_value_impl(from, value, std::forward<Args>(args)...);
|
||||
if (err == errc::ok)
|
||||
{
|
||||
to = value;
|
||||
}
|
||||
return err;
|
||||
return deserialize_text_value_impl(from, to.emplace<T>(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline bool is_next_field_null(
|
||||
deserialization_context& ctx
|
||||
const deserialization_context& ctx
|
||||
)
|
||||
{
|
||||
int1 type_byte;
|
||||
errc err = deserialize(type_byte, ctx);
|
||||
if (err == errc::ok)
|
||||
{
|
||||
if (type_byte.value == 0xfb)
|
||||
{
|
||||
return true; // it was null, do not rewind
|
||||
}
|
||||
ctx.rewind(1); // it was not null, rewind (this byte is part of the actual message)
|
||||
}
|
||||
return false;
|
||||
if (!ctx.enough_size(1))
|
||||
return false;
|
||||
return *ctx.first() == 0xfb;
|
||||
}
|
||||
|
||||
} // detail
|
||||
@@ -232,9 +284,9 @@ boost::mysql::error_code boost::mysql::detail::deserialize_text_row(
|
||||
output.resize(fields.size());
|
||||
for (std::vector<value>::size_type i = 0; i < fields.size(); ++i)
|
||||
{
|
||||
bool is_null = is_next_field_null(ctx);
|
||||
if (is_null)
|
||||
if (is_next_field_null(ctx))
|
||||
{
|
||||
ctx.advance(1);
|
||||
output[i] = nullptr;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -216,10 +216,13 @@ INSTANTIATE_TEST_SUITE_P(DATETIME, DeserializeTextValueTest, Values(
|
||||
text_value_testcase("6_decimals_hms", "2010-02-15 02:05:30.000000", makedt(2010, 2, 15, 2, 5, 30), protocol_field_type::datetime, 0, 6),
|
||||
text_value_testcase("6_decimals_hmsu", "2010-02-15 02:05:30.002395", makedt(2010, 2, 15, 2, 5, 30, 2395), protocol_field_type::datetime, 0, 6),
|
||||
text_value_testcase("6_decimals_min", "1000-01-01 00:00:00.000000", makedt(1000, 1, 1), protocol_field_type::datetime, 0, 6),
|
||||
text_value_testcase("6_decimals_max", "9999-12-31 23:59:59.999999", makedt(9999, 12, 31, 23, 59, 59, 999999), protocol_field_type::datetime, 0, 6)
|
||||
text_value_testcase("6_decimals_max", "9999-12-31 23:59:59.999999", makedt(9999, 12, 31, 23, 59, 59, 999999), protocol_field_type::datetime, 0, 6),
|
||||
|
||||
// not a real case, we cap decimals to 6
|
||||
text_value_testcase("7_decimals", "2010-02-15 02:05:30.002395", makedt(2010, 2, 15, 2, 5, 30, 2395), protocol_field_type::datetime, 0, 7)
|
||||
), test_name_generator);
|
||||
|
||||
// Right now, timestamps are deserialized as DATETIMEs. TODO: update this when we consider time zones
|
||||
// Right now, timestamps are deserialized as DATETIMEs
|
||||
INSTANTIATE_TEST_SUITE_P(TIMESTAMP, DeserializeTextValueTest, Values(
|
||||
text_value_testcase("0_decimals", "2010-02-15 02:05:30", makedt(2010, 2, 15, 2, 5, 30), protocol_field_type::timestamp),
|
||||
text_value_testcase("6_decimals", "2010-02-15 02:05:30.085670", makedt(2010, 2, 15, 2, 5, 30, 85670), protocol_field_type::timestamp, 0, 6),
|
||||
@@ -237,6 +240,7 @@ INSTANTIATE_TEST_SUITE_P(TIME, DeserializeTextValueTest, Values(
|
||||
text_value_testcase("0_decimals_negative_hms", "-14:51:23", -maket(14, 51, 23), protocol_field_type::time),
|
||||
text_value_testcase("0_decimals_min", "-838:59:59", -maket(838, 59, 59), protocol_field_type::time),
|
||||
text_value_testcase("0_decimals_zero", "00:00:00", maket(0, 0, 0), protocol_field_type::time),
|
||||
text_value_testcase("0_decimals_negative_h0", "-00:51:23", -maket(0, 51, 23), protocol_field_type::time),
|
||||
|
||||
text_value_testcase("1_decimals_positive_hms", "14:51:23.0", maket(14, 51, 23), protocol_field_type::time, 0, 1),
|
||||
text_value_testcase("1_decimals_positive_hmsu", "14:51:23.5", maket(14, 51, 23, 500000), protocol_field_type::time, 0, 1),
|
||||
@@ -245,6 +249,7 @@ INSTANTIATE_TEST_SUITE_P(TIME, DeserializeTextValueTest, Values(
|
||||
text_value_testcase("1_decimals_negative_hmsu", "-14:51:23.5", -maket(14, 51, 23, 500000), protocol_field_type::time, 0, 1),
|
||||
text_value_testcase("1_decimals_min", "-838:59:58.9", -maket(838, 59, 58, 900000), protocol_field_type::time, 0, 1),
|
||||
text_value_testcase("1_decimals_zero", "00:00:00.0", maket(0, 0, 0), protocol_field_type::time, 0, 1),
|
||||
text_value_testcase("1_decimals_negative_h0", "-00:51:23.1", -maket(0, 51, 23, 100000), protocol_field_type::time, 0, 1),
|
||||
|
||||
text_value_testcase("2_decimals_positive_hms", "14:51:23.00", maket(14, 51, 23), protocol_field_type::time, 0, 2),
|
||||
text_value_testcase("2_decimals_positive_hmsu", "14:51:23.52", maket(14, 51, 23, 520000), protocol_field_type::time, 0, 2),
|
||||
@@ -253,6 +258,7 @@ INSTANTIATE_TEST_SUITE_P(TIME, DeserializeTextValueTest, Values(
|
||||
text_value_testcase("2_decimals_negative_hmsu", "-14:51:23.50", -maket(14, 51, 23, 500000), protocol_field_type::time, 0, 2),
|
||||
text_value_testcase("2_decimals_min", "-838:59:58.99", -maket(838, 59, 58, 990000), protocol_field_type::time, 0, 2),
|
||||
text_value_testcase("2_decimals_zero", "00:00:00.00", maket(0, 0, 0), protocol_field_type::time, 0, 2),
|
||||
text_value_testcase("2_decimals_negative_h0", "-00:51:23.12", -maket(0, 51, 23, 120000), protocol_field_type::time, 0, 2),
|
||||
|
||||
text_value_testcase("3_decimals_positive_hms", "14:51:23.000", maket(14, 51, 23), protocol_field_type::time, 0, 3),
|
||||
text_value_testcase("3_decimals_positive_hmsu", "14:51:23.501", maket(14, 51, 23, 501000), protocol_field_type::time, 0, 3),
|
||||
@@ -261,6 +267,7 @@ INSTANTIATE_TEST_SUITE_P(TIME, DeserializeTextValueTest, Values(
|
||||
text_value_testcase("3_decimals_negative_hmsu", "-14:51:23.003", -maket(14, 51, 23, 3000), protocol_field_type::time, 0, 3),
|
||||
text_value_testcase("3_decimals_min", "-838:59:58.999", -maket(838, 59, 58, 999000), protocol_field_type::time, 0, 3),
|
||||
text_value_testcase("3_decimals_zero", "00:00:00.000", maket(0, 0, 0), protocol_field_type::time, 0, 3),
|
||||
text_value_testcase("3_decimals_negative_h0", "-00:51:23.123", -maket(0, 51, 23, 123000), protocol_field_type::time, 0, 3),
|
||||
|
||||
text_value_testcase("4_decimals_positive_hms", "14:51:23.0000", maket(14, 51, 23), protocol_field_type::time, 0, 4),
|
||||
text_value_testcase("4_decimals_positive_hmsu", "14:51:23.5017", maket(14, 51, 23, 501700), protocol_field_type::time, 0, 4),
|
||||
@@ -269,6 +276,7 @@ INSTANTIATE_TEST_SUITE_P(TIME, DeserializeTextValueTest, Values(
|
||||
text_value_testcase("4_decimals_negative_hmsu", "-14:51:23.0038", -maket(14, 51, 23, 3800), protocol_field_type::time, 0, 4),
|
||||
text_value_testcase("4_decimals_min", "-838:59:58.9999", -maket(838, 59, 58, 999900), protocol_field_type::time, 0, 4),
|
||||
text_value_testcase("4_decimals_zero", "00:00:00.0000", maket(0, 0, 0), protocol_field_type::time, 0, 4),
|
||||
text_value_testcase("4_decimals_negative_h0", "-00:51:23.1234", -maket(0, 51, 23, 123400), protocol_field_type::time, 0, 4),
|
||||
|
||||
text_value_testcase("5_decimals_positive_hms", "14:51:23.00000", maket(14, 51, 23), protocol_field_type::time, 0, 5),
|
||||
text_value_testcase("5_decimals_positive_hmsu", "14:51:23.50171", maket(14, 51, 23, 501710), protocol_field_type::time, 0, 5),
|
||||
@@ -277,6 +285,7 @@ INSTANTIATE_TEST_SUITE_P(TIME, DeserializeTextValueTest, Values(
|
||||
text_value_testcase("5_decimals_negative_hmsu", "-14:51:23.00009", -maket(14, 51, 23, 90), protocol_field_type::time, 0, 5),
|
||||
text_value_testcase("5_decimals_min", "-838:59:58.99999", -maket(838, 59, 58, 999990), protocol_field_type::time, 0, 5),
|
||||
text_value_testcase("5_decimals_zero", "00:00:00.00000", maket(0, 0, 0), protocol_field_type::time, 0, 5),
|
||||
text_value_testcase("5_decimals_negative_h0", "-00:51:23.12345", -maket(0, 51, 23, 123450), protocol_field_type::time, 0, 5),
|
||||
|
||||
text_value_testcase("6_decimals_positive_hms", "14:51:23.000000", maket(14, 51, 23), protocol_field_type::time, 0, 6),
|
||||
text_value_testcase("6_decimals_positive_hmsu", "14:51:23.501717", maket(14, 51, 23, 501717), protocol_field_type::time, 0, 6),
|
||||
@@ -285,6 +294,7 @@ INSTANTIATE_TEST_SUITE_P(TIME, DeserializeTextValueTest, Values(
|
||||
text_value_testcase("6_decimals_negative_hmsu", "-14:51:23.900000", -maket(14, 51, 23, 900000), protocol_field_type::time, 0, 6),
|
||||
text_value_testcase("6_decimals_min", "-838:59:58.999999", -maket(838, 59, 58, 999999), protocol_field_type::time, 0, 6),
|
||||
text_value_testcase("6_decimals_zero", "00:00:00.000000", maket(0, 0, 0), protocol_field_type::time, 0, 6),
|
||||
text_value_testcase("6_decimals_negative_h0", "-00:51:23.123456", -maket(0, 51, 23, 123456), protocol_field_type::time, 0, 6),
|
||||
|
||||
// This is not a real case - we cap anything above 6 decimals to 6
|
||||
text_value_testcase("7_decimals", "14:51:23.501717", maket(14, 51, 23, 501717), protocol_field_type::time, 0, 7)
|
||||
@@ -303,17 +313,17 @@ struct err_text_value_testcase : named_param
|
||||
std::string name;
|
||||
std::string_view from;
|
||||
protocol_field_type type;
|
||||
unsigned decimals;
|
||||
std::uint16_t flags;
|
||||
unsigned decimals;
|
||||
errc expected_err;
|
||||
|
||||
err_text_value_testcase(std::string&& name, std::string_view from, protocol_field_type type,
|
||||
unsigned decimals=0, std::uint16_t flags=0, errc expected_err=errc::protocol_value_error) :
|
||||
std::uint16_t flags=0, unsigned decimals=0, errc expected_err=errc::protocol_value_error) :
|
||||
name(std::move(name)),
|
||||
from(from),
|
||||
type(type),
|
||||
decimals(decimals),
|
||||
flags(flags),
|
||||
decimals(decimals),
|
||||
expected_err(expected_err)
|
||||
{
|
||||
}
|
||||
@@ -369,7 +379,7 @@ std::vector<err_text_value_testcase> make_int32_err_cases(
|
||||
{
|
||||
// Unsigned integers behaviour for negative inputs are determined by what iostreams
|
||||
// do (accepting it and overflowing)
|
||||
return make_int_err_cases(t, "-2147483649", "2147483648", "-2147483649", "4294967296");
|
||||
return make_int_err_cases(t, "-2147483649", "2147483648", "-4294967296", "4294967296");
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(TINYINT, DeserializeTextValueErrorTest, ValuesIn(
|
||||
@@ -398,7 +408,7 @@ std::vector<err_text_value_testcase> make_int64_err_cases(
|
||||
t,
|
||||
"-9223372036854775809",
|
||||
"9223372036854775808",
|
||||
"-9223372036854775809",
|
||||
"-18446744073709551616",
|
||||
"18446744073709551616"
|
||||
);
|
||||
}
|
||||
@@ -479,6 +489,13 @@ std::vector<err_text_value_testcase> make_datetime_err_cases(
|
||||
err_text_value_testcase("no_decimals_4", "2020-05-02 23:01:00 ", t, 0, 4),
|
||||
err_text_value_testcase("no_decimals_5", "2020-05-02 23:01:00 ", t, 0, 5),
|
||||
err_text_value_testcase("no_decimals_6", "2020-05-02 23:01:00 ", t, 0, 6),
|
||||
err_text_value_testcase("trailing_0", "2020-05-02 23:01:0p", t, 0, 0),
|
||||
err_text_value_testcase("trailing_1", "2020-05-02 23:01:00.p", t, 0, 1),
|
||||
err_text_value_testcase("trailing_2", "2020-05-02 23:01:00.1p", t, 0, 2),
|
||||
err_text_value_testcase("trailing_3", "2020-05-02 23:01:00.12p", t, 0, 3),
|
||||
err_text_value_testcase("trailing_4", "2020-05-02 23:01:00.123p", t, 0, 4),
|
||||
err_text_value_testcase("trailing_5", "2020-05-02 23:01:00.1234p", t, 0, 5),
|
||||
err_text_value_testcase("trailing_6", "2020-05-02 23:01:00.12345p", t, 0, 6),
|
||||
err_text_value_testcase("bad_delimiter", "2020-05-02 23-01-00", t),
|
||||
err_text_value_testcase("missing_1gp_0", "2020-05-02 23:01: ", t),
|
||||
err_text_value_testcase("missing_2gp_0", "2020-05-02 23: ", t),
|
||||
@@ -490,11 +507,11 @@ std::vector<err_text_value_testcase> make_datetime_err_cases(
|
||||
err_text_value_testcase("invalid_hour2", "2020-05-02 240:2:20", t),
|
||||
err_text_value_testcase("negative_hour", "2020-05-02 -2:20:20", t),
|
||||
err_text_value_testcase("invalid_min", "2020-05-02 22:60:20", t),
|
||||
err_text_value_testcase("nagetive_min", "2020-05-02 22:-1:20", t),
|
||||
err_text_value_testcase("negative_min", "2020-05-02 22:-1:20", t),
|
||||
err_text_value_testcase("invalid_sec", "2020-05-02 22:06:60", t),
|
||||
err_text_value_testcase("nagetive_sec", "2020-05-02 22:06:-1", t),
|
||||
err_text_value_testcase("negative_sec", "2020-05-02 22:06:-1", t),
|
||||
err_text_value_testcase("negative_micro", "2020-05-02 22:06:01.-1", t, 0, 2),
|
||||
err_text_value_testcase("lt_min", "0900-01-01 00:00:00.00", t, 0, 2),
|
||||
err_text_value_testcase("lt_min", "0090-01-01 00:00:00.00", t, 0, 2),
|
||||
err_text_value_testcase("gt_max", "10000-01-01 00:00:00.00", t, 0, 2)
|
||||
};
|
||||
}
|
||||
@@ -509,6 +526,62 @@ INSTANTIATE_TEST_SUITE_P(TIMESTAMP, DeserializeTextValueErrorTest, ValuesIn(
|
||||
make_datetime_err_cases(protocol_field_type::timestamp)
|
||||
), test_name_generator);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(TIME, DeserializeTextValueErrorTest, Values(
|
||||
err_text_value_testcase("empty", "", protocol_field_type::time),
|
||||
err_text_value_testcase("not_numbers", "abjkjdb67", protocol_field_type::time),
|
||||
err_text_value_testcase("too_short_0", "1:20:20", protocol_field_type::time),
|
||||
err_text_value_testcase("too_short_1", "1:20:20.1", protocol_field_type::time, 0, 1),
|
||||
err_text_value_testcase("too_short_2", "01:20:20.1", protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("too_short_3", "01:20:20.12", protocol_field_type::time, 0, 3),
|
||||
err_text_value_testcase("too_short_4", "01:20:20.123", protocol_field_type::time, 0, 4),
|
||||
err_text_value_testcase("too_short_5", "01:20:20.1234", protocol_field_type::time, 0, 5),
|
||||
err_text_value_testcase("too_short_6", "01:20:20.12345", protocol_field_type::time, 0, 6),
|
||||
err_text_value_testcase("too_long_0", "-9999:40:40", protocol_field_type::time, 0, 0),
|
||||
err_text_value_testcase("too_long_1", "-9999:40:40.1", protocol_field_type::time, 0, 1),
|
||||
err_text_value_testcase("too_long_2", "-9999:40:40.12", protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("too_long_3", "-9999:40:40.123", protocol_field_type::time, 0, 3),
|
||||
err_text_value_testcase("too_long_4", "-9999:40:40.1234", protocol_field_type::time, 0, 4),
|
||||
err_text_value_testcase("too_long_5", "-9999:40:40.12345", protocol_field_type::time, 0, 5),
|
||||
err_text_value_testcase("too_long_6", "-9999:40:40.123456", protocol_field_type::time, 0, 6),
|
||||
err_text_value_testcase("extra_long", "-99999999:40:40.12345678", protocol_field_type::time, 0, 6),
|
||||
err_text_value_testcase("extra_long2", "99999999999:40:40", protocol_field_type::time, 0, 6),
|
||||
err_text_value_testcase("decimals_0", "01:20:20.1", protocol_field_type::time, 0, 0),
|
||||
err_text_value_testcase("no_decimals_1", "01:20:20 ", protocol_field_type::time, 0, 1),
|
||||
err_text_value_testcase("no_decimals_2", "01:20:20 ", protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("no_decimals_3", "01:20:20 ", protocol_field_type::time, 0, 3),
|
||||
err_text_value_testcase("no_decimals_4", "01:20:20 ", protocol_field_type::time, 0, 4),
|
||||
err_text_value_testcase("no_decimals_5", "01:20:20 ", protocol_field_type::time, 0, 5),
|
||||
err_text_value_testcase("no_decimals_6", "01:20:20 ", protocol_field_type::time, 0, 6),
|
||||
err_text_value_testcase("bad_delimiter", "01-20-20", protocol_field_type::time),
|
||||
err_text_value_testcase("missing_1gp_0", "23:01: ", protocol_field_type::time),
|
||||
err_text_value_testcase("missing_2gp_0", "23: ", protocol_field_type::time),
|
||||
err_text_value_testcase("missing_1gp_1", "23:01:.9 ", protocol_field_type::time, 0, 1),
|
||||
err_text_value_testcase("missing_2gp_1", "23:.9 ", protocol_field_type::time, 0, 1),
|
||||
err_text_value_testcase("invalid_min", "22:60:20", protocol_field_type::time),
|
||||
err_text_value_testcase("negative_min", "22:-1:20", protocol_field_type::time),
|
||||
err_text_value_testcase("invalid_sec", "22:06:60", protocol_field_type::time),
|
||||
err_text_value_testcase("negative_sec", "22:06:-1", protocol_field_type::time),
|
||||
err_text_value_testcase("invalid_micro_1", "22:06:01.99", protocol_field_type::time, 0, 1),
|
||||
err_text_value_testcase("invalid_micro_2", "22:06:01.999", protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("invalid_micro_3", "22:06:01.9999", protocol_field_type::time, 0, 3),
|
||||
err_text_value_testcase("invalid_micro_4", "22:06:01.99999", protocol_field_type::time, 0, 4),
|
||||
err_text_value_testcase("invalid_micro_5", "22:06:01.999999", protocol_field_type::time, 0, 5),
|
||||
err_text_value_testcase("invalid_micro_6", "22:06:01.9999999", protocol_field_type::time, 0, 6),
|
||||
err_text_value_testcase("negative_micro", "22:06:01.-1", protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("lt_min", "-900:00:00.00", protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("gt_max", "900:00:00.00", protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("invalid_sign", "x670:00:00.00", protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("null_char", makesv("20:00:\00.00"), protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("trailing_0", "22:06:01k", protocol_field_type::time, 0, 0),
|
||||
err_text_value_testcase("trailing_1", "22:06:01.1k", protocol_field_type::time, 0, 1),
|
||||
err_text_value_testcase("trailing_2", "22:06:01.12k", protocol_field_type::time, 0, 2),
|
||||
err_text_value_testcase("trailing_3", "22:06:01.123k", protocol_field_type::time, 0, 3),
|
||||
err_text_value_testcase("trailing_4", "22:06:01.1234k", protocol_field_type::time, 0, 4),
|
||||
err_text_value_testcase("trailing_5", "22:06:01.12345k", protocol_field_type::time, 0, 5),
|
||||
err_text_value_testcase("trailing_6", "22:06:01.123456k", protocol_field_type::time, 0, 6),
|
||||
err_text_value_testcase("double_sign", "--22:06:01.123456", protocol_field_type::time, 0, 6)
|
||||
), test_name_generator);
|
||||
|
||||
// All cases, row
|
||||
struct DeserializeTextRowTest : public Test
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user