From a76caa8a83c9dd3aa98cf6dd41cf150e39afb81a Mon Sep 17 00:00:00 2001 From: ruben Date: Fri, 8 May 2020 16:54:22 +0100 Subject: [PATCH] Refactored binary protocol magic numbers Fixed wider ranges for DATE and DATETIME Removed old binary (de)serialization functions --- TODO.txt | 23 +-- .../boost/mysql/detail/protocol/constants.hpp | 69 ++++++++- .../protocol/impl/binary_deserialization.ipp | 142 ++++++++++++------ .../protocol/impl/binary_serialization.ipp | 119 +++++++-------- .../protocol/impl/text_deserialization.ipp | 31 +--- include/boost/mysql/impl/value.hpp | 2 +- .../protocol/binary_deserialization_error.cpp | 8 +- .../protocol/binary_deserialization_value.cpp | 4 +- .../protocol/text_deserialization_error.cpp | 7 +- .../protocol/text_deserialization_value.cpp | 5 +- 10 files changed, 238 insertions(+), 172 deletions(-) diff --git a/TODO.txt b/TODO.txt index 7b6d38c4..bfac3f40 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,23 +1,13 @@ Sanitize - Refactor binary deserialization tests - serialize_binary_value(), get_binary_value_size() instead of global serialize for floats and times - Move serialization tests to just binary serialization tests - Verify that deserialization test fixture works - Add float, double, times error tests in serialization.cpp - 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 + Complete DATETIME and TIME deserialize_binary_value error tests + Complete serialize_binary_value tests + Change deserialize_text_value to allow zero and invalid dates/datetimes + Integ tests for zero and invalid dates + Remove deserialization test error fixture + Change text row to use parameterized tests See if we have any trouble with user input in binary serialization: make assertions Test with an unknown protocol type - Random input tests Better docs - Wandbox Breaking up the tutorial in pieces Explaining the different overloads and async methods available Try to include Readme instead of copying it @@ -54,6 +44,7 @@ Other possible features Lower C++ std requirements Status flags accessors in resultset (for OK_Packet) Technical debt + Random input tests Change channel read to make less syscalls Test dashboard Sanitizers diff --git a/include/boost/mysql/detail/protocol/constants.hpp b/include/boost/mysql/detail/protocol/constants.hpp index 4d8c7600..b65c549e 100644 --- a/include/boost/mysql/detail/protocol/constants.hpp +++ b/include/boost/mysql/detail/protocol/constants.hpp @@ -74,8 +74,8 @@ constexpr std::uint8_t auth_more_data_header = 0x01; constexpr std::string_view fast_auth_complete_challenge = "\3"; // Column flags -namespace column_flags -{ +namespace column_flags { + constexpr std::uint16_t not_null = 1; // Field can't be NULL. constexpr std::uint16_t pri_key = 2; // Field is part of a primary key. constexpr std::uint16_t unique_key = 4; // Field is part of a unique key. @@ -92,16 +92,73 @@ constexpr std::uint16_t no_default_value = 4096; // Field doesn't have defau constexpr std::uint16_t on_update_now = 8192; // Field is set to NOW on UPDATE. constexpr std::uint16_t part_key = 16384; // Intern; Part of some key. constexpr std::uint16_t num = 32768; // Field is num (for clients) -} + +} // column_flags // Prepared statements -namespace cursor_types -{ +namespace cursor_types { + constexpr std::uint8_t no_cursor = 0; constexpr std::uint8_t read_only = 1; constexpr std::uint8_t for_update = 2; constexpr std::uint8_t scrollable = 4; -} + +} // cursor_types + +// 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 + +// Binary protocol (de)serialization constants +namespace binc { + +constexpr std::size_t length_sz = 1; // length byte, for date, datetime and time +constexpr std::size_t year_sz = 2; +constexpr std::size_t month_sz = 1; +constexpr std::size_t date_day_sz = 1; +constexpr std::size_t time_days_sz = 4; +constexpr std::size_t hours_sz = 1; +constexpr std::size_t mins_sz = 1; +constexpr std::size_t secs_sz = 1; +constexpr std::size_t micros_sz = 4; +constexpr std::size_t time_sign_sz = 1; + +constexpr std::size_t date_sz = year_sz + month_sz + date_day_sz; // does not include length + +constexpr std::size_t datetime_d_sz = date_sz; +constexpr std::size_t datetime_dhms_sz = datetime_d_sz + hours_sz + mins_sz + secs_sz; +constexpr std::size_t datetime_dhmsu_sz = datetime_dhms_sz + micros_sz; + +constexpr std::size_t time_dhms_sz = time_sign_sz + time_days_sz + hours_sz + mins_sz + secs_sz; +constexpr std::size_t time_dhmsu_sz = time_dhms_sz + micros_sz; + +constexpr std::size_t max_days = 34; // equivalent to the 839 hours, in the broken format +constexpr unsigned max_hour = 23; +constexpr unsigned max_min = 59; +constexpr unsigned max_sec = 59; +constexpr unsigned max_micro = 999999; + +} // binc } // detail diff --git a/include/boost/mysql/detail/protocol/impl/binary_deserialization.ipp b/include/boost/mysql/detail/protocol/impl/binary_deserialization.ipp index a78e581b..239e41c0 100644 --- a/include/boost/mysql/detail/protocol/impl/binary_deserialization.ipp +++ b/include/boost/mysql/detail/protocol/impl/binary_deserialization.ipp @@ -11,6 +11,7 @@ #include #include "boost/mysql/detail/protocol/serialization.hpp" #include "boost/mysql/detail/protocol/null_bitmap_traits.hpp" +#include "boost/mysql/detail/protocol/constants.hpp" #include "boost/mysql/detail/auxiliar/tmp.hpp" namespace boost { @@ -62,9 +63,8 @@ errc deserialize_binary_value_to_variant_float( if (!ctx.enough_size(sizeof(T))) return errc::incomplete_message; - T v; - // Endianness conversion. Boost.Endian support for floats start at 1.71 + T v; #if BOOST_ENDIAN_BIG_BYTE char buf [sizeof(T)]; std::memcpy(buf, ctx.first(), sizeof(T)); @@ -73,59 +73,78 @@ errc deserialize_binary_value_to_variant_float( #else std::memcpy(&v, ctx.first(), sizeof(T)); #endif - ctx.advance(sizeof(T)); + + // Nans and infs not allowed in SQL if (std::isnan(v) || std::isinf(v)) - { - //output = nullptr; return errc::protocol_value_error; - } - else - { - output = v; - } + + // Done + ctx.advance(sizeof(T)); + output = v; return errc::ok; } // Time types +inline errc deserialize_binary_ymd( + deserialization_context& ctx, + ::date::year_month_day& output +) +{ + int2 year; + int1 month; + int1 day; + + auto err = deserialize_fields(ctx, year, month, day); + if (err != errc::ok) + return err; + + output = ::date::year_month_day ( + ::date::year(year.value), + ::date::month(month.value), + ::date::day(day.value) + ); + + return errc::ok; +} + inline errc deserialize_binary_value_to_variant_date( deserialization_context& ctx, value& output ) noexcept { - int1 length; - int2 year; - int1 month; - int1 day; - // Deserialize length + int1 length; auto err = deserialize(length, ctx); if (err != errc::ok) return err; - // A zero date. This is represented in C++ as a NULL - if (length.value < 4) + // Check for zero dates, represented in C++ as a NULL + if (length.value < binc::date_sz) { output = nullptr; return errc::ok; } // Deserialize rest of fields - err = deserialize_fields(ctx, year, month, day); + ::date::year_month_day ymd; + err = deserialize_binary_ymd(ctx, ymd); if (err != errc::ok) return err; - ::date::year_month_day ymd (::date::year(year.value), ::date::month(month.value), ::date::day(day.value)); - if (!ymd.ok()) // invalid date. We represent this as a NULL + // Check for invalid dates, represented as NULL in C++ + if (!ymd.ok()) { output = nullptr; return errc::ok; } + // Range check date d (ymd); if (d < min_date || d > max_date) return errc::protocol_value_error; - output = d; + // Convert to sys_days (date) + output = static_cast(ymd); return errc::ok; } @@ -134,58 +153,72 @@ inline errc deserialize_binary_value_to_variant_datetime( value& output ) noexcept { - int1 length; - int2 year; - int1 month; - int1 day; - int1 hours; - int1 minutes; - int1 seconds; - int4 micros; + using namespace binc; // Deserialize length + int1 length; auto err = deserialize(length, ctx); if (err != errc::ok) return err; - // A zero datetime, represented as NULL in C++ - if (length.value < 4) + // Check for zero datetimes, represented as NULL in C++ + if (length.value < datetime_d_sz) { output = nullptr; return errc::ok; } - // Date part - err = deserialize_fields(ctx, year, month, day); + // Deserialize date + ::date::year_month_day ymd; + err = deserialize_binary_ymd(ctx, ymd); if (err != errc::ok) return err; - ::date::year_month_day ymd (::date::year(year.value), ::date::month(month.value), ::date::day(day.value)); + + // Check for invalid dates, represented in C++ as NULL if (!ymd.ok()) { output = nullptr; return errc::ok; } - // Rest of fields - if (length.value >= 7) + // If the DATETIME contains no value for these fields, they are zero + int1 hours (0); + int1 minutes (0); + int1 seconds (0); + int4 micros (0); + + // Hours, minutes, seconds + if (length.value >= datetime_dhms_sz) { err = deserialize_fields(ctx, hours, minutes, seconds); if (err != errc::ok) return err; } - if (length.value >= 11) + + // Microseconds + if (length.value >= datetime_dhmsu_sz) { err = deserialize(micros, ctx); if (err != errc::ok) return err; } - // TODO: range check + // Range check + if (hours.value > max_hour || + minutes.value > max_min || + seconds.value > max_sec || + micros.value > max_micro) + { + return errc::protocol_value_error; + } // Compose the final datetime. Doing time of day and date separately to avoid overflow - auto time_of_day_part = std::chrono::hours(hours.value) + std::chrono::minutes(minutes.value) + - std::chrono::seconds(seconds.value) + std::chrono::microseconds(micros.value); - output = date(ymd) + time_of_day_part; + auto time_of_day = + std::chrono::hours(hours.value) + + std::chrono::minutes(minutes.value) + + std::chrono::seconds(seconds.value) + + std::chrono::microseconds(micros.value); + output = static_cast(ymd) + time_of_day; return errc::ok; } @@ -194,12 +227,15 @@ inline errc deserialize_binary_value_to_variant_time( value& output ) noexcept { - // Length + using namespace binc; + + // Deserialize length int1 length; auto err = deserialize(length, ctx); if (err != errc::ok) return err; + // If the TIME contains no value for these fields, they are zero int1 is_negative (0); int4 days (0); int1 hours (0); @@ -207,7 +243,8 @@ inline errc deserialize_binary_value_to_variant_time( int1 seconds(0); int4 microseconds(0); - if (length.value >= 8) + // Sign, days, hours, minutes, seconds + if (length.value >= time_dhms_sz) { err = deserialize_fields( ctx, @@ -220,20 +257,33 @@ inline errc deserialize_binary_value_to_variant_time( if (err != errc::ok) return err; } - if (length.value >= 12) + + // Microseconds + if (length.value >= time_dhmsu_sz) { err = deserialize(microseconds, ctx); if (err != errc::ok) return err; } - output = (is_negative.value ? -1 : 1) * ( + // Range check + if (days.value > max_days || + hours.value > max_hour || + minutes.value > max_min || + seconds.value > max_sec || + microseconds.value > max_micro) + { + return errc::protocol_value_error; + } + + // Compose the final time + output = time((is_negative.value ? -1 : 1) * ( ::date::days(days.value) + std::chrono::hours(hours.value) + std::chrono::minutes(minutes.value) + std::chrono::seconds(seconds.value) + std::chrono::microseconds(microseconds.value) - ); + )); return errc::ok; } diff --git a/include/boost/mysql/detail/protocol/impl/binary_serialization.ipp b/include/boost/mysql/detail/protocol/impl/binary_serialization.ipp index 280052b3..354458b1 100644 --- a/include/boost/mysql/detail/protocol/impl/binary_serialization.ipp +++ b/include/boost/mysql/detail/protocol/impl/binary_serialization.ipp @@ -8,54 +8,13 @@ #ifndef INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_BINARY_SERIALIZATION_IPP_ #define INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_BINARY_SERIALIZATION_IPP_ +#include "boost/mysql/detail/protocol/constants.hpp" + namespace boost { namespace mysql { namespace detail { -// Does not add the length prefix byte -inline void serialize_binary_ymd( - const ::date::year_month_day& ymd, - serialization_context& ctx -) noexcept -{ - serialize_fields( - ctx, - int2(static_cast(static_cast(ymd.year()))), - int1(static_cast(static_cast(ymd.month()))), - int1(static_cast(static_cast(ymd.day()))) - ); -} - -struct broken_datetime -{ - ::date::year_month_day ymd; - ::date::time_of_day tod; - - broken_datetime(const datetime& input) noexcept : - ymd(::date::floor<::date::days>(input)), - tod(input - ::date::floor<::date::days>(input)) - { - } -}; - -struct broken_time -{ - ::date::days days; - std::chrono::hours hours; - std::chrono::minutes minutes; - std::chrono::seconds seconds; - std::chrono::microseconds microseconds; - - broken_time(const time& input) noexcept : - days(std::chrono::duration_cast<::date::days>(input)), - hours(std::chrono::duration_cast(input % ::date::days(1))), - minutes(std::chrono::duration_cast(input % std::chrono::hours(1))), - seconds(std::chrono::duration_cast(input % std::chrono::minutes(1))), - microseconds(input % std::chrono::seconds(1)) - { - } -}; - +// Floating point types template std::enable_if_t> serialize_binary_value_impl( @@ -74,13 +33,32 @@ serialize_binary_value_impl( #endif } +// Time types + +// Does not add the length prefix byte +inline void serialize_binary_ymd( + const ::date::year_month_day& ymd, + serialization_context& ctx +) noexcept +{ + serialize_fields( + ctx, + int2(static_cast(static_cast(ymd.year()))), + int1(static_cast(static_cast(ymd.month()))), + int1(static_cast(static_cast(ymd.day()))) + ); +} + inline void serialize_binary_value_impl( const date& input, serialization_context& ctx ) { - serialize(int1(4), ctx); // length byte - serialize_binary_ymd(::date::year_month_day (input), ctx); + ::date::year_month_day ymd (input); + assert(ymd.ok()); + + serialize(int1(binc::date_sz), ctx); + serialize_binary_ymd(ymd, ctx); } inline void serialize_binary_value_impl( @@ -88,16 +66,21 @@ inline void serialize_binary_value_impl( serialization_context& ctx ) { - broken_datetime brokendt (input); - auto micros = static_cast(brokendt.tod.subseconds().count()); - serialize(int1(11), ctx); - serialize_binary_ymd(brokendt.ymd, ctx); + // Break datetime + auto days = ::date::floor<::date::days>(input); + ::date::year_month_day ymd (days); + ::date::time_of_day tod (input - days); + assert(ymd.ok()); + + // Serialize + serialize(int1(binc::datetime_dhmsu_sz), ctx); + serialize_binary_ymd(ymd, ctx); serialize_fields( ctx, - int1(static_cast(brokendt.tod.hours().count())), - int1(static_cast(brokendt.tod.minutes().count())), - int1(static_cast(brokendt.tod.seconds().count())), - int4(micros) + int1(static_cast(tod.hours().count())), + int1(static_cast(tod.minutes().count())), + int1(static_cast(tod.seconds().count())), + int4(static_cast(tod.subseconds().count())) ); } @@ -106,18 +89,24 @@ inline void serialize_binary_value_impl( serialization_context& ctx ) { - broken_time broken (input); + // Break time + auto days = std::chrono::duration_cast<::date::days>(input); + auto hours = std::chrono::duration_cast(input % ::date::days(1)); + auto minutes = std::chrono::duration_cast(input % std::chrono::hours(1)); + auto seconds = std::chrono::duration_cast(input % std::chrono::minutes(1)); + auto microseconds = input % std::chrono::seconds(1); int1 is_negative (input.count() < 0 ? 1 : 0); - auto micros = static_cast(std::abs(broken.microseconds.count())); + + // Serialize serialize_fields( ctx, - int1(12), // length + int1(binc::time_dhmsu_sz), is_negative, - int4(static_cast(std::abs(broken.days.count()))), - int1(static_cast(std::abs(broken.hours.count()))), - int1(static_cast(std::abs(broken.minutes.count()))), - int1(static_cast(std::abs(broken.seconds.count()))), - int4(micros) + int4(static_cast(std::abs(days.count()))), + int1(static_cast(std::abs(hours.count()))), + int1(static_cast(std::abs(minutes.count()))), + int1(static_cast(std::abs(seconds.count()))), + int4(static_cast(std::abs(microseconds.count()))) ); } @@ -133,9 +122,9 @@ struct size_visitor std::size_t operator()(T) noexcept { return sizeof(T); } std::size_t operator()(std::string_view v) noexcept { return get_size(string_lenenc(v), ctx); } - std::size_t operator()(const date&) noexcept { return 5; } - std::size_t operator()(const datetime&) noexcept { return 12; } - std::size_t operator()(const time&) noexcept { return 13; } + std::size_t operator()(const date&) noexcept { return binc::date_sz + binc::length_sz; } + std::size_t operator()(const datetime&) noexcept { return binc::datetime_dhmsu_sz + binc::length_sz; } + std::size_t operator()(const time&) noexcept { return binc::time_dhmsu_sz + binc::length_sz; } std::size_t operator()(std::nullptr_t) noexcept { return 0; } }; diff --git a/include/boost/mysql/detail/protocol/impl/text_deserialization.ipp b/include/boost/mysql/detail/protocol/impl/text_deserialization.ipp index 7be78f51..d26fd633 100644 --- a/include/boost/mysql/detail/protocol/impl/text_deserialization.ipp +++ b/include/boost/mysql/detail/protocol/impl/text_deserialization.ipp @@ -11,36 +11,12 @@ #include #include #include -#include +#include "boost/mysql/detail/protocol/constants.hpp" 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); @@ -78,11 +54,10 @@ inline errc deserialize_text_value_impl( return errc::protocol_value_error; // Range check - if (result > max_date || result < min_date) + to = result; + if (to < min_date || to > max_date) return errc::protocol_value_error; - // Done - to = result; return errc::ok; } diff --git a/include/boost/mysql/impl/value.hpp b/include/boost/mysql/impl/value.hpp index ce3d6486..2eafd840 100644 --- a/include/boost/mysql/impl/value.hpp +++ b/include/boost/mysql/impl/value.hpp @@ -15,7 +15,7 @@ namespace mysql { namespace detail { // Max/min -constexpr date min_date = ::date::day(1)/::date::January/::date::year(100); // some implementations support less than the official +constexpr date min_date = ::date::day(1)/::date::January/::date::year(0); // slightly more flexible than official min constexpr date max_date = ::date::day(31)/::date::December/::date::year(9999); constexpr datetime min_datetime = min_date; constexpr datetime max_datetime = max_date + std::chrono::hours(24) - std::chrono::microseconds(1); diff --git a/test/unit/detail/protocol/binary_deserialization_error.cpp b/test/unit/detail/protocol/binary_deserialization_error.cpp index 33f24056..ff57d685 100644 --- a/test/unit/detail/protocol/binary_deserialization_error.cpp +++ b/test/unit/detail/protocol/binary_deserialization_error.cpp @@ -133,9 +133,13 @@ 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 + err_binary_value_testcase("no_month_day", {0x04, 0x09, 0x27}, + protocol_field_type::date, errc::incomplete_message), + err_binary_value_testcase("no_day", {0x04, 0x09, 0x27, 0x01}, + protocol_field_type::date, errc::incomplete_message), + err_binary_value_testcase("gt_max", {0x04, 0x10, 0x27, 0x0c, 0x1f}, // year 10000 protocol_field_type::date), - err_binary_value_testcase("year_lt_min", {0x04, 0x63, 0x00, 0x03, 0x1c}, // year 99 + err_binary_value_testcase("protocol_max", {0x04, 0xff, 0xff, 0x0c, 0x1f}, protocol_field_type::date) )); diff --git a/test/unit/detail/protocol/binary_deserialization_value.cpp b/test/unit/detail/protocol/binary_deserialization_value.cpp index 93ae3944..d75c4f94 100644 --- a/test/unit/detail/protocol/binary_deserialization_value.cpp +++ b/test/unit/detail/protocol/binary_deserialization_value.cpp @@ -138,8 +138,8 @@ INSTANTIATE_TEST_SUITE_P(DOUBLE, DeserializeBinaryValueTest, Values( INSTANTIATE_TEST_SUITE_P(DATE, DeserializeBinaryValueTest, ::testing::Values( binary_value_testcase("regular", {0x04, 0xda, 0x07, 0x03, 0x1c}, makedate(2010, 3, 28), protocol_field_type::date), - binary_value_testcase("min", {0x04, 0xe8, 0x03, 0x01, 0x01}, - makedate(1000, 1, 1), protocol_field_type::date), + binary_value_testcase("min", {0x04, 0x00, 0x00, 0x01, 0x01}, + makedate(0, 1, 1), protocol_field_type::date), binary_value_testcase("max", {0x04, 0x0f, 0x27, 0x0c, 0x1f}, makedate(9999, 12, 31), protocol_field_type::date) ), test_name_generator); diff --git a/test/unit/detail/protocol/text_deserialization_error.cpp b/test/unit/detail/protocol/text_deserialization_error.cpp index 56ad5fef..f28c9c98 100644 --- a/test/unit/detail/protocol/text_deserialization_error.cpp +++ b/test/unit/detail/protocol/text_deserialization_error.cpp @@ -166,13 +166,14 @@ INSTANTIATE_TEST_SUITE_P(DATE, DeserializeTextValueErrorTest, Values( err_text_value_testcase("too_few_groups", "2020-00005", protocol_field_type::date), err_text_value_testcase("incomplete_year", "999-05-005", protocol_field_type::date), err_text_value_testcase("null_value", makesv("2020-05-\02"), protocol_field_type::date), - err_text_value_testcase("lt_min", "0099-05-02", protocol_field_type::date), + err_text_value_testcase("lt_min", "-001-05-02", protocol_field_type::date), err_text_value_testcase("gt_max", "10000-05-2", protocol_field_type::date), err_text_value_testcase("long_month", "2010-005-2", protocol_field_type::date), err_text_value_testcase("long_day", "2010-5-002", protocol_field_type::date), err_text_value_testcase("negative_year", "-999-05-02", protocol_field_type::date), err_text_value_testcase("negative_month", "2010--5-02", protocol_field_type::date), - err_text_value_testcase("negative_day", "2010-05-- 2", protocol_field_type::date) + err_text_value_testcase("negative_day", "2010-05--2", protocol_field_type::date), + err_text_value_testcase("hex", "ffff-ff-ff", protocol_field_type::date) ), test_name_generator); std::vector make_datetime_err_cases( @@ -223,7 +224,7 @@ std::vector make_datetime_err_cases( err_text_value_testcase("invalid_sec", "2020-05-02 22:06:60", 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", "0090-01-01 00:00:00.00", t, 0, 2), + err_text_value_testcase("lt_min", "-001-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) }; } diff --git a/test/unit/detail/protocol/text_deserialization_value.cpp b/test/unit/detail/protocol/text_deserialization_value.cpp index abf2e932..c07c5c87 100644 --- a/test/unit/detail/protocol/text_deserialization_value.cpp +++ b/test/unit/detail/protocol/text_deserialization_value.cpp @@ -188,9 +188,8 @@ INSTANTIATE_TEST_SUITE_P(DOUBLE, DeserializeTextValueTest, ValuesIn( INSTANTIATE_TEST_SUITE_P(DATE, DeserializeTextValueTest, Values( text_value_testcase("regular_date", "2019-02-28", makedate(2019, 2, 28), protocol_field_type::date), text_value_testcase("leap_year", "1788-02-29", makedate(1788, 2, 29), protocol_field_type::date), - text_value_testcase("min", "1000-01-01", makedate(1000, 1, 1), protocol_field_type::date), - text_value_testcase("max", "9999-12-31", makedate(9999, 12, 31), protocol_field_type::date), - text_value_testcase("unofficial_min", "0100-01-01", makedate(100, 1, 1), protocol_field_type::date) + text_value_testcase("min", "0000-01-01", makedate(0, 1, 1), protocol_field_type::date), + text_value_testcase("max", "9999-12-31", makedate(9999, 12, 31), protocol_field_type::date) ), test_name_generator); std::vector make_datetime_cases(